diff --git a/build/mobile/remoteautomation.py b/build/mobile/remoteautomation.py index 525a857776..67dcd72cd2 100644 --- a/build/mobile/remoteautomation.py +++ b/build/mobile/remoteautomation.py @@ -2,6 +2,7 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +import datetime import glob import time import re @@ -122,8 +123,11 @@ class RemoteAutomation(Automation): if self._devicemanager.fileExists(traces): try: t = self._devicemanager.pullFile(traces) - print "Contents of %s:" % traces - print t + if t: + stripped = t.strip() + if len(stripped) > 0: + print "Contents of %s:" % traces + print t # Once reported, delete traces self.deleteANRs() except DMError: @@ -238,10 +242,10 @@ class RemoteAutomation(Automation): self.procName = cmd[0].split('/')[-1] if cmd[0] == 'am' and cmd[1] in RemoteAutomation._specialAmCommands: self.procName = app - print "Robocop process name: "+self.procName - # Setting timeout at 1 hour since on a remote device this takes much longer - self.timeout = 3600 + # Setting timeout at 1 hour since on a remote device this takes much longer. + # Temporarily increased to 75 minutes because no more chunks can be created. + self.timeout = 4500 # The benefit of the following sleep is unclear; it was formerly 15 seconds time.sleep(1) @@ -316,19 +320,22 @@ class RemoteAutomation(Automation): def wait(self, timeout = None, noOutputTimeout = None): timer = 0 noOutputTimer = 0 - interval = 20 - + interval = 10 if timeout == None: timeout = self.timeout - status = 0 - while (self.dm.getTopActivity() == self.procName): - # retrieve log updates every 60 seconds - if timer % 60 == 0: + top = self.procName + slowLog = False + while (top == self.procName): + # Get log updates on each interval, but if it is taking + # too long, only do it every 60 seconds + if (not slowLog) or (timer % 60 == 0): + startRead = datetime.datetime.now() messages = self.read_stdout() + if (datetime.datetime.now() - startRead) > datetime.timedelta(seconds=5): + slowLog = True if messages: noOutputTimer = 0 - time.sleep(interval) timer += interval noOutputTimer += interval @@ -338,10 +345,9 @@ class RemoteAutomation(Automation): if (noOutputTimeout and noOutputTimer > noOutputTimeout): status = 2 break - + top = self.dm.getTopActivity() # Flush anything added to stdout during the sleep self.read_stdout() - return status def kill(self, stagedShutdown = False): diff --git a/build/moz.build b/build/moz.build index 90e349dc7a..b0bf3d5845 100644 --- a/build/moz.build +++ b/build/moz.build @@ -26,10 +26,6 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android': 'mobile/sutagent/android/ffxcp', 'mobile/sutagent/android/fencp', ] - if not CONFIG['MOZ_B2GDROID']: - TEST_DIRS += [ - 'mobile/robocop', - ] for var in ('GRE_MILESTONE', 'MOZ_APP_VERSION', 'MOZ_APP_BASENAME', 'MOZ_APP_VENDOR', 'MOZ_APP_ID', 'MAR_CHANNEL_ID', diff --git a/config/faster/rules.mk b/config/faster/rules.mk index 654d79ac83..215cde6126 100644 --- a/config/faster/rules.mk +++ b/config/faster/rules.mk @@ -27,10 +27,6 @@ # - PYTHON, the path to the python executable # - ACDEFINES, which contains a set of -Dvar=name to be used during # preprocessing -# - MOZ_CHROME_FILE_FORMAT, which defines whether to use file copies or -# symbolic links -# - JAR_MN_TARGETS, which defines the targets to use for jar manifest -# processing, see further below # - INSTALL_MANIFESTS, which defines the list of base directories handled # by install manifests, see further below # - MANIFEST_TARGETS, which defines the file paths of chrome manifests, see @@ -42,7 +38,6 @@ # Targets to be triggered for a default build default: $(addprefix install-,$(INSTALL_MANIFESTS)) -default: $(addprefix jar-,$(JAR_MN_TARGETS)) # Explicit files to be built for a default build default: $(addprefix $(TOPOBJDIR)/,$(MANIFEST_TARGETS)) @@ -53,6 +48,12 @@ default: $(TOPOBJDIR)/dist/bin/webapprt/webapprt.ini # Targets from the recursive make backend to be built for a default build default: $(TOPOBJDIR)/config/makefiles/xpidl/xpidl +ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) +# Mac builds require to copy things in dist/bin/*.app +default: + $(MAKE) -C $(TOPOBJDIR)/$(MOZ_BUILD_APP)/app repackage +endif + .PHONY: FORCE # Extra define to trigger some workarounds. We should strive to limit the @@ -95,52 +96,6 @@ $(addprefix install-,$(INSTALL_MANIFESTS)): install-%: $(TOPOBJDIR)/config/build $(MOZ_DEBUG_DEFINES) \ install_$(subst /,_,$*) -# Install files from jar manifests. Ideally, they would be using install -# manifests, but the code to read jar manifests and emit appropriate -# install manifests is not there yet. -# Things missing: -# - DEFINES from config/config.mk -# - L10N -# - -e when USE_EXTENSION_MANIFEST is set in moz.build -# -# The list given in JAR_MN_TARGETS corresponds to the list of `jar-%` targets -# to be processed, with the `jar-` prefix stripped. -# The Makefile is expected to specify the source jar manifest as a dependency -# to each target. There is no expectation that the `jar-%` target name matches -# the source file name in any way. For example: -# JAR_MN_TARGETS = foo -# jar-foo: /path/to/some/jar.mn -# Additionally, extra defines can be specified for the processing of the jar -# manifest by settig the `defines` variable specifically for the given target. -# For example: -# jar-foo: defines = -Dqux=foo -# The default base path where files are going to be installed is `dist/bin`. -# It is possible to use a different path by setting the `install_target` -# variable. For example: -# jar-foo: install_target = dist/bin/foo -# When processing jar manifests, relative paths given inside a jar manifest -# can be resolved from an object directory. The default path for that object -# directory is the translation of the jar manifest directory path from the -# source directory to the object directory. That is, for -# $(TOPSRCDIR)/path/to/jar.mn, the default would be $(TOPOBJDIR)/path/to. -# In case a different path must be used for the object directory, the `objdir` -# variable can be set. For example: -# jar-foo: objdir=/some/other/path -jar-%: objdir ?= $(dir $(patsubst $(TOPSRCDIR)%,$(TOPOBJDIR)%,$<)) -jar-%: install_target ?= dist/bin -jar-%: - cd $(objdir) && \ - $(PYTHON) -m mozbuild.action.jar_maker \ - -j $(TOPOBJDIR)/$(install_target)/chrome \ - -t $(TOPSRCDIR) \ - -f $(MOZ_CHROME_FILE_FORMAT) \ - -c $(dir $<)/en-US \ - -DAB_CD=en-US \ - $(defines) \ - $(ACDEFINES) \ - $(MOZ_DEBUG_DEFINES) \ - $< - # Create some chrome manifests # This rule is forced to run every time because it may be updating files that # already exit. @@ -159,13 +114,6 @@ $(addprefix $(TOPOBJDIR)/,$(MANIFEST_TARGETS)): FORCE # Below is a set of additional dependencies and variables used to build things # that are not supported by data in moz.build. -# GENERATED_FILES are not supported yet, and even if they were, the -# dependencies are missing information. -$(foreach p,linux osx windows,jar-browser-themes-$(p)-jar.mn): \ -jar-browser-themes-%-jar.mn: \ - $(TOPOBJDIR)/browser/themes/%/tab-selected-end.svg \ - $(TOPOBJDIR)/browser/themes/%/tab-selected-start.svg - # Files to build with the recursive backend and simply copy $(TOPOBJDIR)/dist/bin/greprefs.js: $(TOPOBJDIR)/modules/libpref/greprefs.js $(TOPOBJDIR)/dist/bin/platform.ini: $(TOPOBJDIR)/toolkit/xre/platform.ini diff --git a/config/rules.mk b/config/rules.mk index 63712ce37a..43787ac0b1 100644 --- a/config/rules.mk +++ b/config/rules.mk @@ -1128,11 +1128,6 @@ ifneq (,$(DIST_SUBDIR)$(XPI_NAME)) PREF_DIR = defaults/preferences endif -# on win32, pref files need CRLF line endings... see bug 206029 -ifeq (WINNT,$(OS_ARCH)) -PREF_PPFLAGS += --line-endings=crlf -endif - ifneq ($(PREF_JS_EXPORTS),) ifndef NO_DIST_INSTALL PREF_JS_EXPORTS_PATH := $(FINAL_TARGET)/$(PREF_DIR) diff --git a/js/src/builtin/Iterator.js b/js/src/builtin/Iterator.js index 6ae33960ac..5f78547cad 100644 --- a/js/src/builtin/Iterator.js +++ b/js/src/builtin/Iterator.js @@ -101,7 +101,7 @@ function CreateListIterator(array) { ThrowTypeError(JSMSG_INCOMPATIBLE_METHOD, "next", "method", ToString(this)); let array = UnsafeGetObjectFromReservedSlot(this, ITERATOR_SLOT_TARGET); - let index = UnsafeGetInt32FromReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX); + let index = UnsafeGetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX); if (index >= ToLength(array.length)) { UnsafeSetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX, 1/0); diff --git a/js/src/builtin/Module.js b/js/src/builtin/Module.js index c462135d7c..2e82cfcdf2 100644 --- a/js/src/builtin/Module.js +++ b/js/src/builtin/Module.js @@ -18,23 +18,24 @@ function ModuleGetExportedNames(exportStarSet = []) return []; // Step 3 - exportStarSet.push(module); + _DefineDataProperty(exportStarSet, exportStarSet.length, module); // Step 4 let exportedNames = []; + let namesCount = 0; // Step 5 let localExportEntries = module.localExportEntries; for (let i = 0; i < localExportEntries.length; i++) { let e = localExportEntries[i]; - exportedNames.push(e.exportName); + _DefineDataProperty(exportedNames, namesCount++, e.exportName); } // Step 6 let indirectExportEntries = module.indirectExportEntries; for (let i = 0; i < indirectExportEntries.length; i++) { let e = indirectExportEntries[i]; - exportedNames.push(e.exportName); + _DefineDataProperty(exportedNames, namesCount++, e.exportName); } // Step 7 @@ -46,7 +47,7 @@ function ModuleGetExportedNames(exportStarSet = []) for (let j = 0; j < starNames.length; j++) { let n = starNames[j]; if (n !== "default" && !(n in exportedNames)) - exportedNames.push(n); + _DefineDataProperty(exportedNames, namesCount++, n); } } @@ -72,7 +73,7 @@ function ModuleResolveExport(exportName, resolveSet = [], exportStarSet = []) } // Step 3 - resolveSet.push({module: module, exportName: exportName}); + _DefineDataProperty(resolveSet, resolveSet.length, {module: module, exportName: exportName}); // Step 4 let localExportEntries = module.localExportEntries; @@ -107,7 +108,7 @@ function ModuleResolveExport(exportName, resolveSet = [], exportStarSet = []) return null; // Step 8 - exportStarSet.push(module); + _DefineDataProperty(exportStarSet, exportStarSet.length, module); // Step 9 let starResolution = null; @@ -153,7 +154,7 @@ function GetModuleNamespace(module) if (resolution === null) ThrowSyntaxError(JSMSG_MISSING_NAMESPACE_EXPORT); if (resolution !== "ambiguous") - unambiguousNames.push(name); + _DefineDataProperty(unambiguousNames, unambiguousNames.length, name); } namespace = ModuleNamespaceCreate(module, unambiguousNames); } diff --git a/js/src/builtin/ModuleObject.cpp b/js/src/builtin/ModuleObject.cpp index 86f1ddc165..2e09f9564d 100644 --- a/js/src/builtin/ModuleObject.cpp +++ b/js/src/builtin/ModuleObject.cpp @@ -574,7 +574,7 @@ ModuleObject::create(ExclusiveContext* cx, HandleObject enclosingStaticScope) ModuleObject::finalize(js::FreeOp* fop, JSObject* obj) { ModuleObject* self = &obj->as(); - if (!self->getReservedSlot(ImportBindingsSlot).isUndefined()) + if (self->hasImportBindings()) fop->delete_(&self->importBindings()); if (IndirectBindingMap* bindings = self->namespaceBindings()) fop->delete_(bindings); @@ -592,6 +592,13 @@ ModuleObject::environment() const return &value.toObject().as(); } +bool +ModuleObject::hasImportBindings() const +{ + // Import bindings may not be present if we hit OOM in initialization. + return !getReservedSlot(ImportBindingsSlot).isUndefined(); +} + IndirectBindingMap& ModuleObject::importBindings() { @@ -719,7 +726,8 @@ ModuleObject::trace(JSTracer* trc, JSObject* obj) module.setReservedSlot(ScriptSlot, PrivateValue(script)); } - TraceBindings(trc, module.importBindings()); + if (module.hasImportBindings()) + TraceBindings(trc, module.importBindings()); if (IndirectBindingMap* bindings = module.namespaceBindings()) TraceBindings(trc, *bindings); @@ -785,7 +793,10 @@ ModuleObject::evaluate(JSContext* cx, HandleModuleObject self, MutableHandleValu { RootedScript script(cx, self->script()); RootedModuleEnvironmentObject scope(cx, self->environment()); - MOZ_ASSERT(scope); + if (!scope) { + JS_ReportError(cx, "Module declarations have not yet been instantiated"); + return false; + } return Execute(cx, script, *scope, rval.address()); } diff --git a/js/src/builtin/ModuleObject.h b/js/src/builtin/ModuleObject.h index 9b5fe511a1..276d0d6b5e 100644 --- a/js/src/builtin/ModuleObject.h +++ b/js/src/builtin/ModuleObject.h @@ -223,6 +223,7 @@ class ModuleObject : public NativeObject static void finalize(js::FreeOp* fop, JSObject* obj); bool hasScript() const; + bool hasImportBindings() const; FunctionDeclarationVector* functionDeclarations(); }; diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp index 6d05ed8622..09b4725986 100644 --- a/js/src/builtin/Object.cpp +++ b/js/src/builtin/Object.cpp @@ -1005,8 +1005,6 @@ static const JSFunctionSpec object_static_methods[] = { JS_FN("setPrototypeOf", obj_setPrototypeOf, 2, 0), JS_FN("getOwnPropertyDescriptor", obj_getOwnPropertyDescriptor,2, 0), JS_FN("keys", obj_keys, 1, 0), - JS_SELF_HOSTED_FN("values", "ObjectValues", 1, JSPROP_DEFINE_LATE), - JS_SELF_HOSTED_FN("entries", "ObjectEntries", 1, JSPROP_DEFINE_LATE), JS_FN("is", obj_is, 2, 0), JS_FN("defineProperty", obj_defineProperty, 3, 0), JS_FN("defineProperties", obj_defineProperties, 2, 0), diff --git a/js/src/builtin/Object.js b/js/src/builtin/Object.js index dc6c927fb1..83bbb03e04 100644 --- a/js/src/builtin/Object.js +++ b/js/src/builtin/Object.js @@ -134,54 +134,3 @@ function ObjectLookupGetter(name) { } while (object !== null); } -// Draft proposal http://tc39.github.io/proposal-object-values-entries/#Object.values -function ObjectValues(O) { - // Until https://bugzilla.mozilla.org/show_bug.cgi?id=1170372 implemented - var attrs = ATTR_CONFIGURABLE | ATTR_ENUMERABLE | ATTR_WRITABLE; - - // Steps 1-2. - var object = ToObject(O); - - // Steps 3-4. - // EnumerableOwnProperties is inlined here. - var keys = OwnPropertyKeys(object, JSITER_OWNONLY | JSITER_HIDDEN); - var values = []; - var valuesCount = 0; - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - if (!callFunction(std_Object_propertyIsEnumerable, object, key)) - continue; - - var value = object[key]; - _DefineDataProperty(values, valuesCount++, value, attrs); - } - - // Step 5. - return values; -} - -// Draft proposal http://tc39.github.io/proposal-object-values-entries/#Object.entries -function ObjectEntries(O) { - // Until https://bugzilla.mozilla.org/show_bug.cgi?id=1170372 implemented - var attrs = ATTR_CONFIGURABLE | ATTR_ENUMERABLE | ATTR_WRITABLE; - - // Steps 1-2. - var object = ToObject(O); - - // Steps 3-4. - // EnumerableOwnProperties is inlined here. - var keys = OwnPropertyKeys(object, JSITER_OWNONLY | JSITER_HIDDEN); - var entries = []; - var entriesCount = 0; - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - if (!callFunction(std_Object_propertyIsEnumerable, object, key)) - continue; - - var value = object[key]; - _DefineDataProperty(entries, entriesCount++, [key, value], attrs); - } - - // Step 5. - return entries; -} diff --git a/js/src/builtin/RegExp.cpp b/js/src/builtin/RegExp.cpp index 139d52c69e..7df68daff9 100644 --- a/js/src/builtin/RegExp.cpp +++ b/js/src/builtin/RegExp.cpp @@ -140,11 +140,13 @@ js::ExecuteRegExpLegacy(JSContext* cx, RegExpStatics* res, RegExpObject& reobj, return CreateRegExpMatchResult(cx, input, matches, rval); } -/* ES6 draft rc4 21.2.3.2.2. */ -bool -RegExpInitialize(JSContext* cx, RegExpObjectBuilder& builder, - HandleValue patternValue, HandleValue flagsValue, - RegExpStaticsUse staticsUse, MutableHandleObject result) +/* + * ES6 21.2.3.2.2. Because this function only ever returns |obj| in the spec, + * provided by the user, we omit it and just return the usual success/failure. + */ +static bool +RegExpInitialize(JSContext* cx, Handle obj, HandleValue patternValue, + HandleValue flagsValue, RegExpStaticsUse staticsUse) { RootedAtom pattern(cx); if (patternValue.isUndefined()) { @@ -183,148 +185,10 @@ RegExpInitialize(JSContext* cx, RegExpObjectBuilder& builder, } /* Steps 11-15. */ - RootedObject reobj(cx, builder.build(pattern, flags)); - if (!reobj) + if (!InitializeRegExp(cx, obj, pattern, flags)) return false; /* Step 16. */ - result.set(reobj); - return true; -} - -/* - * ES6 draft rc4 21.2.3.1 steps 5-10. - * ES6 draft rc4 B.2.5.1 steps 3-5. - * Compile a new |RegExpShared| for the |RegExpObject|. - */ -static bool -CompileRegExpObject(JSContext* cx, RegExpObjectBuilder& builder, const CallArgs& args, - RegExpCreationMode creationMode, bool patternIsRegExp=false) -{ - if (args.length() == 0) { - /* - * 21.2.3.1 step 10. - * B.2.5.1 step 5. - */ - RegExpStatics* res = cx->global()->getRegExpStatics(cx); - if (!res) - return false; - - RootedAtom empty(cx, cx->runtime()->emptyString); - RegExpObject* reobj = builder.build(empty, res->getFlags()); - if (!reobj) - return false; - - args.rval().setObject(*reobj); - return true; - } - - RootedValue patternValue(cx, args.get(0)); - - /* - * 21.2.3.1 step 5 - * B.2.5.1 step 3. - */ - ESClassValue cls; - if (!GetClassOfValue(cx, patternValue, &cls)) - return false; - if (cls == ESClass_RegExp) { - /* - * B.2.5.1 step 3.a. - */ - if (args.hasDefined(1) && creationMode == CreateForCompile) { - JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NEWREGEXP_FLAGGED); - return false; - } - - /* - * Beware, patternObj may be a (transparent) proxy to a RegExp, so only - * use generic (proxyable) operations on patternObj that do not assume - * patternObj.is(). - */ - RootedObject patternObj(cx, &patternValue.toObject()); - - RootedAtom sourceAtom(cx); - RegExpFlag flags; - { - /* - * 21.2.3.1 step 5.a. - * B.2.5.1 step 3.a. - * Extract the 'source' from patternObj; do not reuse the - * RegExpShared since it may be from a different compartment. - */ - RegExpGuard g(cx); - if (!RegExpToShared(cx, patternObj, &g)) - return false; - sourceAtom = g->getSource(); - - if (args.hasDefined(1)) { - /* 21.2.3.1 step 5.c. */ - flags = RegExpFlag(0); - RootedString flagStr(cx, ToString(cx, args[1])); - if (!flagStr) - return false; - if (!ParseRegExpFlags(cx, flagStr, &flags)) - return false; - } else { - /* - * 21.2.3.1 step 5.b. - * B.2.5.1 step 3.c. - */ - flags = g->getFlags(); - } - } - - /* - * 21.2.3.1 steps 8-10. - * B.2.5.1 step 5. - */ - RegExpObject* reobj = builder.build(sourceAtom, flags); - if (!reobj) - return false; - - args.rval().setObject(*reobj); - return true; - } - - RootedValue P(cx); - RootedValue F(cx); - /* 21.2.3.1 step 6. */ - if (patternIsRegExp) { - MOZ_ASSERT(creationMode == CreateForConstruct); - RootedObject patternObj(cx, &patternValue.toObject()); - - /* 21.2.3.1 steps 6.a-b. */ - if (!GetProperty(cx, patternObj, patternObj, cx->names().source, &P)) - return false; - - /* 21.2.3.1 step 6.c. */ - if (!args.hasDefined(1)) { - /* 21.2.3.1 steps 6.c.i-ii. */ - if (!GetProperty(cx, patternObj, patternObj, cx->names().flags, &F)) - return false; - } else { - /* 21.2.3.1 steps 6.d. */ - F = args[1]; - } - } else { - /* - * 21.2.3.1 steps 7.a-b. - * B.2.5.1 steps 4.a-b. - */ - P = patternValue; - F = args.get(1); - } - - /* - * 21.2.3.1 steps 8-10. - * B.2.5.1 step 5. - */ - RootedObject reobj(cx); - if (!RegExpInitialize(cx, builder, P, F, UseRegExpStatics, &reobj)) - return false; - - args.rval().setObject(*reobj); return true; } @@ -366,15 +230,61 @@ js::IsRegExp(JSContext* cx, HandleValue value, bool* result) return true; } -/* ES6 draft rc4 B.2.5.1. */ +/* ES6 B.2.5.1. */ MOZ_ALWAYS_INLINE bool regexp_compile_impl(JSContext* cx, const CallArgs& args) { MOZ_ASSERT(IsRegExpObject(args.thisv())); - /* Steps 3-5. */ - RegExpObjectBuilder builder(cx, &args.thisv().toObject().as()); - return CompileRegExpObject(cx, builder, args, CreateForCompile); + Rooted regexp(cx, &args.thisv().toObject().as()); + + // Step 3. + RootedValue patternValue(cx, args.get(0)); + ESClassValue cls; + if (!GetClassOfValue(cx, patternValue, &cls)) + return false; + if (cls == ESClass_RegExp) { + // Step 3a. + if (args.hasDefined(1)) { + JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NEWREGEXP_FLAGGED); + return false; + } + + // Beware! |patternObj| might be a proxy into another compartment, so + // don't assume |patternObj.is()|. For the same reason, + // don't reuse the RegExpShared below. + RootedObject patternObj(cx, &patternValue.toObject()); + + RootedAtom sourceAtom(cx); + RegExpFlag flags; + { + // Step 3b. + RegExpGuard g(cx); + if (!RegExpToShared(cx, patternObj, &g)) + return false; + + sourceAtom = g->getSource(); + flags = g->getFlags(); + } + + // Step 5. + if (!InitializeRegExp(cx, regexp, sourceAtom, flags)) + return false; + + args.rval().setObject(*regexp); + return true; + } + + // Step 4. + RootedValue P(cx, patternValue); + RootedValue F(cx, args.get(1)); + + // Step 5. + if (!RegExpInitialize(cx, regexp, P, F, UseRegExpStatics)) + return false; + + args.rval().setObject(*regexp); + return true; } static bool @@ -386,29 +296,32 @@ regexp_compile(JSContext* cx, unsigned argc, Value* vp) return CallNonGenericMethod(cx, args); } -/* ES6 draft rc4 21.2.3.1. */ +/* ES6 21.2.3.1. */ bool js::regexp_construct(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); - /* Steps 1-2. */ + // Steps 1-2. bool patternIsRegExp; if (!IsRegExp(cx, args.get(0), &patternIsRegExp)) return false; - /* Step 4. */ - if (!args.isConstructing()) { - /* Step 4.b. */ + if (args.isConstructing()) { + // XXX Step 3! + } else { + // XXX Step 4a + + // Step 4b. if (patternIsRegExp && !args.hasDefined(1)) { RootedObject patternObj(cx, &args[0].toObject()); - /* Steps 4.b.i-ii. */ + // Steps 4b.i-ii. RootedValue patternConstructor(cx); if (!GetProperty(cx, patternObj, patternObj, cx->names().constructor, &patternConstructor)) return false; - /* Step 4.b.iii. */ + // Step 4b.iii. if (patternConstructor.isObject() && patternConstructor.toObject() == args.callee()) { args.rval().set(args[0]); return true; @@ -416,9 +329,91 @@ js::regexp_construct(JSContext* cx, unsigned argc, Value* vp) } } - /* Steps 5-10. */ - RegExpObjectBuilder builder(cx); - return CompileRegExpObject(cx, builder, args, CreateForConstruct, patternIsRegExp); + RootedValue patternValue(cx, args.get(0)); + + // Step 5. + ESClassValue cls; + if (!GetClassOfValue(cx, patternValue, &cls)) + return false; + if (cls == ESClass_RegExp) { + // Beware! |patternObj| might be a proxy into another compartment, so + // don't assume |patternObj.is()|. For the same reason, + // don't reuse the RegExpShared below. + RootedObject patternObj(cx, &patternValue.toObject()); + + RootedAtom sourceAtom(cx); + RegExpFlag flags; + { + // Step 5.a. + RegExpGuard g(cx); + if (!RegExpToShared(cx, patternObj, &g)) + return false; + sourceAtom = g->getSource(); + + if (!args.hasDefined(1)) { + // Step 5b. + flags = g->getFlags(); + } else { + // Step 5c. + // XXX We shouldn't be converting to string yet! This must + // come *after* the .constructor access in step 8. + flags = RegExpFlag(0); + RootedString flagStr(cx, ToString(cx, args[1])); + if (!flagStr) + return false; + if (!ParseRegExpFlags(cx, flagStr, &flags)) + return false; + } + } + + // Steps 8-9. + // XXX Note bug in step 5c, with respect to step 8. + Rooted regexp(cx, RegExpAlloc(cx)); + if (!regexp) + return false; + + // Step 10. + if (!InitializeRegExp(cx, regexp, sourceAtom, flags)) + return false; + + args.rval().setObject(*regexp); + return true; + } + + RootedValue P(cx); + RootedValue F(cx); + + // Step 6. + if (patternIsRegExp) { + RootedObject patternObj(cx, &patternValue.toObject()); + + // Steps 6a-b. + if (!GetProperty(cx, patternObj, patternObj, cx->names().source, &P)) + return false; + + // Steps 6c-d. + F = args.get(1); + if (F.isUndefined()) { + if (!GetProperty(cx, patternObj, patternObj, cx->names().flags, &F)) + return false; + } + } else { + // Steps 7a-b. + P = patternValue; + F = args.get(1); + } + + // Steps 8-9. + Rooted regexp(cx, RegExpAlloc(cx)); + if (!regexp) + return false; + + // Step 10. + if (!RegExpInitialize(cx, regexp, P, F, UseRegExpStatics)) + return false; + + args.rval().setObject(*regexp); + return true; } bool @@ -434,12 +429,14 @@ js::regexp_construct_no_statics(JSContext* cx, unsigned argc, Value* vp) /* Steps 1-6 are not required since pattern is always string. */ /* Steps 7-10. */ - RegExpObjectBuilder builder(cx); - RootedObject reobj(cx); - if (!RegExpInitialize(cx, builder, args[0], args.get(1), DontUseRegExpStatics, &reobj)) + Rooted regexp(cx, RegExpAlloc(cx)); + if (!regexp) return false; - args.rval().setObject(*reobj); + if (!RegExpInitialize(cx, regexp, args[0], args.get(1), DontUseRegExpStatics)) + return false; + + args.rval().setObject(*regexp); return true; } @@ -703,12 +700,8 @@ js::CreateRegExpPrototype(JSContext* cx, JSProtoKey key) return nullptr; proto->NativeObject::setPrivate(nullptr); - HandlePropertyName empty = cx->names().empty; - RegExpObjectBuilder builder(cx, proto); - if (!builder.build(empty, RegExpFlag(0))) - return nullptr; - - return proto; + RootedAtom source(cx, cx->names().empty); + return InitializeRegExp(cx, proto, source, RegExpFlag(0)); } static bool diff --git a/js/src/builtin/RegExp.h b/js/src/builtin/RegExp.h index 018cb64ebb..8085adfc73 100644 --- a/js/src/builtin/RegExp.h +++ b/js/src/builtin/RegExp.h @@ -26,9 +26,6 @@ enum RegExpStaticsUpdate { UpdateRegExpStatics, DontUpdateRegExpStatics }; // Whether RegExp statics should be used to create a RegExp instance. enum RegExpStaticsUse { UseRegExpStatics, DontUseRegExpStatics }; -// This enum is used to indicate whether 'CompileRegExpObject' is called from 'regexp_compile'. -enum RegExpCreationMode { CreateForCompile, CreateForConstruct }; - RegExpRunStatus ExecuteRegExp(JSContext* cx, HandleObject regexp, HandleString string, MatchPairs* matches, RegExpStaticsUpdate staticsUpdate); @@ -99,8 +96,6 @@ IsRegExp(JSContext* cx, HandleValue value, bool* result); // RegExp ClassSpec members used in RegExpObject.cpp. extern bool regexp_construct(JSContext* cx, unsigned argc, Value* vp); -extern JSObject* -CreateRegExpPrototype(JSContext* cx, JSProtoKey key); extern const JSPropertySpec regexp_static_props[]; extern const JSPropertySpec regexp_properties[]; extern const JSFunctionSpec regexp_methods[]; diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 90e7f6c564..fc7575c960 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -53,6 +53,25 @@ static bool fuzzingSafe = false; // OOM conditions. static bool disableOOMFunctions = false; +static bool +EnvVarIsDefined(const char* name) +{ + const char* value = getenv(name); + return value && *value; +} + +#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) +static bool +EnvVarAsInt(const char* name, int* valueOut) +{ + if (!EnvVarIsDefined(name)) + return false; + + *valueOut = atoi(getenv(name)); + return true; +} +#endif + static bool GetBuildConfiguration(JSContext* cx, unsigned argc, Value* vp) { @@ -1062,6 +1081,93 @@ ResetOOMFailure(JSContext* cx, unsigned argc, Value* vp) OOM_maxAllocations = UINT32_MAX; return true; } + +static bool +OOMTest(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + + if (args.length() != 1 || !args[0].isObject() || !args[0].toObject().is()) { + JS_ReportError(cx, "oomTest() takes a single function argument."); + return false; + } + + if (disableOOMFunctions) { + args.rval().setUndefined(); + return true; + } + + RootedFunction function(cx, &args[0].toObject().as()); + + bool verbose = EnvVarIsDefined("OOM_VERBOSE"); + + unsigned threadStart = oom::THREAD_TYPE_MAIN; + unsigned threadEnd = oom::THREAD_TYPE_MAX; + + // Test a single thread type if specified by the OOM_THREAD environment variable. + int threadOption = 0; + if (EnvVarAsInt("OOM_THREAD", &threadOption)) { + if (threadOption < oom::THREAD_TYPE_MAIN || threadOption > oom::THREAD_TYPE_MAX) { + JS_ReportError(cx, "OOM_THREAD value out of range."); + return false; + } + + threadStart = threadOption; + threadEnd = threadOption + 1; + } + + JS_SetGCZeal(cx, 0, JS_DEFAULT_ZEAL_FREQ); + + for (unsigned thread = threadStart; thread < threadEnd; thread++) { + if (verbose) + fprintf(stderr, "thread %d\n", thread); + + HelperThreadState().waitForAllThreads(); + js::oom::targetThread = thread; + + unsigned allocation = 1; + bool handledOOM; + do { + if (verbose) + fprintf(stderr, " allocation %d\n", allocation); + + MOZ_ASSERT(!cx->isExceptionPending()); + MOZ_ASSERT(!cx->runtime()->hadOutOfMemory); + + OOM_maxAllocations = OOM_counter + allocation; + OOM_failAlways = false; + + RootedValue result(cx); + bool ok = JS_CallFunction(cx, cx->global(), function, + HandleValueArray::empty(), &result); + + handledOOM = OOM_counter >= OOM_maxAllocations; + OOM_maxAllocations = UINT32_MAX; + + MOZ_ASSERT_IF(ok, !cx->isExceptionPending()); + MOZ_ASSERT_IF(!ok, cx->isExceptionPending()); + + // Note that it is possible that the function throws an exception + // unconnected to OOM, in which case we ignore it. More correct + // would be to have the caller pass some kind of exception + // specification and to check the exception against it. + + cx->clearPendingException(); + cx->runtime()->hadOutOfMemory = false; + + allocation++; + } while (handledOOM); + + if (verbose) { + fprintf(stderr, " finished after %d allocations\n", allocation - 2); + } + } + + js::oom::targetThread = js::oom::THREAD_TYPE_NONE; + + args.rval().setUndefined(); + return true; +} #endif static const js::Class FakePromiseClass = { @@ -3034,6 +3140,12 @@ static const JSFunctionSpecWithHelp TestingFunctions[] = { "resetOOMFailure()", " Remove the allocation failure scheduled by either oomAfterAllocations() or\n" " oomAtAllocation() and return whether any allocation had been caused to fail."), + + JS_FN_HELP("oomTest", OOMTest, 0, 0, +"oomTest(function)", +" Test that the passed function behaves correctly under OOM conditions by\n" +" repeatedly executing it and simulating allocation failure at successive\n" +" allocations until the function completes without seeing a failure."), #endif JS_FN_HELP("makeFakePromise", MakeFakePromise, 0, 0, @@ -3432,7 +3544,7 @@ js::DefineTestingFunctions(JSContext* cx, HandleObject obj, bool fuzzingSafe_, bool disableOOMFunctions_) { fuzzingSafe = fuzzingSafe_; - if (getenv("MOZ_FUZZING_SAFE") && getenv("MOZ_FUZZING_SAFE")[0] != '0') + if (EnvVarIsDefined("MOZ_FUZZING_SAFE")) fuzzingSafe = true; disableOOMFunctions = disableOOMFunctions_; diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 5693c80027..b702007a8e 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -3191,7 +3191,11 @@ BytecodeEmitter::emitSwitch(ParseNode* pn) /* Emit code for evaluating cases and jumping to case statements. */ for (ParseNode* caseNode = cases->pn_head; caseNode; caseNode = caseNode->pn_next) { ParseNode* caseValue = caseNode->pn_left; - if (caseValue && !emitTree(caseValue)) + // If the expression is a literal, suppress line number + // emission so that debugging works more naturally. + if (caseValue && + !emitTree(caseValue, caseValue->isLiteral() ? SUPPRESS_LINENOTE : + EMIT_LINENOTE)) return false; if (!beforeCases) { /* prevCaseOffset is the previous JSOP_CASE's bytecode offset. */ @@ -5770,14 +5774,17 @@ BytecodeEmitter::emitCStyleFor(ParseNode* pn, ptrdiff_t top) bool BytecodeEmitter::emitFor(ParseNode* pn, ptrdiff_t top) { + if (pn->pn_left->isKind(PNK_FORHEAD)) + return emitCStyleFor(pn, top); + + if (!updateLineNumberNotes(pn->pn_pos.begin)) + return false; + if (pn->pn_left->isKind(PNK_FORIN)) return emitForIn(pn, top); - if (pn->pn_left->isKind(PNK_FOROF)) - return emitForOf(StmtType::FOR_OF_LOOP, pn, top); - - MOZ_ASSERT(pn->pn_left->isKind(PNK_FORHEAD)); - return emitCStyleFor(pn, top); + MOZ_ASSERT(pn->pn_left->isKind(PNK_FOROF)); + return emitForOf(StmtType::FOR_OF_LOOP, pn, top); } MOZ_NEVER_INLINE bool @@ -6021,6 +6028,20 @@ BytecodeEmitter::emitWhile(ParseNode* pn, ptrdiff_t top) * . . . * N N*(ifeq-fail; goto); ifeq-pass goto; N*ifne-pass; ifne-fail */ + + // If we have a single-line while, like "while (x) ;", we want to + // emit the line note before the initial goto, so that the + // debugger sees a single entry point. This way, if there is a + // breakpoint on the line, it will only fire once; and "next"ing + // will skip the whole loop. However, for the multi-line case we + // want to emit the line note after the initial goto, so that + // "cont" stops on each iteration -- but without a stop before the + // first iteration. + if (parser->tokenStream.srcCoords.lineNum(pn->pn_pos.begin) == + parser->tokenStream.srcCoords.lineNum(pn->pn_pos.end) && + !updateSourceCoordNotes(pn->pn_pos.begin)) + return false; + LoopStmtInfo stmtInfo(cx); pushLoopStatement(&stmtInfo, StmtType::WHILE_LOOP, top); @@ -7552,7 +7573,7 @@ BytecodeEmitter::emitClass(ParseNode* pn) } bool -BytecodeEmitter::emitTree(ParseNode* pn) +BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote) { JS_CHECK_RECURSION(cx, return false); @@ -7562,8 +7583,11 @@ BytecodeEmitter::emitTree(ParseNode* pn) ptrdiff_t top = offset(); pn->pn_offset = top; - /* Emit notes to tell the current bytecode's source line number. */ - if (!updateLineNumberNotes(pn->pn_pos.begin)) + /* Emit notes to tell the current bytecode's source line number. + However, a couple trees require special treatment; see the + relevant emitter functions for details. */ + if (emitLineNote == EMIT_LINENOTE && pn->getKind() != PNK_WHILE && pn->getKind() != PNK_FOR && + !updateLineNumberNotes(pn->pn_pos.begin)) return false; switch (pn->getKind()) { diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index 1c2cff9177..4fa1038e78 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -336,8 +336,14 @@ struct BytecodeEmitter void setJumpOffsetAt(ptrdiff_t off); + // Control whether emitTree emits a line number note. + enum EmitLineNumberNote { + EMIT_LINENOTE, + SUPPRESS_LINENOTE + }; + // Emit code for the tree rooted at pn. - bool emitTree(ParseNode* pn); + bool emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote = EMIT_LINENOTE); // Emit function code for the tree rooted at body. bool emitFunctionScript(ParseNode* body); diff --git a/js/src/jit-test/lib/oomTest.js b/js/src/jit-test/lib/oomTest.js deleted file mode 100644 index 75e6d49219..0000000000 --- a/js/src/jit-test/lib/oomTest.js +++ /dev/null @@ -1,39 +0,0 @@ -// Function to test OOM handling by repeatedly calling a function and failing -// successive allocations. - -if (!("oomAtAllocation" in this && "resetOOMFailure" in this && "oomThreadTypes" in this)) - quit(); - -if ("gczeal" in this) - gczeal(0); - -const verbose = ("os" in this) && os.getenv("OOM_VERBOSE"); - -// Test out of memory handing by calling a function f() while causing successive -// memory allocations to fail. Repeat until f() finishes without reaching the -// failing allocation. -function oomTest(f) { - for (let thread = 1; thread < oomThreadTypes(); thread++) { - if (verbose) - print("testing thread " + thread); - - var i = 1; - var more; - do { - if (verbose) - print("fail at " + i); - try { - oomAtAllocation(i, thread); - f(); - more = resetOOMFailure(); - } catch (e) { - // Ignore exceptions. - more = resetOOMFailure(); - } - i++; - } while(more); - - if (verbose) - print("finished after " + (i - 2) + " failures"); - } -} diff --git a/js/src/jit-test/tests/baseline/bug847425.js b/js/src/jit-test/tests/baseline/bug847425.js index dd6575951d..448abceafa 100644 --- a/js/src/jit-test/tests/baseline/bug847425.js +++ b/js/src/jit-test/tests/baseline/bug847425.js @@ -1,4 +1,4 @@ -// |jit-test| allow-oom +// |jit-test| allow-oom; allow-unhandlable-oom gcparam("maxBytes", gcparam("gcBytes") + 4*1024); var max = 400; function f(b) { diff --git a/js/src/jit-test/tests/basic/bug1220766.js b/js/src/jit-test/tests/basic/bug1220766.js new file mode 100644 index 0000000000..fca11eafe6 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug1220766.js @@ -0,0 +1,3 @@ +iter = getSelfHostedValue("CreateListIterator")([]); +iter.next(); +iter.next(); diff --git a/js/src/jit-test/tests/coverage/bug1214548.js b/js/src/jit-test/tests/coverage/bug1214548.js new file mode 100644 index 0000000000..0aa0072334 --- /dev/null +++ b/js/src/jit-test/tests/coverage/bug1214548.js @@ -0,0 +1,7 @@ +oomTest(() => { + var g = newGlobal(); + g.eval("\ + function f(){}; \ + getLcovInfo(); \ + "); +}); diff --git a/js/src/jit-test/tests/debug/Frame-onStep-14.js b/js/src/jit-test/tests/debug/Frame-onStep-14.js new file mode 100644 index 0000000000..2e77d5647a --- /dev/null +++ b/js/src/jit-test/tests/debug/Frame-onStep-14.js @@ -0,0 +1,46 @@ +// Test how stepping interacts with switch statements. + +var g = newGlobal(); + +g.eval('function bob() { return "bob"; }'); + +// Stepping into a sparse switch should not stop on literal cases. +evaluate(`function lit(x) { // 1 + debugger; // 2 + switch(x) { // 3 + case "nope": // 4 + break; // 5 + case "bob": // 6 + break; // 7 + } // 8 +}`, {lineNumber: 1, global: g}); + +// Stepping into a sparse switch should stop on non-literal cases. +evaluate(`function nonlit(x) { // 1 + debugger; // 2 + switch(x) { // 3 + case bob(): // 4 + break; // 5 + } // 6 +}`, {lineNumber: 1, global: g}); + +var dbg = Debugger(g); +var badStep = false; + +function test(s, okLine) { + dbg.onDebuggerStatement = function(frame) { + frame.onStep = function() { + let thisLine = this.script.getOffsetLocation(this.offset).lineNumber; + // The stop at line 3 is the switch. + if (thisLine > 3) { + assertEq(thisLine, okLine) + frame.onStep = undefined; + } + }; + }; + g.eval(s); +} + +test("lit('bob');", 7); + +test("nonlit('bob');", 4); diff --git a/js/src/jit-test/tests/debug/Script-getLineOffsets-08.js b/js/src/jit-test/tests/debug/Script-getLineOffsets-08.js new file mode 100644 index 0000000000..84914d7334 --- /dev/null +++ b/js/src/jit-test/tests/debug/Script-getLineOffsets-08.js @@ -0,0 +1,24 @@ +// A "while" or a "for" loop should have a single entry point. + +var g = newGlobal(); +var dbg = new Debugger(g); + +dbg.onDebuggerStatement = function(frame) { + var s = frame.eval('f').return.script; + + // There should be just a single entry point for the first line of + // the function. See below to understand the "+2". + assertEq(s.getLineOffsets(g.line0 + 2).length, 1); +}; + + +function test(code) { + g.eval('var line0 = Error().lineNumber;\n' + + 'function f() {\n' + // line0 + 1 + code + '\n' + // line0 + 2 -- see above + '}\n' + + 'debugger;'); +} + +test('while (false)\n;'); +test('for (;false;)\n;'); diff --git a/js/src/jit-test/tests/gc/bug-1165966.js b/js/src/jit-test/tests/gc/bug-1165966.js index 62c5b1a372..bbcf4545e7 100644 --- a/js/src/jit-test/tests/gc/bug-1165966.js +++ b/js/src/jit-test/tests/gc/bug-1165966.js @@ -1,5 +1,7 @@ // |jit-test| --no-ion -load(libdir + 'oomTest.js'); +if (!('oomTest' in this)) + quit(); + var g = newGlobal(); oomTest(function() { Debugger(g); diff --git a/js/src/jit-test/tests/gc/bug-1171909.js b/js/src/jit-test/tests/gc/bug-1171909.js index 5a210fe051..16d4ff1bde 100644 --- a/js/src/jit-test/tests/gc/bug-1171909.js +++ b/js/src/jit-test/tests/gc/bug-1171909.js @@ -1,2 +1,4 @@ -load(libdir + 'oomTest.js'); +if (!('oomTest' in this)) + quit(); + oomTest((function(x) { assertEq(x + y + ex, 25); })); diff --git a/js/src/jit-test/tests/gc/bug-1206677.js b/js/src/jit-test/tests/gc/bug-1206677.js index 9ddfbf383a..c666b7aac8 100644 --- a/js/src/jit-test/tests/gc/bug-1206677.js +++ b/js/src/jit-test/tests/gc/bug-1206677.js @@ -1,6 +1,4 @@ -load(libdir + 'oomTest.js'); - -if (helperThreadCount() === 0) +if (!('oomTest' in this) || helperThreadCount() === 0) quit(0); var lfGlobal = newGlobal(); diff --git a/js/src/jit-test/tests/gc/bug-1208994.js b/js/src/jit-test/tests/gc/bug-1208994.js index 4c69e49879..b2326cd628 100644 --- a/js/src/jit-test/tests/gc/bug-1208994.js +++ b/js/src/jit-test/tests/gc/bug-1208994.js @@ -1,2 +1,4 @@ -load(libdir + 'oomTest.js'); +if (!('oomTest' in this)) + quit(); + oomTest(() => getBacktrace({args: oomTest[load+1], locals: true, thisprops: true})); diff --git a/js/src/jit-test/tests/gc/bug-1209001.js b/js/src/jit-test/tests/gc/bug-1209001.js new file mode 100644 index 0000000000..dfbf54b312 --- /dev/null +++ b/js/src/jit-test/tests/gc/bug-1209001.js @@ -0,0 +1,4 @@ +if (!('oomTest' in this)) + quit(); + +oomTest(() => parseModule('import v from "mod";')); diff --git a/js/src/jit-test/tests/gc/bug-978802.js b/js/src/jit-test/tests/gc/bug-978802.js new file mode 100644 index 0000000000..33c2012ec1 --- /dev/null +++ b/js/src/jit-test/tests/gc/bug-978802.js @@ -0,0 +1,18 @@ +if (!('oomTest' in this)) + quit(); + +oomTest(() => { + try { + var max = 400; + function f(b) { + if (b) { + f(b - 1); + } else { + g = {}; + } + g.apply(null, arguments); + } + f(max - 1); + } catch(exc0) {} + f(); +}); diff --git a/js/src/jit-test/tests/gc/oomInArrayProtoTest.js b/js/src/jit-test/tests/gc/oomInArrayProtoTest.js index 9471013940..c2712d8fd9 100644 --- a/js/src/jit-test/tests/gc/oomInArrayProtoTest.js +++ b/js/src/jit-test/tests/gc/oomInArrayProtoTest.js @@ -1,4 +1,5 @@ -load(libdir + 'oomTest.js'); +if (!('oomTest' in this)) + quit(); function arrayProtoOutOfRange() { function f(obj) { diff --git a/js/src/jit-test/tests/gc/oomInDebugger.js b/js/src/jit-test/tests/gc/oomInDebugger.js index 96f8174bcc..adf7f64a79 100644 --- a/js/src/jit-test/tests/gc/oomInDebugger.js +++ b/js/src/jit-test/tests/gc/oomInDebugger.js @@ -1,3 +1,5 @@ -load(libdir + 'oomTest.js'); +if (!('oomTest' in this)) + quit(); + var g = newGlobal(); oomTest(() => Debugger(g)); diff --git a/js/src/jit-test/tests/gc/oomInExceptionHandlerBailout.js b/js/src/jit-test/tests/gc/oomInExceptionHandlerBailout.js index c00950e77e..fd77c00c6e 100644 --- a/js/src/jit-test/tests/gc/oomInExceptionHandlerBailout.js +++ b/js/src/jit-test/tests/gc/oomInExceptionHandlerBailout.js @@ -1,4 +1,5 @@ -load(libdir + 'oomTest.js'); +if (!('oomTest' in this)) + quit(); oomTest(() => { let x = 0; diff --git a/js/src/jit-test/tests/gc/oomInFormatStackDump.js b/js/src/jit-test/tests/gc/oomInFormatStackDump.js index c801a91f67..94a398b025 100644 --- a/js/src/jit-test/tests/gc/oomInFormatStackDump.js +++ b/js/src/jit-test/tests/gc/oomInFormatStackDump.js @@ -1,2 +1,4 @@ -load(libdir + 'oomTest.js'); +if (!('oomTest' in this)) + quit(); + oomTest(() => getBacktrace({args: true, locals: true, thisprops: true})); diff --git a/js/src/jit-test/tests/gc/oomInGetJumpLabelForBranch.js b/js/src/jit-test/tests/gc/oomInGetJumpLabelForBranch.js index 3e535f31d5..e701554740 100644 --- a/js/src/jit-test/tests/gc/oomInGetJumpLabelForBranch.js +++ b/js/src/jit-test/tests/gc/oomInGetJumpLabelForBranch.js @@ -1,3 +1,5 @@ -// |jit-test| --no-threads -load(libdir + 'oomTest.js'); +// |jit-test| allow-oom; allow-unhandlable-oom; --no-threads +if (!('oomTest' in this)) + quit(); + oomTest(() => getBacktrace({thisprops: gc() && delete addDebuggee.enabled})); diff --git a/js/src/jit-test/tests/gc/oomInNewGlobal.js b/js/src/jit-test/tests/gc/oomInNewGlobal.js index e371c72021..443c3c8e07 100644 --- a/js/src/jit-test/tests/gc/oomInNewGlobal.js +++ b/js/src/jit-test/tests/gc/oomInNewGlobal.js @@ -1,2 +1,4 @@ -load(libdir + 'oomTest.js'); +if (!('oomTest' in this)) + quit(); + oomTest(newGlobal); diff --git a/js/src/jit-test/tests/gc/oomInParseAsmJS.js b/js/src/jit-test/tests/gc/oomInParseAsmJS.js index 0ae3736a13..b5279a26a6 100644 --- a/js/src/jit-test/tests/gc/oomInParseAsmJS.js +++ b/js/src/jit-test/tests/gc/oomInParseAsmJS.js @@ -1,4 +1,6 @@ -load(libdir + 'oomTest.js'); +if (!('oomTest' in this)) + quit(); + function parseAsmJS() { eval(`function m(stdlib) { diff --git a/js/src/jit-test/tests/gc/oomInParseFunction.js b/js/src/jit-test/tests/gc/oomInParseFunction.js index 070e0e7103..9946bc2d00 100644 --- a/js/src/jit-test/tests/gc/oomInParseFunction.js +++ b/js/src/jit-test/tests/gc/oomInParseFunction.js @@ -1,2 +1,4 @@ -load(libdir + 'oomTest.js'); +if (!('oomTest' in this)) + quit(); + oomTest(() => eval("function f() {}")); diff --git a/js/src/jit-test/tests/gc/oomInRegExp.js b/js/src/jit-test/tests/gc/oomInRegExp.js index 01066cd997..a675f9b53c 100644 --- a/js/src/jit-test/tests/gc/oomInRegExp.js +++ b/js/src/jit-test/tests/gc/oomInRegExp.js @@ -1,3 +1,5 @@ -load(libdir + 'oomTest.js'); +if (!('oomTest' in this)) + quit(); + oomTest(() => assertEq("foobar\xff5baz\u1200".search(/bar\u0178\d/i), 3)); oomTest(() => assertEq((/(?!(?!(?!6)[\Wc]))/i).test(), false)); diff --git a/js/src/jit-test/tests/gc/oomInWeakMap.js b/js/src/jit-test/tests/gc/oomInWeakMap.js index e26fb5d5f3..157d728907 100644 --- a/js/src/jit-test/tests/gc/oomInWeakMap.js +++ b/js/src/jit-test/tests/gc/oomInWeakMap.js @@ -1,4 +1,6 @@ -load(libdir + 'oomTest.js'); +if (!('oomTest' in this)) + quit(); + oomTest(function () { eval(`var wm = new WeakMap(); wm.set({}, 'FOO').get(false);`); diff --git a/js/src/jit-test/tests/modules/bug-1219044.js b/js/src/jit-test/tests/modules/bug-1219044.js new file mode 100644 index 0000000000..82cfeebb00 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1219044.js @@ -0,0 +1,5 @@ +if (!('oomTest' in this)) + quit(); + +oomTest(() => parseModule('import v from "mod";')); +fullcompartmentchecks(true); diff --git a/js/src/jit-test/tests/modules/bug-1219408.js b/js/src/jit-test/tests/modules/bug-1219408.js new file mode 100644 index 0000000000..85d7092894 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1219408.js @@ -0,0 +1,2 @@ +// |jit-test| error: Error +parseModule("").evaluation(); diff --git a/js/src/jit-test/tests/profiler/bug1211962.js b/js/src/jit-test/tests/profiler/bug1211962.js index 532fa93fc6..01e819d502 100644 --- a/js/src/jit-test/tests/profiler/bug1211962.js +++ b/js/src/jit-test/tests/profiler/bug1211962.js @@ -1,5 +1,6 @@ // |jit-test| slow; -load(libdir + "oomTest.js"); +if (!('oomTest' in this)) + quit(); enableSPSProfiling(); var lfGlobal = newGlobal(); diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index a5a65f6b4b..529f1524f6 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -11883,6 +11883,11 @@ IonBuilder::getPropTryInnerize(bool* emitted, MDefinition* obj, PropertyName* na { // See the comment in tryInnerizeWindow for how this works. + // Note that it's important that we do this _before_ we'd try to + // do the optimizations below on obj normally, since some of those + // optimizations have fallback paths that are slower than the path + // we'd produce here. + MOZ_ASSERT(*emitted == false); MDefinition* inner = tryInnerizeWindow(obj); @@ -11890,15 +11895,6 @@ IonBuilder::getPropTryInnerize(bool* emitted, MDefinition* obj, PropertyName* na return true; if (!forceInlineCaches()) { - // Note: the Baseline ICs don't know about this optimization, so it's - // possible the global property's HeapTypeSet has not been initialized - // yet. In this case we'll fall back to getPropTryCache for now. - - // Note that it's important that we do this _before_ we'd try to - // do the optimizations below on obj normally, since some of those - // optimizations have fallback paths that are slower than the path - // we'd produce here. - trackOptimizationAttempt(TrackedStrategy::GetProp_Constant); if (!getPropTryConstant(emitted, inner, NameToId(name), types) || *emitted) return *emitted; diff --git a/js/src/jit/mips-shared/Assembler-mips-shared.cpp b/js/src/jit/mips-shared/Assembler-mips-shared.cpp index 6dbc8d22ea..83264fe24e 100644 --- a/js/src/jit/mips-shared/Assembler-mips-shared.cpp +++ b/js/src/jit/mips-shared/Assembler-mips-shared.cpp @@ -1298,6 +1298,10 @@ AssemblerMIPSShared::bind(Label* label, BufferOffset boff) // A used label holds a link to branch that uses it. BufferOffset b(label); do { + // Even a 0 offset may be invalid if we're out of memory. + if (oom()) + return; + Instruction* inst = editSrc(b); // Second word holds a pointer to the next branch in label's chain. @@ -1313,7 +1317,7 @@ AssemblerMIPSShared::bind(Label* label, BufferOffset boff) void AssemblerMIPSShared::retarget(Label* label, Label* target) { - if (label->used()) { + if (label->used() && !oom()) { if (target->bound()) { bind(label, BufferOffset(target)); } else if (target->used()) { diff --git a/js/src/jit/mips-shared/Assembler-mips-shared.h b/js/src/jit/mips-shared/Assembler-mips-shared.h index a42a97650e..137f7afff1 100644 --- a/js/src/jit/mips-shared/Assembler-mips-shared.h +++ b/js/src/jit/mips-shared/Assembler-mips-shared.h @@ -1030,7 +1030,7 @@ class AssemblerMIPSShared : public AssemblerShared // label operations void bind(Label* label, BufferOffset boff = BufferOffset()); - virtual void bind(InstImm* inst, uint32_t branch, uint32_t target) = 0; + virtual void bind(InstImm* inst, uintptr_t branch, uintptr_t target) = 0; virtual void Bind(uint8_t* rawCode, AbsoluteLabel* label, const void* address) = 0; uint32_t currentOffset() { return nextOffset().getOffset(); diff --git a/js/src/jit/mips-shared/Bailouts-mips-shared.cpp b/js/src/jit/mips-shared/Bailouts-mips-shared.cpp index 16042181b2..7d8c2a76da 100644 --- a/js/src/jit/mips-shared/Bailouts-mips-shared.cpp +++ b/js/src/jit/mips-shared/Bailouts-mips-shared.cpp @@ -4,10 +4,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "jit/mips-shared/Bailouts-mips-shared.h" - -#include "jscntxt.h" -#include "jscompartment.h" +#include "jit/Bailouts.h" using namespace js; using namespace js::jit; diff --git a/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp b/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp index 8bcba6dc86..b8facc61c5 100644 --- a/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp +++ b/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp @@ -198,16 +198,6 @@ CodeGeneratorMIPSShared::bailout(LSnapshot* snapshot) bailoutFrom(&label, snapshot); } -void -CodeGeneratorMIPSShared::visitOutOfLineBailout(OutOfLineBailout* ool) -{ - // Push snapshotOffset and make sure stack is aligned. - masm.subPtr(Imm32(2 * sizeof(void*)), StackPointer); - masm.storePtr(ImmWord(ool->snapshot()->snapshotOffset()), Address(StackPointer, 0)); - - masm.jump(&deoptLabel_); -} - void CodeGeneratorMIPSShared::visitMinMaxD(LMinMaxD* ins) { diff --git a/js/src/jit/mips-shared/CodeGenerator-mips-shared.h b/js/src/jit/mips-shared/CodeGenerator-mips-shared.h index b7e237f464..f1bfae2484 100644 --- a/js/src/jit/mips-shared/CodeGenerator-mips-shared.h +++ b/js/src/jit/mips-shared/CodeGenerator-mips-shared.h @@ -175,7 +175,7 @@ class CodeGeneratorMIPSShared : public CodeGeneratorShared virtual void visitTruncateFToInt32(LTruncateFToInt32* ins); // Out of line visitors. - void visitOutOfLineBailout(OutOfLineBailout* ool); + virtual void visitOutOfLineBailout(OutOfLineBailout* ool) = 0; protected: virtual ValueOperand ToOutValue(LInstruction* ins) = 0; void memoryBarrier(MemoryBarrierBits barrier); diff --git a/js/src/jit/mips32/Architecture-mips32.h b/js/src/jit/mips32/Architecture-mips32.h index a34bfb8960..a4c3aee4c3 100644 --- a/js/src/jit/mips32/Architecture-mips32.h +++ b/js/src/jit/mips32/Architecture-mips32.h @@ -47,15 +47,25 @@ class FloatRegisters : public FloatRegistersMIPSShared public: static const char* GetName(uint32_t i) { MOZ_ASSERT(i < Total); - return GetName(Code(i % 32)); + return FloatRegistersMIPSShared::GetName(Code(i % 32)); } static Code FromName(const char* name); static const uint32_t Total = 64; static const uint32_t TotalDouble = 16; + static const uint32_t RegisterIdLimit = 32; + // Workarounds: On Loongson CPU-s the odd FP registers behave differently + // in fp-32 mode than standard MIPS. +#if defined(_MIPS_ARCH_LOONGSON3A) + static const uint32_t TotalSingle = 16; + static const uint32_t Allocatable = 28; + static const SetType AllSingleMask = 0x55555555ULL; +#else static const uint32_t TotalSingle = 32; static const uint32_t Allocatable = 42; + static const SetType AllSingleMask = (1ULL << 32) - 1; +#endif // When saving all registers we only need to do is save double registers. static const uint32_t TotalPhys = 16; @@ -63,7 +73,7 @@ class FloatRegisters : public FloatRegistersMIPSShared "SetType should be large enough to enumerate all registers."); static const SetType AllDoubleMask = 0x55555555ULL << 32; - static const SetType AllMask = AllDoubleMask | ((1ULL << 32) - 1); + static const SetType AllMask = AllDoubleMask | AllSingleMask; static const SetType NonVolatileDoubleMask = ((1ULL << FloatRegisters::f20) | @@ -165,7 +175,7 @@ class FloatRegister : public FloatRegisterMIPSShared } Encoding encoding() const { MOZ_ASSERT(!isInvalid()); - return Code(code_ | (kind_ << 5)); + return Encoding(code_); } uint32_t id() const { return code_; @@ -178,10 +188,15 @@ class FloatRegister : public FloatRegisterMIPSShared // This is similar to FromCode except for double registers on O32. static FloatRegister FromIndex(uint32_t index, RegType kind) { #if defined(USES_O32_ABI) + // Only even FP registers are avaiable for Loongson on O32. +# if defined(_MIPS_ARCH_LOONGSON3A) + return FloatRegister(index * 2, kind); +# else if (kind == Double) - return FloatRegister(index * 2, RegType(kind)); + return FloatRegister(index * 2, kind); +# endif #endif - return FloatRegister(index, RegType(kind)); + return FloatRegister(index, kind); } bool volatile_() const { diff --git a/js/src/jit/mips32/Assembler-mips32.cpp b/js/src/jit/mips32/Assembler-mips32.cpp index 53956106d7..b3ca5c9a46 100644 --- a/js/src/jit/mips32/Assembler-mips32.cpp +++ b/js/src/jit/mips32/Assembler-mips32.cpp @@ -82,21 +82,21 @@ const Register ABIArgGenerator::NonReturn_VolatileReg1 = a1; uint32_t js::jit::RT(FloatRegister r) { - MOZ_ASSERT(r.id() < FloatRegisters::TotalSingle); + MOZ_ASSERT(r.id() < FloatRegisters::RegisterIdLimit); return r.id() << RTShift; } uint32_t js::jit::RD(FloatRegister r) { - MOZ_ASSERT(r.id() < FloatRegisters::TotalSingle); + MOZ_ASSERT(r.id() < FloatRegisters::RegisterIdLimit); return r.id() << RDShift; } uint32_t js::jit::SA(FloatRegister r) { - MOZ_ASSERT(r.id() < FloatRegisters::TotalSingle); + MOZ_ASSERT(r.id() < FloatRegisters::RegisterIdLimit); return r.id() << SAShift; } @@ -261,7 +261,7 @@ Assembler::Bind(uint8_t* rawCode, AbsoluteLabel* label, const void* address) } void -Assembler::bind(InstImm* inst, uint32_t branch, uint32_t target) +Assembler::bind(InstImm* inst, uintptr_t branch, uintptr_t target) { int32_t offset = target - branch; InstImm inst_bgezal = InstImm(op_regimm, zero, rt_bgezal, BOffImm16(0)); @@ -321,7 +321,7 @@ void Assembler::bind(RepatchLabel* label) { BufferOffset dest = nextOffset(); - if (label->used()) { + if (label->used() && !oom()) { // If the label has a use, then change this use to refer to // the bound label; BufferOffset b(label->offset()); diff --git a/js/src/jit/mips32/Assembler-mips32.h b/js/src/jit/mips32/Assembler-mips32.h index 25877b18e0..4c067579e9 100644 --- a/js/src/jit/mips32/Assembler-mips32.h +++ b/js/src/jit/mips32/Assembler-mips32.h @@ -129,7 +129,7 @@ class Assembler : public AssemblerMIPSShared static void TraceJumpRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader); static void TraceDataRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader); - void bind(InstImm* inst, uint32_t branch, uint32_t target); + void bind(InstImm* inst, uintptr_t branch, uintptr_t target); // Copy the assembly code to the given buffer, and perform any pending // relocations relying on the target address. diff --git a/js/src/jit/mips32/Bailouts-mips32.cpp b/js/src/jit/mips32/Bailouts-mips32.cpp index c8856fdc6d..1b92d729c9 100644 --- a/js/src/jit/mips32/Bailouts-mips32.cpp +++ b/js/src/jit/mips32/Bailouts-mips32.cpp @@ -4,11 +4,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "jit/mips32/Bailouts-mips32.h" + #include "jscntxt.h" #include "jscompartment.h" -#include "jit/mips-shared/Bailouts-mips-shared.h" - using namespace js; using namespace js::jit; diff --git a/js/src/jit/mips-shared/Bailouts-mips-shared.h b/js/src/jit/mips32/Bailouts-mips32.h similarity index 93% rename from js/src/jit/mips-shared/Bailouts-mips-shared.h rename to js/src/jit/mips32/Bailouts-mips32.h index 575d13def2..0c4d7f3132 100644 --- a/js/src/jit/mips-shared/Bailouts-mips-shared.h +++ b/js/src/jit/mips32/Bailouts-mips32.h @@ -4,8 +4,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef jit_mips_shared_Bailouts_mips_shared_h -#define jit_mips_shared_Bailouts_mips_shared_h +#ifndef jit_mips32_Bailouts_mips32_h +#define jit_mips32_Bailouts_mips32_h #include "jit/Bailouts.h" #include "jit/JitCompartment.h" @@ -74,4 +74,4 @@ class BailoutStack } // namespace jit } // namespace js -#endif /* jit_mips_shared_Bailouts_mips_shared_h */ +#endif /* jit_mips32_Bailouts_mips32_h */ diff --git a/js/src/jit/mips32/CodeGenerator-mips32.cpp b/js/src/jit/mips32/CodeGenerator-mips32.cpp index f469463fda..df446419c2 100644 --- a/js/src/jit/mips32/CodeGenerator-mips32.cpp +++ b/js/src/jit/mips32/CodeGenerator-mips32.cpp @@ -46,6 +46,16 @@ class js::jit::OutOfLineTableSwitch : public OutOfLineCodeBasesnapshot()->snapshotOffset()), Address(StackPointer, 0)); + + masm.jump(&deoptLabel_); +} + void CodeGeneratorMIPS::visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool) { diff --git a/js/src/jit/mips32/CodeGenerator-mips32.h b/js/src/jit/mips32/CodeGenerator-mips32.h index 329c03efbf..220b7365f5 100644 --- a/js/src/jit/mips32/CodeGenerator-mips32.h +++ b/js/src/jit/mips32/CodeGenerator-mips32.h @@ -40,6 +40,7 @@ class CodeGeneratorMIPS : public CodeGeneratorMIPSShared virtual void visitCompareBitwiseAndBranch(LCompareBitwiseAndBranch* lir); // Out of line visitors. + void visitOutOfLineBailout(OutOfLineBailout* ool); void visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool); protected: ValueOperand ToValue(LInstruction* ins, size_t pos); diff --git a/js/src/jit/mips32/MacroAssembler-mips32.cpp b/js/src/jit/mips32/MacroAssembler-mips32.cpp index 9ffee05b3a..6b727bfb0e 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.cpp +++ b/js/src/jit/mips32/MacroAssembler-mips32.cpp @@ -596,7 +596,8 @@ MacroAssemblerMIPS::ma_bal(Label* label, DelaySlotFill delaySlotFill) BufferOffset bo = writeInst(getBranchCode(BranchIsCall).encode()); writeInst(nextInChain); - label->use(bo.getOffset()); + if (!oom()) + label->use(bo.getOffset()); // Leave space for long jump. as_nop(); if (delaySlotFill == FillDelaySlot) @@ -655,7 +656,8 @@ MacroAssemblerMIPS::branchWithCode(InstImm code, Label* label, JumpKind jumpKind code.setBOffImm16(BOffImm16(4)); BufferOffset bo = writeInst(code.encode()); writeInst(nextInChain); - label->use(bo.getOffset()); + if (!oom()) + label->use(bo.getOffset()); return; } @@ -666,7 +668,8 @@ MacroAssemblerMIPS::branchWithCode(InstImm code, Label* label, JumpKind jumpKind BufferOffset bo = writeInst(code.encode()); writeInst(nextInChain); - label->use(bo.getOffset()); + if (!oom()) + label->use(bo.getOffset()); // Leave space for potential long jump. as_nop(); as_nop(); diff --git a/js/src/jit/mips32/Simulator-mips32.cpp b/js/src/jit/mips32/Simulator-mips32.cpp index 40e873f7ba..9a331ea5c9 100644 --- a/js/src/jit/mips32/Simulator-mips32.cpp +++ b/js/src/jit/mips32/Simulator-mips32.cpp @@ -727,7 +727,7 @@ MipsDebugger::printAllRegsIncludingFPU() printf("\n\n"); // f0, f1, f2, ... f31. - for (uint32_t i = 0; i < FloatRegisters::TotalSingle; i++) { + for (uint32_t i = 0; i < FloatRegisters::RegisterIdLimit; i++) { if (i & 0x1) { printf("%3s: 0x%08x\tflt: %-8.4g\n", FloatRegisters::GetName(i), diff --git a/js/src/jit/mips32/Trampoline-mips32.cpp b/js/src/jit/mips32/Trampoline-mips32.cpp index dbfb4ffbd0..a01c881fb8 100644 --- a/js/src/jit/mips32/Trampoline-mips32.cpp +++ b/js/src/jit/mips32/Trampoline-mips32.cpp @@ -13,7 +13,7 @@ #include "jit/JitFrames.h" #include "jit/JitSpewer.h" #include "jit/Linker.h" -#include "jit/mips-shared/Bailouts-mips-shared.h" +#include "jit/mips32/Bailouts-mips32.h" #include "jit/mips32/SharedICHelpers-mips32.h" #ifdef JS_ION_PERF # include "jit/PerfSpewer.h" diff --git a/js/src/jit/mips64/Assembler-mips64.cpp b/js/src/jit/mips64/Assembler-mips64.cpp index dd80f1fe1c..4820be7d8b 100644 --- a/js/src/jit/mips64/Assembler-mips64.cpp +++ b/js/src/jit/mips64/Assembler-mips64.cpp @@ -256,7 +256,7 @@ Assembler::Bind(uint8_t* rawCode, AbsoluteLabel* label, const void* address) } void -Assembler::bind(InstImm* inst, uint64_t branch, uint64_t target) +Assembler::bind(InstImm* inst, uintptr_t branch, uintptr_t target) { int64_t offset = target - branch; InstImm inst_bgezal = InstImm(op_regimm, zero, rt_bgezal, BOffImm16(0)); @@ -281,18 +281,21 @@ Assembler::bind(InstImm* inst, uint64_t branch, uint64_t target) } if (BOffImm16::IsInRange(offset)) { - bool conditional = (inst[0].encode() != inst_bgezal.encode() && - inst[0].encode() != inst_beq.encode()); - inst[0].setBOffImm16(BOffImm16(offset)); inst[1].makeNop(); + // Don't skip trailing nops can imporve performance + // on Loongson3 platform. +#ifndef _MIPS_ARCH_LOONGSON3A + bool conditional = (inst[0].encode() != inst_bgezal.encode() && + inst[0].encode() != inst_beq.encode()); + // Skip the trailing nops in conditional branches. - // FIXME: On Loongson3 platform, the branch degrade performance. - if (0 && conditional) { + if (conditional) { inst[2] = InstImm(op_regimm, zero, rt_bgez, BOffImm16(5 * sizeof(uint32_t))).encode(); // There are 4 nops after this } +#endif return; } @@ -317,7 +320,7 @@ void Assembler::bind(RepatchLabel* label) { BufferOffset dest = nextOffset(); - if (label->used()) { + if (label->used() && !oom()) { // If the label has a use, then change this use to refer to // the bound label; BufferOffset b(label->offset()); @@ -368,10 +371,10 @@ uint64_t Assembler::ExtractLoad64Value(Instruction* inst0) { InstImm* i0 = (InstImm*) inst0; - InstImm* i1 = (InstImm*) inst0->next(); - InstReg* i2 = (InstReg*) inst1->next(); - InstImm* i3 = (InstImm*) inst2->next(); - InstImm* i5 = (InstImm*) inst3->next()->next(); + InstImm* i1 = (InstImm*) i0->next(); + InstReg* i2 = (InstReg*) i1->next(); + InstImm* i3 = (InstImm*) i2->next(); + InstImm* i5 = (InstImm*) i3->next()->next(); MOZ_ASSERT(i0->extractOpcode() == ((uint32_t)op_lui >> OpcodeShift)); MOZ_ASSERT(i1->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift)); @@ -398,10 +401,10 @@ void Assembler::UpdateLoad64Value(Instruction* inst0, uint64_t value) { InstImm* i0 = (InstImm*) inst0; - InstImm* i1 = (InstImm*) inst0->next(); - InstReg* i2 = (InstReg*) inst1->next(); - InstImm* i3 = (InstImm*) inst2->next(); - InstImm* i5 = (InstImm*) inst3->next()->next(); + InstImm* i1 = (InstImm*) i0->next(); + InstReg* i2 = (InstReg*) i1->next(); + InstImm* i3 = (InstImm*) i2->next(); + InstImm* i5 = (InstImm*) i3->next()->next(); MOZ_ASSERT(i0->extractOpcode() == ((uint32_t)op_lui >> OpcodeShift)); MOZ_ASSERT(i1->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift)); diff --git a/js/src/jit/mips64/Assembler-mips64.h b/js/src/jit/mips64/Assembler-mips64.h index 85ca1c1890..6dd8e52398 100644 --- a/js/src/jit/mips64/Assembler-mips64.h +++ b/js/src/jit/mips64/Assembler-mips64.h @@ -131,7 +131,7 @@ class Assembler : public AssemblerMIPSShared static void TraceJumpRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader); static void TraceDataRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader); - void bind(InstImm* inst, uint64_t branch, uint64_t target); + void bind(InstImm* inst, uintptr_t branch, uintptr_t target); // Copy the assembly code to the given buffer, and perform any pending // relocations relying on the target address. diff --git a/js/src/jit/mips64/Bailouts-mips64.cpp b/js/src/jit/mips64/Bailouts-mips64.cpp index 022560a442..3c6c4c6c47 100644 --- a/js/src/jit/mips64/Bailouts-mips64.cpp +++ b/js/src/jit/mips64/Bailouts-mips64.cpp @@ -4,17 +4,17 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "jit/mips64/Bailouts-mips64.h" + #include "jscntxt.h" #include "jscompartment.h" -#include "jit/mips-shared/Bailouts-mips-shared.h" - using namespace js; using namespace js::jit; BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator& activations, BailoutStack* bailout) - : machine_(bailout->machine()) + : machine_(bailout->machineState()) { uint8_t* sp = bailout->parentStackPointer(); framePointer_ = sp + bailout->frameSize(); diff --git a/js/src/jit/mips64/Bailouts-mips64.h b/js/src/jit/mips64/Bailouts-mips64.h new file mode 100644 index 0000000000..1f80b303f8 --- /dev/null +++ b/js/src/jit/mips64/Bailouts-mips64.h @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef jit_mips64_Bailouts_mips64_h +#define jit_mips64_Bailouts_mips64_h + +#include "jit/Bailouts.h" +#include "jit/JitCompartment.h" + +namespace js { +namespace jit { + +class BailoutStack +{ + RegisterDump::FPUArray fpregs_; + RegisterDump::GPRArray regs_; + uintptr_t frameSize_; + uintptr_t snapshotOffset_; + + public: + MachineState machineState() { + return MachineState::FromBailout(regs_, fpregs_); + } + uint32_t snapshotOffset() const { + return snapshotOffset_; + } + uint32_t frameSize() const { + return frameSize_; + } + uint8_t* parentStackPointer() { + return (uint8_t*)this + sizeof(BailoutStack); + } + static size_t offsetOfFrameSize() { + return offsetof(BailoutStack, frameSize_); + } +}; + +} // namespace jit +} // namespace js + +#endif /* jit_mips64_Bailouts_mips64_h */ diff --git a/js/src/jit/mips64/CodeGenerator-mips64.cpp b/js/src/jit/mips64/CodeGenerator-mips64.cpp index 5efe8572da..83500add1b 100644 --- a/js/src/jit/mips64/CodeGenerator-mips64.cpp +++ b/js/src/jit/mips64/CodeGenerator-mips64.cpp @@ -46,6 +46,14 @@ class js::jit::OutOfLineTableSwitch : public OutOfLineCodeBasesnapshot()->snapshotOffset())); + + masm.jump(&deoptLabel_); +} + void CodeGeneratorMIPS64::visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool) { diff --git a/js/src/jit/mips64/CodeGenerator-mips64.h b/js/src/jit/mips64/CodeGenerator-mips64.h index e08fc2ca18..c1ed1e62c5 100644 --- a/js/src/jit/mips64/CodeGenerator-mips64.h +++ b/js/src/jit/mips64/CodeGenerator-mips64.h @@ -46,6 +46,7 @@ class CodeGeneratorMIPS64 : public CodeGeneratorMIPSShared virtual void visitCompareBitwiseAndBranch(LCompareBitwiseAndBranch* lir); // Out of line visitors. + void visitOutOfLineBailout(OutOfLineBailout* ool); void visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool); protected: ValueOperand ToValue(LInstruction* ins, size_t pos); diff --git a/js/src/jit/mips64/MacroAssembler-mips64.cpp b/js/src/jit/mips64/MacroAssembler-mips64.cpp index e52b56e310..c5792759dc 100644 --- a/js/src/jit/mips64/MacroAssembler-mips64.cpp +++ b/js/src/jit/mips64/MacroAssembler-mips64.cpp @@ -703,7 +703,8 @@ MacroAssemblerMIPS64::ma_bal(Label* label, DelaySlotFill delaySlotFill) BufferOffset bo = writeInst(getBranchCode(BranchIsCall).encode()); writeInst(nextInChain); - label->use(bo.getOffset()); + if (!oom()) + label->use(bo.getOffset()); // Leave space for long jump. as_nop(); as_nop(); @@ -765,7 +766,8 @@ MacroAssemblerMIPS64::branchWithCode(InstImm code, Label* label, JumpKind jumpKi code.setBOffImm16(BOffImm16(4)); BufferOffset bo = writeInst(code.encode()); writeInst(nextInChain); - label->use(bo.getOffset()); + if (!oom()) + label->use(bo.getOffset()); return; } @@ -777,7 +779,8 @@ MacroAssemblerMIPS64::branchWithCode(InstImm code, Label* label, JumpKind jumpKi BufferOffset bo = writeInst(code.encode()); writeInst(nextInChain); - label->use(bo.getOffset()); + if (!oom()) + label->use(bo.getOffset()); // Leave space for potential long jump. as_nop(); as_nop(); @@ -2526,6 +2529,105 @@ MacroAssemblerMIPS64Compat::handleFailureWithHandlerTail(void* handler) jump(a1); } +template +void +MacroAssemblerMIPS64Compat::compareExchangeToTypedIntArray(Scalar::Type arrayType, const T& mem, + Register oldval, Register newval, + Register temp, Register valueTemp, + Register offsetTemp, Register maskTemp, + AnyRegister output) +{ + switch (arrayType) { + case Scalar::Int8: + compareExchange8SignExtend(mem, oldval, newval, valueTemp, offsetTemp, maskTemp, output.gpr()); + break; + case Scalar::Uint8: + compareExchange8ZeroExtend(mem, oldval, newval, valueTemp, offsetTemp, maskTemp, output.gpr()); + break; + case Scalar::Uint8Clamped: + compareExchange8ZeroExtend(mem, oldval, newval, valueTemp, offsetTemp, maskTemp, output.gpr()); + break; + case Scalar::Int16: + compareExchange16SignExtend(mem, oldval, newval, valueTemp, offsetTemp, maskTemp, output.gpr()); + break; + case Scalar::Uint16: + compareExchange16ZeroExtend(mem, oldval, newval, valueTemp, offsetTemp, maskTemp, output.gpr()); + break; + case Scalar::Int32: + compareExchange32(mem, oldval, newval, valueTemp, offsetTemp, maskTemp, output.gpr()); + break; + case Scalar::Uint32: + // At the moment, the code in MCallOptimize.cpp requires the output + // type to be double for uint32 arrays. See bug 1077305. + MOZ_ASSERT(output.isFloat()); + compareExchange32(mem, oldval, newval, valueTemp, offsetTemp, maskTemp, temp); + convertUInt32ToDouble(temp, output.fpu()); + break; + default: + MOZ_CRASH("Invalid typed array type"); + } +} + +template void +MacroAssemblerMIPS64Compat::compareExchangeToTypedIntArray(Scalar::Type arrayType, const Address& mem, + Register oldval, Register newval, Register temp, + Register valueTemp, Register offsetTemp, Register maskTemp, + AnyRegister output); +template void +MacroAssemblerMIPS64Compat::compareExchangeToTypedIntArray(Scalar::Type arrayType, const BaseIndex& mem, + Register oldval, Register newval, Register temp, + Register valueTemp, Register offsetTemp, Register maskTemp, + AnyRegister output); + +template +void +MacroAssemblerMIPS64Compat::atomicExchangeToTypedIntArray(Scalar::Type arrayType, const T& mem, + Register value, Register temp, Register valueTemp, + Register offsetTemp, Register maskTemp, + AnyRegister output) +{ + switch (arrayType) { + case Scalar::Int8: + atomicExchange8SignExtend(mem, value, valueTemp, offsetTemp, maskTemp, output.gpr()); + break; + case Scalar::Uint8: + atomicExchange8ZeroExtend(mem, value, valueTemp, offsetTemp, maskTemp, output.gpr()); + break; + case Scalar::Uint8Clamped: + atomicExchange8ZeroExtend(mem, value, valueTemp, offsetTemp, maskTemp, output.gpr()); + break; + case Scalar::Int16: + atomicExchange16SignExtend(mem, value, valueTemp, offsetTemp, maskTemp, output.gpr()); + break; + case Scalar::Uint16: + atomicExchange16ZeroExtend(mem, value, valueTemp, offsetTemp, maskTemp, output.gpr()); + break; + case Scalar::Int32: + atomicExchange32(mem, value, valueTemp, offsetTemp, maskTemp, output.gpr()); + break; + case Scalar::Uint32: + // At the moment, the code in MCallOptimize.cpp requires the output + // type to be double for uint32 arrays. See bug 1077305. + MOZ_ASSERT(output.isFloat()); + atomicExchange32(mem, value, valueTemp, offsetTemp, maskTemp, temp); + convertUInt32ToDouble(temp, output.fpu()); + break; + default: + MOZ_CRASH("Invalid typed array type"); + } +} + +template void +MacroAssemblerMIPS64Compat::atomicExchangeToTypedIntArray(Scalar::Type arrayType, const Address& mem, + Register value, Register temp, Register valueTemp, + Register offsetTemp, Register maskTemp, + AnyRegister output); +template void +MacroAssemblerMIPS64Compat::atomicExchangeToTypedIntArray(Scalar::Type arrayType, const BaseIndex& mem, + Register value, Register temp, Register valueTemp, + Register offsetTemp, Register maskTemp, + AnyRegister output); + CodeOffsetLabel MacroAssemblerMIPS64Compat::toggledJump(Label* label) { diff --git a/js/src/jit/mips64/MacroAssembler-mips64.h b/js/src/jit/mips64/MacroAssembler-mips64.h index 4422070f4b..a7f6055c81 100644 --- a/js/src/jit/mips64/MacroAssembler-mips64.h +++ b/js/src/jit/mips64/MacroAssembler-mips64.h @@ -772,219 +772,322 @@ class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64 // The following functions are exposed for use in platform-shared code. template - void compareExchange8SignExtend(const T& mem, Register oldval, Register newval, Register output) + void compareExchange8SignExtend(const T& mem, Register oldval, Register newval, Register valueTemp, + Register offsetTemp, Register maskTemp, Register output) { - MOZ_CRASH("NYI"); + compareExchange(1, true, mem, oldval, newval, valueTemp, offsetTemp, maskTemp, output); } template - void compareExchange8ZeroExtend(const T& mem, Register oldval, Register newval, Register output) + void compareExchange8ZeroExtend(const T& mem, Register oldval, Register newval, Register valueTemp, + Register offsetTemp, Register maskTemp, Register output) { - MOZ_CRASH("NYI"); + compareExchange(1, false, mem, oldval, newval, valueTemp, offsetTemp, maskTemp, output); } template - void compareExchange16SignExtend(const T& mem, Register oldval, Register newval, Register output) + void compareExchange16SignExtend(const T& mem, Register oldval, Register newval, Register valueTemp, + Register offsetTemp, Register maskTemp, Register output) { - MOZ_CRASH("NYI"); + compareExchange(2, true, mem, oldval, newval, valueTemp, offsetTemp, maskTemp, output); } template - void compareExchange16ZeroExtend(const T& mem, Register oldval, Register newval, Register output) + void compareExchange16ZeroExtend(const T& mem, Register oldval, Register newval, Register valueTemp, + Register offsetTemp, Register maskTemp, Register output) { - MOZ_CRASH("NYI"); + compareExchange(2, false, mem, oldval, newval, valueTemp, offsetTemp, maskTemp, output); } template - void compareExchange32(const T& mem, Register oldval, Register newval, Register output) + void compareExchange32(const T& mem, Register oldval, Register newval, Register valueTemp, + Register offsetTemp, Register maskTemp, Register output) { - MOZ_CRASH("NYI"); + compareExchange(4, false, mem, oldval, newval, valueTemp, offsetTemp, maskTemp, output); } template - void atomicExchange8SignExtend(const T& mem, Register value, Register output) + void atomicExchange8SignExtend(const T& mem, Register value, Register valueTemp, + Register offsetTemp, Register maskTemp, Register output) { - MOZ_CRASH("NYI"); + atomicExchange(1, true, mem, value, valueTemp, offsetTemp, maskTemp, output); } template - void atomicExchange8ZeroExtend(const T& mem, Register value, Register output) + void atomicExchange8ZeroExtend(const T& mem, Register value, Register valueTemp, + Register offsetTemp, Register maskTemp, Register output) { - MOZ_CRASH("NYI"); + atomicExchange(1, false, mem, value, valueTemp, offsetTemp, maskTemp, output); } template - void atomicExchange16SignExtend(const T& mem, Register value, Register output) + void atomicExchange16SignExtend(const T& mem, Register value, Register valueTemp, + Register offsetTemp, Register maskTemp, Register output) { - MOZ_CRASH("NYI"); + atomicExchange(2, true, mem, value, valueTemp, offsetTemp, maskTemp, output); } template - void atomicExchange16ZeroExtend(const T& mem, Register value, Register output) + void atomicExchange16ZeroExtend(const T& mem, Register value, Register valueTemp, + Register offsetTemp, Register maskTemp, Register output) { - MOZ_CRASH("NYI"); + atomicExchange(2, false, mem, value, valueTemp, offsetTemp, maskTemp, output); } template - void atomicExchange32(const T& mem, Register value, Register output) + void atomicExchange32(const T& mem, Register value, Register valueTemp, + Register offsetTemp, Register maskTemp, Register output) { - MOZ_CRASH("NYI"); + atomicExchange(4, false, mem, value, valueTemp, offsetTemp, maskTemp, output); } template - void atomicFetchAdd8SignExtend(const S& value, const T& mem, Register temp, Register output) { - MOZ_CRASH("NYI"); + void atomicFetchAdd8SignExtend(const S& value, const T& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp, Register output) + { + atomicFetchOp(1, true, AtomicFetchAddOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp, output); } template - void atomicFetchAdd8ZeroExtend(const S& value, const T& mem, Register temp, Register output) { - MOZ_CRASH("NYI"); + void atomicFetchAdd8ZeroExtend(const S& value, const T& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp, Register output) + { + atomicFetchOp(1, false, AtomicFetchAddOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp, output); } template - void atomicFetchAdd16SignExtend(const S& value, const T& mem, Register temp, Register output) { - MOZ_CRASH("NYI"); + void atomicFetchAdd16SignExtend(const S& value, const T& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp, Register output) + { + atomicFetchOp(2, true, AtomicFetchAddOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp, output); } template - void atomicFetchAdd16ZeroExtend(const S& value, const T& mem, Register temp, Register output) { - MOZ_CRASH("NYI"); + void atomicFetchAdd16ZeroExtend(const S& value, const T& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp, Register output) + { + atomicFetchOp(2, false, AtomicFetchAddOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp, output); } template - void atomicFetchAdd32(const S& value, const T& mem, Register temp, Register output) { - MOZ_CRASH("NYI"); + void atomicFetchAdd32(const S& value, const T& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp, Register output) + { + atomicFetchOp(4, false, AtomicFetchAddOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp, output); } template - void atomicAdd8(const T& value, const S& mem) { - MOZ_CRASH("NYI"); + void atomicAdd8(const T& value, const S& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp) + { + atomicEffectOp(1, AtomicFetchAddOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp); } template - void atomicAdd16(const T& value, const S& mem) { - MOZ_CRASH("NYI"); + void atomicAdd16(const T& value, const S& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp) + { + atomicEffectOp(2, AtomicFetchAddOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp); } template - void atomicAdd32(const T& value, const S& mem) { - MOZ_CRASH("NYI"); + void atomicAdd32(const T& value, const S& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp) + { + atomicEffectOp(4, AtomicFetchAddOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp); } template - void atomicFetchSub8SignExtend(const S& value, const T& mem, Register temp, Register output) { - MOZ_CRASH("NYI"); + void atomicFetchSub8SignExtend(const S& value, const T& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp, Register output) + { + atomicFetchOp(1, true, AtomicFetchSubOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp, output); } template - void atomicFetchSub8ZeroExtend(const S& value, const T& mem, Register temp, Register output) { - MOZ_CRASH("NYI"); + void atomicFetchSub8ZeroExtend(const S& value, const T& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp, Register output) + { + atomicFetchOp(1, false, AtomicFetchSubOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp, output); } template - void atomicFetchSub16SignExtend(const S& value, const T& mem, Register temp, Register output) { - MOZ_CRASH("NYI"); + void atomicFetchSub16SignExtend(const S& value, const T& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp, Register output) + { + atomicFetchOp(2, true, AtomicFetchSubOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp, output); } template - void atomicFetchSub16ZeroExtend(const S& value, const T& mem, Register temp, Register output) { - MOZ_CRASH("NYI"); + void atomicFetchSub16ZeroExtend(const S& value, const T& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp, Register output) + { + atomicFetchOp(2, false, AtomicFetchSubOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp, output); } template - void atomicFetchSub32(const S& value, const T& mem, Register temp, Register output) { - MOZ_CRASH("NYI"); + void atomicFetchSub32(const S& value, const T& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp, Register output) + { + atomicFetchOp(4, false, AtomicFetchSubOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp, output); } - template void atomicSub8(const T& value, const S& mem) { - MOZ_CRASH("NYI"); + template + void atomicSub8(const T& value, const S& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp) + { + atomicEffectOp(1, AtomicFetchSubOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp); } - template void atomicSub16(const T& value, const S& mem) { - MOZ_CRASH("NYI"); + template + void atomicSub16(const T& value, const S& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp) + { + atomicEffectOp(2, AtomicFetchSubOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp); } - template void atomicSub32(const T& value, const S& mem) { - MOZ_CRASH("NYI"); + template + void atomicSub32(const T& value, const S& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp) + { + atomicEffectOp(4, AtomicFetchSubOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp); } template - void atomicFetchAnd8SignExtend(const S& value, const T& mem, Register temp, Register output) { - MOZ_CRASH("NYI"); + void atomicFetchAnd8SignExtend(const S& value, const T& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp, Register output) + { + atomicFetchOp(1, true, AtomicFetchAndOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp, output); } template - void atomicFetchAnd8ZeroExtend(const S& value, const T& mem, Register temp, Register output) { - MOZ_CRASH("NYI"); + void atomicFetchAnd8ZeroExtend(const S& value, const T& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp, Register output) + { + atomicFetchOp(1, false, AtomicFetchAndOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp, output); } template - void atomicFetchAnd16SignExtend(const S& value, const T& mem, Register temp, Register output) { - MOZ_CRASH("NYI"); + void atomicFetchAnd16SignExtend(const S& value, const T& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp, Register output) + { + atomicFetchOp(2, true, AtomicFetchAndOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp, output); } template - void atomicFetchAnd16ZeroExtend(const S& value, const T& mem, Register temp, Register output) { - MOZ_CRASH("NYI"); + void atomicFetchAnd16ZeroExtend(const S& value, const T& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp, Register output) + { + atomicFetchOp(2, false, AtomicFetchAndOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp, output); } template - void atomicFetchAnd32(const S& value, const T& mem, Register temp, Register output) { - MOZ_CRASH("NYI"); + void atomicFetchAnd32(const S& value, const T& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp, Register output) + { + atomicFetchOp(4, false, AtomicFetchAndOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp, output); } template - void atomicAnd8(const T& value, const S& mem) { - MOZ_CRASH("NYI"); + void atomicAnd8(const T& value, const S& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp) + { + atomicEffectOp(1, AtomicFetchAndOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp); } template - void atomicAnd16(const T& value, const S& mem) { - MOZ_CRASH("NYI"); + void atomicAnd16(const T& value, const S& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp) + { + atomicEffectOp(2, AtomicFetchAndOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp); } template - void atomicAnd32(const T& value, const S& mem) { - MOZ_CRASH("NYI"); + void atomicAnd32(const T& value, const S& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp) + { + atomicEffectOp(4, AtomicFetchAndOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp); } template - void atomicFetchOr8SignExtend(const S& value, const T& mem, Register temp, Register output) { - MOZ_CRASH("NYI"); + void atomicFetchOr8SignExtend(const S& value, const T& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp, Register output) + { + atomicFetchOp(1, true, AtomicFetchOrOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp, output); } template - void atomicFetchOr8ZeroExtend(const S& value, const T& mem, Register temp, Register output) { - MOZ_CRASH("NYI"); + void atomicFetchOr8ZeroExtend(const S& value, const T& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp, Register output) + { + atomicFetchOp(1, false, AtomicFetchOrOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp, output); } template - void atomicFetchOr16SignExtend(const S& value, const T& mem, Register temp, Register output) { - MOZ_CRASH("NYI"); + void atomicFetchOr16SignExtend(const S& value, const T& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp, Register output) + { + atomicFetchOp(2, true, AtomicFetchOrOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp, output); } template - void atomicFetchOr16ZeroExtend(const S& value, const T& mem, Register temp, Register output) { - MOZ_CRASH("NYI"); + void atomicFetchOr16ZeroExtend(const S& value, const T& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp, Register output) + { + atomicFetchOp(2, false, AtomicFetchOrOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp, output); } template - void atomicFetchOr32(const S& value, const T& mem, Register temp, Register output) { - MOZ_CRASH("NYI"); + void atomicFetchOr32(const S& value, const T& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp, Register output) + { + atomicFetchOp(4, false, AtomicFetchOrOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp, output); } template - void atomicOr8(const T& value, const S& mem) { - MOZ_CRASH("NYI"); + void atomicOr8(const T& value, const S& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp) + { + atomicEffectOp(1, AtomicFetchOrOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp); } template - void atomicOr16(const T& value, const S& mem) { - MOZ_CRASH("NYI"); + void atomicOr16(const T& value, const S& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp) + { + atomicEffectOp(2, AtomicFetchOrOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp); } template - void atomicOr32(const T& value, const S& mem) { - MOZ_CRASH("NYI"); + void atomicOr32(const T& value, const S& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp) + { + atomicEffectOp(4, AtomicFetchOrOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp); } template - void atomicFetchXor8SignExtend(const S& value, const T& mem, Register temp, Register output) { - MOZ_CRASH("NYI"); + void atomicFetchXor8SignExtend(const S& value, const T& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp, Register output) + { + atomicFetchOp(1, true, AtomicFetchXorOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp, output); } template - void atomicFetchXor8ZeroExtend(const S& value, const T& mem, Register temp, Register output) { - MOZ_CRASH("NYI"); + void atomicFetchXor8ZeroExtend(const S& value, const T& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp, Register output) + { + atomicFetchOp(1, false, AtomicFetchXorOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp, output); } template - void atomicFetchXor16SignExtend(const S& value, const T& mem, Register temp, Register output) { - MOZ_CRASH("NYI"); + void atomicFetchXor16SignExtend(const S& value, const T& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp, Register output) + { + atomicFetchOp(2, true, AtomicFetchXorOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp, output); } template - void atomicFetchXor16ZeroExtend(const S& value, const T& mem, Register temp, Register output) { - MOZ_CRASH("NYI"); + void atomicFetchXor16ZeroExtend(const S& value, const T& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp, Register output) + { + atomicFetchOp(2, false, AtomicFetchXorOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp, output); } template - void atomicFetchXor32(const S& value, const T& mem, Register temp, Register output) { - MOZ_CRASH("NYI"); + void atomicFetchXor32(const S& value, const T& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp, Register output) + { + atomicFetchOp(4, false, AtomicFetchXorOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp, output); } template - void atomicXor8(const T& value, const S& mem) { - MOZ_CRASH("NYI"); + void atomicXor8(const T& value, const S& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp) + { + atomicEffectOp(1, AtomicFetchXorOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp); } template - void atomicXor16(const T& value, const S& mem) { - MOZ_CRASH("NYI"); + void atomicXor16(const T& value, const S& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp) + { + atomicEffectOp(2, AtomicFetchXorOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp); } template - void atomicXor32(const T& value, const S& mem) { - MOZ_CRASH("NYI"); + void atomicXor32(const T& value, const S& mem, Register flagTemp, + Register valueTemp, Register offsetTemp, Register maskTemp) + { + atomicEffectOp(4, AtomicFetchXorOp, value, mem, flagTemp, valueTemp, offsetTemp, maskTemp); } + template + void compareExchangeToTypedIntArray(Scalar::Type arrayType, const T& mem, Register oldval, Register newval, + Register temp, Register valueTemp, Register offsetTemp, Register maskTemp, + AnyRegister output); + + template + void atomicExchangeToTypedIntArray(Scalar::Type arrayType, const T& mem, Register value, + Register temp, Register valueTemp, Register offsetTemp, Register maskTemp, + AnyRegister output); + void add32(Register src, Register dest); void add32(Imm32 imm, Register dest); void add32(Imm32 imm, const Address& dest); diff --git a/js/src/jit/mips64/Trampoline-mips64.cpp b/js/src/jit/mips64/Trampoline-mips64.cpp index 80e56e95b1..b9ff925319 100644 --- a/js/src/jit/mips64/Trampoline-mips64.cpp +++ b/js/src/jit/mips64/Trampoline-mips64.cpp @@ -13,7 +13,7 @@ #include "jit/JitFrames.h" #include "jit/JitSpewer.h" #include "jit/Linker.h" -#include "jit/mips-shared/Bailouts-mips-shared.h" +#include "jit/mips64/Bailouts-mips64.h" #include "jit/mips64/SharedICHelpers-mips64.h" #ifdef JS_ION_PERF # include "jit/PerfSpewer.h" @@ -554,10 +554,8 @@ JitRuntime::generateArgumentsRectifier(JSContext* cx, void** returnAddrOut) AutoFlushICache afc("ArgumentsRectifier"); JitCode* code = linker.newCode(cx, OTHER_CODE); - CodeOffsetLabel returnLabel(returnOffset); - returnLabel.fixup(&masm); if (returnAddrOut) - *returnAddrOut = (void*) (code->raw() + returnLabel.offset()); + *returnAddrOut = (void*) (code->raw() + returnOffset); #ifdef JS_ION_PERF writePerfSpewerJitCodeProfile(code, "ArgumentsRectifier"); @@ -575,20 +573,14 @@ JitRuntime::generateArgumentsRectifier(JSContext* cx, void** returnAddrOut) * (See: JitRuntime::generateBailoutHandler). */ static void -PushBailoutFrame(MacroAssembler& masm, uint32_t frameClass, Register spArg) +PushBailoutFrame(MacroAssembler& masm, Register spArg) { - // Make sure that alignment is proper. - masm.checkStackAlignment(); - - // Push registers such that we can access them from [base + code]. - masm.PushRegsInMask(AllRegs); - - // Push the frameSize_ or tableOffset_ stored in ra + // Push the frameSize_ stored in ra // See: CodeGeneratorMIPS64::generateOutOfLineCode() masm.push(ra); - // Push frame class to stack - masm.push(ImmWord(frameClass)); + // Push registers such that we can access them from [base + code]. + masm.PushRegsInMask(AllRegs); // Put pointer to BailoutStack as first argument to the Bailout() masm.movePtr(StackPointer, spArg); @@ -597,12 +589,11 @@ PushBailoutFrame(MacroAssembler& masm, uint32_t frameClass, Register spArg) static void GenerateBailoutThunk(JSContext* cx, MacroAssembler& masm, uint32_t frameClass) { - PushBailoutFrame(masm, frameClass, a0); + PushBailoutFrame(masm, a0); // Put pointer to BailoutInfo static const uint32_t sizeOfBailoutInfo = sizeof(uintptr_t) * 2; masm.subPtr(Imm32(sizeOfBailoutInfo), StackPointer); - masm.storePtr(ImmPtr(nullptr), Address(StackPointer, 0)); masm.movePtr(StackPointer, a1); masm.setupAlignedABICall(); @@ -613,6 +604,13 @@ GenerateBailoutThunk(JSContext* cx, MacroAssembler& masm, uint32_t frameClass) // Get BailoutInfo pointer masm.loadPtr(Address(StackPointer, 0), a2); + // Stack is: + // [frame] + // snapshotOffset + // frameSize + // [bailoutFrame] + // [bailoutInfo] + // // Remove both the bailout frame and the topmost Ion frame's stack. // Load frameSize from stack masm.loadPtr(Address(StackPointer, @@ -1197,7 +1195,7 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx) { // scratch2 := StackPointer + Descriptor.size*1 + JitFrameLayout::Size(); masm.as_daddu(scratch2, StackPointer, scratch1); - masm.add32(Imm32(JitFrameLayout::Size()), scratch2); + masm.addPtr(Imm32(JitFrameLayout::Size()), scratch2); masm.loadPtr(Address(scratch2, RectifierFrameLayout::offsetOfDescriptor()), scratch3); masm.ma_dsrl(scratch1, scratch3, Imm32(FRAMESIZE_SHIFT)); masm.and32(Imm32((1 << FRAMETYPE_BITS) - 1), scratch3); @@ -1218,7 +1216,7 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx) // scratch3 := RectFrame + Rect-Descriptor.Size + RectifierFrameLayout::Size() masm.as_daddu(scratch3, scratch2, scratch1); - masm.add32(Imm32(RectifierFrameLayout::Size()), scratch3); + masm.addPtr(Imm32(RectifierFrameLayout::Size()), scratch3); masm.storePtr(scratch3, lastProfilingFrame); masm.ret(); diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index c22ba58177..603aae97aa 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -2039,7 +2039,8 @@ GenerateLcovInfo(JSContext* cx, JSCompartment* comp, GenericPrinter& out) // Queue the script in the list of script associated to the // current source. - if (!queue.append(fun.getOrCreateScript(cx))) + JSScript* childScript = fun.getOrCreateScript(cx); + if (!childScript || !queue.append(childScript)) return false; } } while (!queue.empty()); diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index cb194e939c..a2d37a6635 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -4098,17 +4098,11 @@ JSScript::argumentsOptimizationFailed(JSContext* cx, HandleScript script) continue; AbstractFramePtr frame = i.abstractFramePtr(); if (frame.isFunctionFrame() && frame.script() == script) { + /* We crash on OOM since cleaning up here would be complicated. */ + AutoEnterOOMUnsafeRegion oomUnsafe; ArgumentsObject* argsobj = ArgumentsObject::createExpected(cx, frame); - if (!argsobj) { - /* - * We can't leave stack frames with script->needsArgsObj but no - * arguments object. It is, however, safe to leave frames with - * an arguments object but !script->needsArgsObj. - */ - script->needsArgsObj_ = false; - return false; - } - + if (!argsobj) + oomUnsafe.crash("JSScript::argumentsOptimizationFailed"); SetFrameArgumentsObject(cx, frame, script, argsobj); } } diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index ea3337787d..7a1bcd6bcc 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -2382,23 +2382,38 @@ BuildFlatMatchArray(JSContext* cx, HandleString textstr, const FlatMatch& fm, return true; } - /* For this non-global match, produce a RegExp.exec-style array. */ - RootedObject obj(cx, NewDenseEmptyArray(cx)); - if (!obj) + /* Get the templateObject that defines the shape and type of the output object */ + JSObject* templateObject = cx->compartment()->regExps.getOrCreateMatchResultTemplateObject(cx); + if (!templateObject) return false; - RootedValue patternVal(cx, StringValue(fm.pattern())); - RootedValue matchVal(cx, Int32Value(fm.match())); - RootedValue textVal(cx, StringValue(textstr)); - - if (!DefineElement(cx, obj, 0, patternVal) || - !DefineProperty(cx, obj, cx->names().index, matchVal) || - !DefineProperty(cx, obj, cx->names().input, textVal)) - { + RootedArrayObject arr(cx, NewDenseFullyAllocatedArrayWithTemplate(cx, 1, templateObject)); + if (!arr) return false; - } - args->rval().setObject(*obj); + /* Store a Value for each pair. */ + arr->setDenseInitializedLength(1); + arr->initDenseElement(0, StringValue(fm.pattern())); + + /* Set the |index| property. (TemplateObject positions it in slot 0) */ + arr->setSlot(0, Int32Value(fm.match())); + + /* Set the |input| property. (TemplateObject positions it in slot 1) */ + arr->setSlot(1, StringValue(textstr)); + +#ifdef DEBUG + RootedValue test(cx); + RootedId id(cx, NameToId(cx->names().index)); + if (!NativeGetProperty(cx, arr, id, &test)) + return false; + MOZ_ASSERT(test == arr->getSlot(0)); + id = NameToId(cx->names().input); + if (!NativeGetProperty(cx, arr, id, &test)) + return false; + MOZ_ASSERT(test == arr->getSlot(1)); +#endif + + args->rval().setObject(*arr); return true; } diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp index 476356536b..88b8b3143d 100644 --- a/js/src/vm/RegExpObject.cpp +++ b/js/src/vm/RegExpObject.cpp @@ -40,96 +40,24 @@ JS_STATIC_ASSERT(GlobalFlag == JSREG_GLOB); JS_STATIC_ASSERT(MultilineFlag == JSREG_MULTILINE); JS_STATIC_ASSERT(StickyFlag == JSREG_STICKY); -/* RegExpObjectBuilder */ - -RegExpObjectBuilder::RegExpObjectBuilder(ExclusiveContext* cx, RegExpObject* reobj) - : cx(cx), reobj_(cx, reobj) -{} - -bool -RegExpObjectBuilder::getOrCreate() +RegExpObject* +js::RegExpAlloc(ExclusiveContext* cx) { - if (reobj_) - return true; - // Note: RegExp objects are always allocated in the tenured heap. This is // not strictly required, but simplifies embedding them in jitcode. - reobj_ = NewBuiltinClassInstance(cx, TenuredObject); - if (!reobj_) - return false; - reobj_->initPrivate(nullptr); + RegExpObject* regexp = NewBuiltinClassInstance(cx, TenuredObject); + if (!regexp) + return nullptr; - return true; -} - -bool -RegExpObjectBuilder::getOrCreateClone(HandleObjectGroup group) -{ - MOZ_ASSERT(!reobj_); - MOZ_ASSERT(group->clasp() == &RegExpObject::class_); - - // Note: RegExp objects are always allocated in the tenured heap. This is - // not strictly required, but simplifies embedding them in jitcode. - reobj_ = NewObjectWithGroup(cx->asJSContext(), group, TenuredObject); - if (!reobj_) - return false; - reobj_->initPrivate(nullptr); - - return true; + regexp->initPrivate(nullptr); + return regexp; } RegExpObject* -RegExpObjectBuilder::build(HandleAtom source, RegExpShared& shared) +js::InitializeRegExp(ExclusiveContext* cx, Handle regexp, HandleAtom source, + RegExpFlag flags) { - if (!getOrCreate()) - return nullptr; - - if (!reobj_->init(cx, source, shared.getFlags())) - return nullptr; - - reobj_->setShared(shared); - return reobj_; -} - -RegExpObject* -RegExpObjectBuilder::build(HandleAtom source, RegExpFlag flags) -{ - if (!getOrCreate()) - return nullptr; - - return reobj_->init(cx, source, flags) ? reobj_.get() : nullptr; -} - -RegExpObject* -RegExpObjectBuilder::clone(Handle other) -{ - RootedObjectGroup group(cx, other->group()); - if (!getOrCreateClone(group)) - return nullptr; - - /* - * Check that the RegExpShared for the original is okay to use in - * the clone -- if the |RegExpStatics| provides more flags we'll - * need a different |RegExpShared|. - */ - RegExpStatics* res = other->getProto()->global().getRegExpStatics(cx); - if (!res) - return nullptr; - - RegExpFlag origFlags = other->getFlags(); - RegExpFlag staticsFlags = res->getFlags(); - if ((origFlags & staticsFlags) != staticsFlags) { - RegExpFlag newFlags = RegExpFlag(origFlags | staticsFlags); - Rooted source(cx, other->getSource()); - return build(source, newFlags); - } - - RegExpGuard g(cx); - if (!other->getShared(cx->asJSContext(), &g)) - return nullptr; - - Rooted source(cx, other->getSource()); - return build(source, *g); + return regexp->init(cx, source, flags) ? regexp : nullptr; } /* MatchPairs */ @@ -292,8 +220,11 @@ RegExpObject::createNoStatics(ExclusiveContext* cx, HandleAtom source, RegExpFla if (!irregexp::ParsePatternSyntax(*tokenStream, alloc, source)) return nullptr; - RegExpObjectBuilder builder(cx); - return builder.build(source, flags); + Rooted regexp(cx, RegExpAlloc(cx)); + if (!regexp) + return nullptr; + + return InitializeRegExp(cx, regexp, source, flags); } bool @@ -945,11 +876,46 @@ RegExpCompartment::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) JSObject* js::CloneRegExpObject(JSContext* cx, JSObject* obj_) { - RegExpObjectBuilder builder(cx); Rooted regex(cx, &obj_->as()); - JSObject* res = builder.clone(regex); - MOZ_ASSERT_IF(res, res->group() == regex->group()); - return res; + + // Check that the RegExpShared for |regex| is okay to reuse in the clone. + // If the |RegExpStatics| provides additional flags, we'll need a new + // |RegExpShared|. + RegExpStatics* currentStatics = regex->getProto()->global().getRegExpStatics(cx); + if (!currentStatics) + return nullptr; + + Rooted source(cx, regex->getSource()); + + RegExpFlag origFlags = regex->getFlags(); + RegExpFlag staticsFlags = currentStatics->getFlags(); + if ((origFlags & staticsFlags) != staticsFlags) { + Rooted clone(cx, RegExpAlloc(cx)); + if (!clone) + return nullptr; + + return InitializeRegExp(cx, clone, source, RegExpFlag(origFlags | staticsFlags)); + } + + // Otherwise, the clone can use |regexp|'s RegExpShared. + RootedObjectGroup group(cx, regex->group()); + + // Note: RegExp objects are always allocated in the tenured heap. This is + // not strictly required, but it simplifies embedding them in jitcode. + Rooted clone(cx, NewObjectWithGroup(cx, group, TenuredObject)); + if (!clone) + return nullptr; + clone->initPrivate(nullptr); + + RegExpGuard g(cx); + if (!regex->getShared(cx, &g)) + return nullptr; + + if (!InitializeRegExp(cx, clone, source, g->getFlags())) + return nullptr; + + clone->setShared(*g.re()); + return clone; } static bool diff --git a/js/src/vm/RegExpObject.h b/js/src/vm/RegExpObject.h index dab59b0a67..02972e3143 100644 --- a/js/src/vm/RegExpObject.h +++ b/js/src/vm/RegExpObject.h @@ -63,28 +63,19 @@ enum RegExpRunStatus RegExpRunStatus_Success_NotFound }; -class RegExpObjectBuilder -{ - ExclusiveContext* cx; - Rooted reobj_; +extern RegExpObject* +RegExpAlloc(ExclusiveContext* cx); - bool getOrCreate(); - bool getOrCreateClone(HandleObjectGroup group); +extern RegExpObject* +InitializeRegExp(ExclusiveContext* cx, Handle regexp, HandleAtom source, + RegExpFlag flags); - public: - explicit RegExpObjectBuilder(ExclusiveContext* cx, RegExpObject* reobj = nullptr); +// |regexp| is under-typed because this function's used in the JIT. +extern JSObject* +CloneRegExpObject(JSContext* cx, JSObject* regexp); - RegExpObject* reobj() { return reobj_; } - - RegExpObject* build(HandleAtom source, RegExpFlag flags); - RegExpObject* build(HandleAtom source, RegExpShared& shared); - - /* Perform a VM-internal clone. */ - RegExpObject* clone(Handle other); -}; - -JSObject* -CloneRegExpObject(JSContext* cx, JSObject* obj); +extern JSObject* +CreateRegExpPrototype(JSContext* cx, JSProtoKey key); /* * A RegExpShared is the compiled representation of a regexp. A RegExpShared is @@ -457,7 +448,9 @@ class RegExpObject : public NativeObject static void trace(JSTracer* trc, JSObject* obj); private: - friend class RegExpObjectBuilder; + friend RegExpObject* + InitializeRegExp(ExclusiveContext* cx, Handle regexp, HandleAtom source, + RegExpFlag flags); bool init(ExclusiveContext* cx, HandleAtom source, RegExpFlag flags); diff --git a/build/mobile/robocop/AndroidManifest.xml.in b/mobile/android/tests/browser/robocop/AndroidManifest.xml.in similarity index 100% rename from build/mobile/robocop/AndroidManifest.xml.in rename to mobile/android/tests/browser/robocop/AndroidManifest.xml.in diff --git a/build/mobile/robocop/Makefile.in b/mobile/android/tests/browser/robocop/Makefile.in similarity index 100% rename from build/mobile/robocop/Makefile.in rename to mobile/android/tests/browser/robocop/Makefile.in diff --git a/build/mobile/robocop/README b/mobile/android/tests/browser/robocop/README similarity index 100% rename from build/mobile/robocop/README rename to mobile/android/tests/browser/robocop/README diff --git a/build/mobile/robocop/moz.build b/mobile/android/tests/browser/robocop/moz.build similarity index 63% rename from build/mobile/robocop/moz.build rename to mobile/android/tests/browser/robocop/moz.build index b2c5dfa47f..6c108c258f 100644 --- a/build/mobile/robocop/moz.build +++ b/mobile/android/tests/browser/robocop/moz.build @@ -6,17 +6,15 @@ DEFINES['ANDROID_PACKAGE_NAME'] = CONFIG['ANDROID_PACKAGE_NAME'] -base = '/mobile/android/tests/browser/robocop/' - ANDROID_APK_NAME = 'robocop-debug' ANDROID_APK_PACKAGE = 'org.mozilla.roboexample.test' -ANDROID_ASSETS_DIRS += [base + 'assets'] +ANDROID_ASSETS_DIRS += ['assets'] TEST_HARNESS_FILES.testing.mochitest += [ - base + 'robocop.ini', - base + 'robocop_autophone.ini', + 'robocop.ini', + 'robocop_autophone.ini', ] -TEST_HARNESS_FILES.testing.mochitest.tests.robocop += [base + x for x in [ +TEST_HARNESS_FILES.testing.mochitest.tests.robocop += [ '*.html', '*.jpg', '*.mp4', @@ -25,8 +23,7 @@ TEST_HARNESS_FILES.testing.mochitest.tests.robocop += [base + x for x in [ '*.swf', '*.webm', '*.xml', + 'reader_mode_pages/**', # The ** preserves directory structure. 'robocop*.js', 'test*.js', -]] -# The ** below preserves directory structure. -TEST_HARNESS_FILES.testing.mochitest.tests.robocop.reader_mode_pages += [base + 'reader_mode_pages/**'] +] diff --git a/build/mobile/robocop/res/values/strings.xml b/mobile/android/tests/browser/robocop/res/values/strings.xml similarity index 100% rename from build/mobile/robocop/res/values/strings.xml rename to mobile/android/tests/browser/robocop/res/values/strings.xml diff --git a/build/mobile/robocop/robotium-solo-4.3.1.jar b/mobile/android/tests/browser/robocop/robotium-solo-4.3.1.jar similarity index 100% rename from build/mobile/robocop/robotium-solo-4.3.1.jar rename to mobile/android/tests/browser/robocop/robotium-solo-4.3.1.jar diff --git a/python/mach/mach/base.py b/python/mach/mach/base.py index 987b5f7f3c..3556dc6e57 100644 --- a/python/mach/mach/base.py +++ b/python/mach/mach/base.py @@ -44,86 +44,3 @@ class UnrecognizedArgumentError(MachError): self.command = command self.arguments = arguments - - -class MethodHandler(object): - """Describes a Python method that implements a mach command. - - Instances of these are produced by mach when it processes classes - defining mach commands. - """ - __slots__ = ( - # The Python class providing the command. This is the class type not - # an instance of the class. Mach will instantiate a new instance of - # the class if the command is executed. - 'cls', - - # Whether the __init__ method of the class should receive a mach - # context instance. This should only affect the mach driver and how - # it instantiates classes. - 'pass_context', - - # The name of the method providing the command. In other words, this - # is the str name of the attribute on the class type corresponding to - # the name of the function. - 'method', - - # The name of the command. - 'name', - - # String category this command belongs to. - 'category', - - # Description of the purpose of this command. - 'description', - - # Docstring associated with command. - 'docstring', - - # Functions used to 'skip' commands if they don't meet the conditions - # in a given context. - 'conditions', - - # argparse.ArgumentParser instance to use as the basis for command - # arguments. - '_parser', - 'parser', - - # Arguments added to this command's parser. This is a 2-tuple of - # positional and named arguments, respectively. - 'arguments', - - # Argument groups added to this command's parser. - 'argument_group_names', - - # Dict of string to MethodHandler defining sub commands for this - # command. - 'subcommand_handlers', - ) - - def __init__(self, cls, method, name, category=None, description=None, - docstring=None, conditions=None, parser=None, arguments=None, - argument_group_names=None, pass_context=False, - subcommand_handlers=None): - - self.cls = cls - self.method = method - self.name = name - self.category = category - self.description = description - self.docstring = docstring - self.conditions = conditions or [] - self.arguments = arguments or [] - self.argument_group_names = argument_group_names or [] - self.pass_context = pass_context - self.subcommand_handlers = subcommand_handlers or {} - self._parser = parser - - @property - def parser(self): - # creating cli parsers at command dispatch time can potentially be - # expensive, make it possible to lazy load them. - if callable(self._parser): - self._parser = self._parser() - return self._parser - diff --git a/python/mach/mach/commands/commandinfo.py b/python/mach/mach/commands/commandinfo.py index 048834ee91..cce85f859d 100644 --- a/python/mach/mach/commands/commandinfo.py +++ b/python/mach/mach/commands/commandinfo.py @@ -7,6 +7,7 @@ from __future__ import absolute_import, print_function, unicode_literals from mach.decorators import ( CommandProvider, Command, + CommandArgument, ) @@ -15,18 +16,29 @@ class BuiltinCommands(object): def __init__(self, context): self.context = context + @property + def command_keys(self): + # NOTE 'REMOVED' is a function in testing/mochitest/mach_commands.py + return (k for k, v in self.context.commands.command_handlers.items() + if not v.conditions or v.conditions[0].__name__ != 'REMOVED') + @Command('mach-commands', category='misc', description='List all mach commands.') def commands(self): - print("\n".join(self.context.commands.command_handlers.keys())) + print("\n".join(self.command_keys)) @Command('mach-debug-commands', category='misc', description='Show info about available mach commands.') - def debug_commands(self): + @CommandArgument('match', metavar='MATCH', default=None, nargs='?', + help='Only display commands containing given substring.') + def debug_commands(self, match=None): import inspect handlers = self.context.commands.command_handlers - for command in sorted(handlers.keys()): + for command in sorted(self.command_keys): + if match and match not in command: + continue + handler = handlers[command] cls = handler.cls method = getattr(cls, getattr(handler, 'method')) diff --git a/python/mach/mach/decorators.py b/python/mach/mach/decorators.py index c8ea72bce6..733fd42f08 100644 --- a/python/mach/mach/decorators.py +++ b/python/mach/mach/decorators.py @@ -9,15 +9,90 @@ import collections import inspect import types -from .base import ( - MachError, - MethodHandler -) - +from .base import MachError from .config import ConfigProvider from .registrar import Registrar +class _MachCommand(object): + """Container for mach command metadata. + + Mach commands contain lots of attributes. This class exists to capture them + in a sane way so tuples, etc aren't used instead. + """ + __slots__ = ( + # Content from decorator arguments to define the command. + 'name', + 'subcommand', + 'category', + 'description', + 'conditions', + '_parser', + 'arguments', + 'argument_group_names', + + # Describes how dispatch is performed. + + # The Python class providing the command. This is the class type not + # an instance of the class. Mach will instantiate a new instance of + # the class if the command is executed. + 'cls', + + # Whether the __init__ method of the class should receive a mach + # context instance. This should only affect the mach driver and how + # it instantiates classes. + 'pass_context', + + # The name of the method providing the command. In other words, this + # is the str name of the attribute on the class type corresponding to + # the name of the function. + 'method', + + # Dict of string to _MachCommand defining sub-commands for this + # command. + 'subcommand_handlers', + ) + + def __init__(self, name=None, subcommand=None, category=None, + description=None, conditions=None, parser=None): + self.name = name + self.subcommand = subcommand + self.category = category + self.description = description + self.conditions = conditions or [] + self._parser = parser + self.arguments = [] + self.argument_group_names = [] + + self.cls = None + self.pass_context = None + self.method = None + self.subcommand_handlers = {} + + @property + def parser(self): + # Creating CLI parsers at command dispatch time can be expensive. Make + # it possible to lazy load them by using functions. + if callable(self._parser): + self._parser = self._parser() + + return self._parser + + @property + def docstring(self): + return self.cls.__dict__[self.method].__doc__ + + def __ior__(self, other): + if not isinstance(other, _MachCommand): + raise ValueError('can only operate on _MachCommand instances') + + for a in self.__slots__: + if not getattr(self, a): + setattr(self, a, getattr(other, a)) + + return self + + def CommandProvider(cls): """Class decorator to denote that it provides subcommands for Mach. @@ -47,6 +122,8 @@ def CommandProvider(cls): if len(spec.args) == 2: pass_context = True + seen_commands = set() + # We scan __dict__ because we only care about the classes own attributes, # not inherited ones. If we did inherited attributes, we could potentially # define commands multiple times. We also sort keys so commands defined in @@ -57,40 +134,37 @@ def CommandProvider(cls): if not isinstance(value, types.FunctionType): continue - command_name, category, description, conditions, parser = getattr( - value, '_mach_command', (None, None, None, None, None)) - - if command_name is None: + command = getattr(value, '_mach_command', None) + if not command: continue - if conditions is None and Registrar.require_conditions: + # Ignore subcommands for now: we handle them later. + if command.subcommand: + continue + + seen_commands.add(command.name) + + if not command.conditions and Registrar.require_conditions: continue msg = 'Mach command \'%s\' implemented incorrectly. ' + \ 'Conditions argument must take a list ' + \ 'of functions. Found %s instead.' - conditions = conditions or [] - if not isinstance(conditions, collections.Iterable): - msg = msg % (command_name, type(conditions)) + if not isinstance(command.conditions, collections.Iterable): + msg = msg % (command.name, type(command.conditions)) raise MachError(msg) - for c in conditions: + for c in command.conditions: if not hasattr(c, '__call__'): - msg = msg % (command_name, type(c)) + msg = msg % (command.name, type(c)) raise MachError(msg) - arguments = getattr(value, '_mach_command_args', None) + command.cls = cls + command.method = attr + command.pass_context = pass_context - argument_group_names = getattr(value, '_mach_command_arg_group_names', None) - - handler = MethodHandler(cls, attr, command_name, category=category, - description=description, docstring=value.__doc__, - conditions=conditions, parser=parser, - arguments=arguments, argument_group_names=argument_group_names, - pass_context=pass_context) - - Registrar.register_command_handler(handler) + Registrar.register_command_handler(command) # Now do another pass to get sub-commands. We do this in two passes so # we can check the parent command existence without having to hold @@ -101,32 +175,33 @@ def CommandProvider(cls): if not isinstance(value, types.FunctionType): continue - command, subcommand, description = getattr(value, '_mach_subcommand', - (None, None, None)) - + command = getattr(value, '_mach_command', None) if not command: continue - if command not in Registrar.command_handlers: + # It is a regular command. + if not command.subcommand: + continue + + if command.name not in seen_commands: raise MachError('Command referenced by sub-command does not ' - 'exist: %s' % command) + 'exist: %s' % command.name) - arguments = getattr(value, '_mach_command_args', None) - argument_group_names = getattr(value, '_mach_command_arg_group_names', None) + if command.name not in Registrar.command_handlers: + continue - handler = MethodHandler(cls, attr, subcommand, description=description, - docstring=value.__doc__, - arguments=arguments, argument_group_names=argument_group_names, - pass_context=pass_context) - parent = Registrar.command_handlers[command] + command.cls = cls + command.method = attr + command.pass_context = pass_context + parent = Registrar.command_handlers[command.name] - if parent.parser: + if parent._parser: raise MachError('cannot declare sub commands against a command ' 'that has a parser installed: %s' % command) - if subcommand in parent.subcommand_handlers: - raise MachError('sub-command already defined: %s' % subcommand) + if command.subcommand in parent.subcommand_handlers: + raise MachError('sub-command already defined: %s' % command.subcommand) - parent.subcommand_handlers[subcommand] = handler + parent.subcommand_handlers[command.subcommand] = command return cls @@ -152,17 +227,14 @@ class Command(object): def foo(self): pass """ - def __init__(self, name, category=None, description=None, conditions=None, - parser=None): - self._name = name - self._category = category - self._description = description - self._conditions = conditions - self._parser = parser + def __init__(self, name, **kwargs): + self._mach_command = _MachCommand(name=name, **kwargs) def __call__(self, func): - func._mach_command = (self._name, self._category, self._description, - self._conditions, self._parser) + if not hasattr(func, '_mach_command'): + func._mach_command = _MachCommand() + + func._mach_command |= self._mach_command return func @@ -184,13 +256,14 @@ class SubCommand(object): description -- A textual description for this sub command. """ def __init__(self, command, subcommand, description=None): - self._command = command - self._subcommand = subcommand - self._description = description + self._mach_command = _MachCommand(name=command, subcommand=subcommand, + description=description) def __call__(self, func): - func._mach_subcommand = (self._command, self._subcommand, - self._description) + if not hasattr(func, '_mach_command'): + func._mach_command = _MachCommand() + + func._mach_command |= self._mach_command return func @@ -217,11 +290,10 @@ class CommandArgument(object): self._command_args = (args, kwargs) def __call__(self, func): - command_args = getattr(func, '_mach_command_args', []) + if not hasattr(func, '_mach_command'): + func._mach_command = _MachCommand() - command_args.insert(0, self._command_args) - - func._mach_command_args = command_args + func._mach_command.arguments.insert(0, self._command_args) return func @@ -250,11 +322,10 @@ class CommandArgumentGroup(object): self._group_name = group_name def __call__(self, func): - command_arg_group_names = getattr(func, '_mach_command_arg_group_names', []) + if not hasattr(func, '_mach_command'): + func._mach_command = _MachCommand() - command_arg_group_names.insert(0, self._group_name) - - func._mach_command_arg_group_names = command_arg_group_names + func._mach_command.argument_group_names.insert(0, self._group_name) return func diff --git a/python/mozbuild/mozbuild/backend/fastermake.py b/python/mozbuild/mozbuild/backend/fastermake.py index 18528b87be..50f41b7bc0 100644 --- a/python/mozbuild/mozbuild/backend/fastermake.py +++ b/python/mozbuild/mozbuild/backend/fastermake.py @@ -2,7 +2,7 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -from __future__ import absolute_import, unicode_literals +from __future__ import absolute_import, unicode_literals, print_function from mozbuild.backend.common import CommonBackend from mozbuild.frontend.data import ( @@ -16,12 +16,29 @@ from mozbuild.frontend.data import ( Resources, VariablePassthru, ) +from mozbuild.jar import JarManifestParser from mozbuild.makeutil import Makefile +from mozbuild.preprocessor import Preprocessor from mozbuild.util import OrderedDefaultDict from mozpack.manifests import InstallManifest import mozpack.path as mozpath from collections import OrderedDict from itertools import chain +import os +import sys + + +class OverwriteInstallManifest(InstallManifest): + def _add_entry(self, dest, entry): + # Because of bug 1210703, we can't let the default behavior of + # InstallManifest._add_entry, which is to error out. + # To match the current behavior of the recursive make libs tier, we + # keep the last one given, but still warn about it. + if dest in self._dests: + print('Warning: Item already in manifest: %s' % dest, + file=sys.stderr) + + self._dests[dest] = entry class FasterMakeBackend(CommonBackend): @@ -30,17 +47,19 @@ class FasterMakeBackend(CommonBackend): self._seen_directories = set() self._defines = dict() - self._jar_manifests = OrderedDict() self._manifest_entries = OrderedDefaultDict(list) - self._install_manifests = OrderedDefaultDict(InstallManifest) + self._install_manifests = OrderedDefaultDict(OverwriteInstallManifest) - def _add_preprocess(self, obj, path, dest, **kwargs): - target = mozpath.basename(path) - # This matches what PP_TARGETS do in config/rules. - if target.endswith('.in'): - target = target[:-3] + self._dependencies = OrderedDefaultDict(list) + + def _add_preprocess(self, obj, path, dest, target=None, **kwargs): + if target is None: + target = mozpath.basename(path) + # This matches what PP_TARGETS do in config/rules. + if target.endswith('.in'): + target = target[:-3] depfile = mozpath.join( self.environment.topobjdir, 'faster', '.deps', mozpath.join(obj.install_target, dest, target).replace('/', '_')) @@ -66,12 +85,7 @@ class FasterMakeBackend(CommonBackend): elif isinstance(obj, JARManifest) and \ obj.install_target.startswith('dist/bin'): - defines = self._defines.get(obj.objdir, []) - if defines: - defines = list(defines.get_defines()) - self._jar_manifests[obj.path] = (obj.objdir, - obj.install_target, - defines) + self._consume_jar_manifest(obj, defines) elif isinstance(obj, VariablePassthru) and \ obj.install_target.startswith('dist/bin'): @@ -174,6 +188,113 @@ class FasterMakeBackend(CommonBackend): self._seen_directories.add(obj.objdir) return True + def _consume_jar_manifest(self, obj, defines): + # Ideally, this would all be handled somehow in the emitter, but + # this would require all the magic surrounding l10n and addons in + # the recursive make backend to die, which is not going to happen + # any time soon enough. + # Notably missing: + # - DEFINES from config/config.mk + # - L10n support + # - The equivalent of -e when USE_EXTENSION_MANIFEST is set in + # moz.build, but it doesn't matter in dist/bin. + pp = Preprocessor() + pp.context.update(defines) + pp.context.update(self.environment.defines) + pp.context.update( + AB_CD='en-US', + BUILD_FASTER=1, + ) + pp.out = JarManifestParser() + pp.do_include(obj.path) + + for jarinfo in pp.out: + install_target = obj.install_target + # Bug 1150417 added some gross hacks, which we don't try to + # support generically. Fortunately, the hacks don't define more + # than chrome manifest entries, so just assume we don't get + # any installation entries. + if jarinfo.name.startswith('../'): + assert not jarinfo.entries + + base = mozpath.join('chrome', jarinfo.name) + + for e in jarinfo.entries: + if e.is_locale: + src = mozpath.join( + jarinfo.relativesrcdir or mozpath.dirname(obj.path), + 'en-US', + e.source) + elif e.source.startswith('/'): + src = mozpath.join(self.environment.topsrcdir, + e.source[1:]) + else: + src = mozpath.join(mozpath.dirname(obj.path), e.source) + + if '*' in e.source: + if e.preprocess: + raise Exception('%s: Wildcards are not supported with ' + 'preprocessing' % obj.path) + def _prefix(s): + for p in s.split('/'): + if '*' not in p: + yield p + '/' + prefix = ''.join(_prefix(src)) + + self._install_manifests[obj.install_target] \ + .add_pattern_symlink( + prefix, + src[len(prefix):], + mozpath.join(base, e.output)) + continue + + if not os.path.exists(src): + if e.is_locale: + raise Exception( + '%s: Cannot find %s' % (obj.path, e.source)) + if e.source.startswith('/'): + src = mozpath.join(self.environment.topobjdir, + e.source[1:]) + else: + # This actually gets awkward if the jar.mn is not + # in the same directory as the moz.build declaring + # it, but it's how it works in the recursive make, + # not that anything relies on that, but it's simpler. + src = mozpath.join(obj.objdir, e.source) + self._dependencies['install-%s' % obj.install_target] \ + .append(mozpath.relpath( + src, self.environment.topobjdir)) + + if e.preprocess: + kwargs = {} + if src.endswith('.css'): + kwargs['marker'] = '%' + self._add_preprocess( + obj, + src, + mozpath.join(base, mozpath.dirname(e.output)), + mozpath.basename(e.output), + defines=defines, + **kwargs) + else: + self._install_manifests[obj.install_target].add_symlink( + src, + mozpath.join(base, e.output)) + + manifest = mozpath.normpath(mozpath.join(obj.install_target, base)) + manifest += '.manifest' + for m in jarinfo.chrome_manifests: + self._manifest_entries[manifest].append( + m.replace('%', jarinfo.name + '/')) + + # ../ special cased for bug 1150417 again. + if not jarinfo.name.startswith('../'): + manifest = mozpath.normpath(mozpath.join(obj.install_target, + 'chrome.manifest')) + entry = 'manifest %s.manifest' % base + if entry not in self._manifest_entries[manifest]: + self._manifest_entries[manifest].append(entry) + def consume_finished(self): mk = Makefile() # Add the default rule at the very beginning. @@ -185,34 +306,11 @@ class FasterMakeBackend(CommonBackend): for var in ( 'PYTHON', 'ACDEFINES', - 'MOZ_CHROME_FILE_FORMAT', + 'MOZ_BUILD_APP', + 'MOZ_WIDGET_TOOLKIT', ): mk.add_statement('%s = %s' % (var, self.environment.substs[var])) - # Add all necessary information for jar manifest processing - jar_mn_targets = [] - - for path, (objdir, install_target, defines) in \ - self._jar_manifests.iteritems(): - rel_manifest = mozpath.relpath(path, self.environment.topsrcdir) - target = rel_manifest.replace('/', '-') - assert target not in jar_mn_targets - jar_mn_targets.append(target) - target = 'jar-%s' % target - mk.create_rule([target]).add_dependencies([path]) - if objdir != mozpath.join(self.environment.topobjdir, - mozpath.dirname(rel_manifest)): - mk.create_rule([target]).add_dependencies( - ['objdir = %s' % objdir]) - if install_target != 'dist/bin': - mk.create_rule([target]).add_dependencies( - ['install_target = %s' % install_target]) - if defines: - mk.create_rule([target]).add_dependencies( - ['defines = %s' % ' '.join(defines)]) - - mk.add_statement('JAR_MN_TARGETS = %s' % ' '.join(jar_mn_targets)) - # Add information for chrome manifest generation manifest_targets = [] @@ -228,6 +326,11 @@ class FasterMakeBackend(CommonBackend): mk.add_statement('INSTALL_MANIFESTS = %s' % ' '.join(self._install_manifests.keys())) + # Add dependencies we infered: + for target, deps in self._dependencies.iteritems(): + mk.create_rule([target]).add_dependencies( + '$(TOPOBJDIR)/%s' % d for d in deps) + mk.add_statement('include $(TOPSRCDIR)/config/faster/rules.mk') for base, install_manifest in self._install_manifests.iteritems(): diff --git a/python/mozbuild/mozbuild/backend/recursivemake.py b/python/mozbuild/mozbuild/backend/recursivemake.py index 77caa4e525..dd4b6dda1d 100644 --- a/python/mozbuild/mozbuild/backend/recursivemake.py +++ b/python/mozbuild/mozbuild/backend/recursivemake.py @@ -605,19 +605,23 @@ class RecursiveMakeBackend(CommonBackend): backend_file.write('DIST_FILES += %s\n' % f) elif isinstance(obj, AndroidResDirs): + # Order matters. for p in obj.paths: backend_file.write('ANDROID_RES_DIRS += %s\n' % p.full_path) elif isinstance(obj, AndroidAssetsDirs): + # Order matters. for p in obj.paths: backend_file.write('ANDROID_ASSETS_DIRS += %s\n' % p.full_path) elif isinstance(obj, AndroidExtraResDirs): - for p in obj.paths: - backend_file.write('ANDROID_EXTRA_RES_DIRS += %s\n' % p.full_path) + # Order does not matter. + for p in sorted(set(p.full_path for p in obj.paths)): + backend_file.write('ANDROID_EXTRA_RES_DIRS += %s\n' % p) elif isinstance(obj, AndroidExtraPackages): - for p in obj.packages: + # Order does not matter. + for p in sorted(set(obj.packages)): backend_file.write('ANDROID_EXTRA_PACKAGES += %s\n' % p) else: @@ -1256,7 +1260,7 @@ INSTALL_TARGETS += %(prefix)s (target, ' '.join(mozpath.join('generated', f) for f in jar.generated_sources))) if jar.extra_jars: backend_file.write('%s_EXTRA_JARS := %s\n' % - (target, ' '.join(jar.extra_jars))) + (target, ' '.join(sorted(set(jar.extra_jars))))) if jar.javac_flags: backend_file.write('%s_JAVAC_FLAGS := %s\n' % (target, ' '.join(jar.javac_flags))) diff --git a/python/mozbuild/mozbuild/base.py b/python/mozbuild/mozbuild/base.py index 88a3be0d6e..75edeb49de 100644 --- a/python/mozbuild/mozbuild/base.py +++ b/python/mozbuild/mozbuild/base.py @@ -278,9 +278,6 @@ class MozbuildObject(ProcessExecutionMixin): @property def bindir(self): - import mozinfo - if mozinfo.os == "mac": - return os.path.join(self.topobjdir, 'dist', self.substs['MOZ_MACBUNDLE_NAME'], 'Contents', 'Resources') return os.path.join(self.topobjdir, 'dist', 'bin') @property @@ -313,12 +310,25 @@ class MozbuildObject(ProcessExecutionMixin): return False return Clobberer(self.topsrcdir, self.topobjdir).clobber_needed() + def have_winrm(self): + # `winrm -h` should print 'winrm version ...' and exit 1 + try: + p = subprocess.Popen(['winrm.exe', '-h'], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + return p.wait() == 1 and p.stdout.read().startswith('winrm') + except: + return False + def remove_objdir(self): """Remove the entire object directory.""" - # We use mozfile because it is faster than shutil.rmtree(). - # mozfile doesn't like unicode arguments (bug 818783). - rmtree(self.topobjdir.encode('utf-8')) + if sys.platform.startswith('win') and self.have_winrm(): + subprocess.check_call(['winrm', '-rf', self.topobjdir]) + else: + # We use mozfile because it is faster than shutil.rmtree(). + # mozfile doesn't like unicode arguments (bug 818783). + rmtree(self.topobjdir.encode('utf-8')) def get_binary_path(self, what='app', validate_exists=True, where='default'): """Obtain the path to a compiled binary for this build configuration. diff --git a/python/mozbuild/mozbuild/preprocessor.py b/python/mozbuild/mozbuild/preprocessor.py index f1b0da82d5..0561860fdd 100644 --- a/python/mozbuild/mozbuild/preprocessor.py +++ b/python/mozbuild/mozbuild/preprocessor.py @@ -274,7 +274,7 @@ class Preprocessor: self.key = MSG RuntimeError.__init__(self, (self.file, self.line, self.key, context)) - def __init__(self, line_endings='\n', defines=None, marker='#'): + def __init__(self, defines=None, marker='#'): self.context = Context() for k,v in {'FILE': '', 'LINE': 0, @@ -288,7 +288,6 @@ class Preprocessor: # 2: #else found self.ifStates = [] self.checkLineNumbers = False - self.writtenLines = 0 self.filters = [] self.cmds = {} for cmd, level in {'define': 0, @@ -311,7 +310,6 @@ class Preprocessor: self.cmds[cmd] = (level, getattr(self, 'do_' + cmd)) self.out = sys.stdout self.setMarker(marker) - self.LE = line_endings self.varsubst = re.compile('@(?P\w+)@', re.U) self.includes = set() self.silenceMissingDirectiveWarnings = False @@ -325,12 +323,6 @@ class Preprocessor: sys.stderr.write('{0}: WARNING: no useful preprocessor directives found\n'.format(file)) pass - def setLineEndings(self, aLE): - """ - Set the line endings to be used for output. - """ - self.LE = {'cr': '\x0D', 'lf': '\x0A', 'crlf': '\x0D\x0A'}[aLE] - def setMarker(self, aMarker): """ Set the marker to be used for processing directives. @@ -373,7 +365,6 @@ class Preprocessor: rv = Preprocessor() rv.context.update(self.context) rv.setMarker(self.marker) - rv.LE = self.LE rv.out = self.out return rv @@ -411,6 +402,11 @@ class Preprocessor: aLine = f[1](aLine) return aLine + def noteLineInfo(self): + # Record the current line and file. Called once before transitioning + # into or out of an included file and after writing each line. + self.line_info = self.context['FILE'], self.context['LINE'] + def write(self, aLine): """ Internal method for handling output. @@ -418,20 +414,19 @@ class Preprocessor: if not self.out: return + next_line, next_file = self.context['LINE'], self.context['FILE'] if self.checkLineNumbers: - self.writtenLines += 1 - ln = self.context['LINE'] - if self.writtenLines != ln: - self.out.write('//@line {line} "{file}"{le}'.format(line=ln, - file=self.context['FILE'], - le=self.LE)) - self.writtenLines = ln + expected_file, expected_line = self.line_info + expected_line += 1 + if (expected_line != next_line or + expected_file and expected_file != next_file): + self.out.write('//@line {line} "{file}"\n'.format(line=next_line, + file=next_file)) + self.noteLineInfo() + filteredLine = self.applyFilters(aLine) if filteredLine != aLine: self.actionLevel = 2 - # ensure our line ending. Only need to handle \n, as we're reading - # with universal line ending support, at least for files. - filteredLine = re.sub('\n', self.LE, filteredLine) self.out.write(filteredLine) def handleCommandLine(self, args, defaultToStdin = False): @@ -490,9 +485,6 @@ class Preprocessor: def getCommandLineParser(self, unescapeDefines = False): escapedValue = re.compile('".*"$') numberValue = re.compile('\d+$') - def handleE(option, opt, value, parser): - for k,v in os.environ.iteritems(): - self.context[k] = v def handleD(option, opt, value, parser): vals = value.split('=', 1) if len(vals) == 1: @@ -507,8 +499,6 @@ class Preprocessor: del self.context[value] def handleF(option, opt, value, parser): self.do_filter(value) - def handleLE(option, opt, value, parser): - self.setLineEndings(value) def handleMarker(option, opt, value, parser): self.setMarker(value) def handleSilenceDirectiveWarnings(option, opt, value, parse): @@ -516,8 +506,6 @@ class Preprocessor: p = OptionParser() p.add_option('-I', action='append', type="string", default = [], metavar="FILENAME", help='Include file') - p.add_option('-E', action='callback', callback=handleE, - help='Import the environment into the defined variables') p.add_option('-D', action='callback', callback=handleD, type="string", metavar="VAR[=VAL]", help='Define a variable') p.add_option('-U', action='callback', callback=handleU, type="string", @@ -529,9 +517,6 @@ class Preprocessor: 'instead of stdout') p.add_option('--depend', type="string", default=None, metavar="FILENAME", help='Generate dependencies in the given file') - p.add_option('--line-endings', action='callback', callback=handleLE, - type="string", metavar="[cr|lr|crlf]", - help='Use the specified line endings [Default: OS dependent]') p.add_option('--marker', action='callback', callback=handleMarker, type="string", help='Use the specified marker instead of #') @@ -563,7 +548,6 @@ class Preprocessor: self.actionLevel = 2 elif self.disableLevel == 0 and not self.comment.match(aLine): self.write(aLine) - pass # Instruction handlers # These are named do_'instruction name' and take one argument @@ -688,7 +672,7 @@ class Preprocessor: lst.append('\n') # add back the newline self.write(reduce(lambda x, y: x+y, lst, '')) def do_literal(self, args): - self.write(args + self.LE) + self.write(args + '\n') def do_filter(self, args): filters = [f for f in args.split(' ') if hasattr(self, 'filter_' + f)] if len(filters) == 0: @@ -752,7 +736,6 @@ class Preprocessor: Files should be opened, and will be closed after processing. """ isName = type(args) == str or type(args) == unicode - oldWrittenLines = self.writtenLines oldCheckLineNumbers = self.checkLineNumbers self.checkLineNumbers = False if isName: @@ -772,6 +755,8 @@ class Preprocessor: oldFile = self.context['FILE'] oldLine = self.context['LINE'] oldDir = self.context['DIRECTORY'] + self.noteLineInfo() + if args.isatty(): # we're stdin, use '-' and '' for file and dir self.context['FILE'] = '-' @@ -782,15 +767,15 @@ class Preprocessor: self.context['FILE'] = abspath self.context['DIRECTORY'] = os.path.dirname(abspath) self.context['LINE'] = 0 - self.writtenLines = 0 + for l in args: self.context['LINE'] += 1 self.handleLine(l) if isName: args.close() + self.context['FILE'] = oldFile self.checkLineNumbers = oldCheckLineNumbers - self.writtenLines = oldWrittenLines self.context['LINE'] = oldLine self.context['DIRECTORY'] = oldDir def do_includesubst(self, args): @@ -802,13 +787,13 @@ class Preprocessor: def preprocess(includes=[sys.stdin], defines={}, output = sys.stdout, - line_endings='\n', marker='#'): - pp = Preprocessor(line_endings=line_endings, - defines=defines, + marker='#'): + pp = Preprocessor(defines=defines, marker=marker) for f in includes: with open(f, 'rU') as input: pp.processFile(input=input, output=output) + return pp.includes # Keep this module independently executable. diff --git a/python/mozbuild/mozbuild/test/test_preprocessor.py b/python/mozbuild/mozbuild/test/test_preprocessor.py index 92d53c12ca..44b5ddcb1f 100644 --- a/python/mozbuild/mozbuild/test/test_preprocessor.py +++ b/python/mozbuild/mozbuild/test/test_preprocessor.py @@ -440,12 +440,6 @@ class TestPreprocessor(unittest.TestCase): '#endif', ]) - def test_lineEndings(self): - with MockedOpen({'f': 'first\n#literal second\n'}): - self.pp.setLineEndings('cr') - self.pp.do_include('f') - self.assertEqual(self.pp.out.getvalue(), "first\rsecond\r") - def test_filterDefine(self): self.do_include_pass([ '#filter substitution', @@ -562,6 +556,56 @@ class TestPreprocessor(unittest.TestCase): self.pp.do_include('f') self.assertEqual(self.pp.out.getvalue(), 'foobarbaz\nbarfoobaz\n') + def test_include_line(self): + files = { + 'test.js': '\n'.join([ + '#define foo foobarbaz', + '#include @inc@', + '@bar@', + '', + ]), + 'bar.js': '\n'.join([ + '#define bar barfoobaz', + '@foo@', + '', + ]), + 'foo.js': '\n'.join([ + 'bazfoobar', + '#include bar.js', + 'bazbarfoo', + '', + ]), + 'baz.js': 'baz\n', + 'f.js': '\n'.join([ + '#include foo.js', + '#filter substitution', + '#define inc bar.js', + '#include test.js', + '#include baz.js', + 'fin', + '', + ]), + } + + with MockedOpen(files): + self.pp.do_include('f.js') + self.assertEqual(self.pp.out.getvalue(), + ('//@line 1 "CWD/foo.js"\n' + 'bazfoobar\n' + '//@line 2 "CWD/bar.js"\n' + '@foo@\n' + '//@line 3 "CWD/foo.js"\n' + 'bazbarfoo\n' + '//@line 2 "CWD/bar.js"\n' + 'foobarbaz\n' + '//@line 3 "CWD/test.js"\n' + 'barfoobaz\n' + '//@line 1 "CWD/baz.js"\n' + 'baz\n' + '//@line 6 "CWD/f.js"\n' + 'fin\n').replace('CWD/', + os.getcwd() + os.path.sep)) + def test_include_missing_file(self): with MockedOpen({'f': '#include foo\n'}): with self.assertRaises(Preprocessor.Error) as e: diff --git a/python/mozbuild/mozpack/files.py b/python/mozbuild/mozpack/files.py index 6c84e98ee5..508512ed85 100644 --- a/python/mozbuild/mozpack/files.py +++ b/python/mozbuild/mozpack/files.py @@ -817,7 +817,8 @@ class FileFinder(BaseFinder): ''' Helper to get appropriate BaseFile instances from the file system. ''' - def __init__(self, base, find_executables=True, ignore=(), **kargs): + def __init__(self, base, find_executables=True, ignore=(), + find_dotfiles=False, **kargs): ''' Create a FileFinder for files under the given base directory. @@ -832,6 +833,7 @@ class FileFinder(BaseFinder): an entry corresponds to a file, that particular file will be ignored. ''' BaseFinder.__init__(self, base, **kargs) + self.find_dotfiles = find_dotfiles self.find_executables = find_executables self.ignore = ignore @@ -866,7 +868,10 @@ class FileFinder(BaseFinder): # inode ordering. for p in sorted(os.listdir(os.path.join(self.base, path))): if p.startswith('.'): - continue + if p in ('.', '..'): + continue + if not self.find_dotfiles: + continue for p_, f in self._find(mozpath.join(path, p)): yield p_, f diff --git a/python/mozbuild/mozpack/test/test_files.py b/python/mozbuild/mozpack/test/test_files.py index 95cc84a88d..7b13f46a68 100644 --- a/python/mozbuild/mozpack/test/test_files.py +++ b/python/mozbuild/mozpack/test/test_files.py @@ -973,6 +973,21 @@ class TestFileFinder(MatchTestTemplate, TestWithTmpDir): self.do_check('**', ['foo/bar', 'foo/baz', 'foo/quxz', 'bar']) self.do_check('foo/**', ['foo/bar', 'foo/baz', 'foo/quxz']) + def test_dotfiles(self): + """Finder can find files beginning with . is configured.""" + self.prepare_match_test(with_dotfiles=True) + self.finder = FileFinder(self.tmpdir, find_dotfiles=True) + self.do_check('**', ['bar', 'foo/.foo', 'foo/.bar/foo', + 'foo/bar', 'foo/baz', 'foo/qux/1', 'foo/qux/bar', + 'foo/qux/2/test', 'foo/qux/2/test2']) + + def test_dotfiles_plus_ignore(self): + self.prepare_match_test(with_dotfiles=True) + self.finder = FileFinder(self.tmpdir, find_dotfiles=True, + ignore=['foo/.bar/**']) + self.do_check('foo/**', ['foo/.foo', 'foo/bar', 'foo/baz', + 'foo/qux/1', 'foo/qux/bar', 'foo/qux/2/test', 'foo/qux/2/test2']) + class TestJarFinder(MatchTestTemplate, TestWithTmpDir): def add(self, path): diff --git a/testing/config/mozharness/android_arm_4_4_config.py b/testing/config/mozharness/android_arm_4_4_config.py deleted file mode 100644 index 0d2f0b0588..0000000000 --- a/testing/config/mozharness/android_arm_4_4_config.py +++ /dev/null @@ -1,105 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -config = { - "suite_definitions": { - "mochitest": { - "run_filename": "runtestsremote.py", - "testsdir": "mochitest", - "options": ["--autorun", "--close-when-done", "--dm_trans=adb", - "--console-level=INFO", "--app=%(app)s", "--remote-webserver=%(remote_webserver)s", - "--xre-path=%(xre_path)s", "--utility-path=%(utility_path)s", - "--http-port=%(http_port)s", "--ssl-port=%(ssl_port)s", - "--certificate-path=%(certs_path)s", "--symbols-path=%(symbols_path)s", - "--quiet", "--log-raw=%(raw_log_file)s", - "--total-chunks=16", - "--run-only-tests=android23.json", - ], - }, - "mochitest-gl": { - "run_filename": "runtestsremote.py", - "testsdir": "mochitest", - "options": ["--autorun", "--close-when-done", "--dm_trans=adb", - "--console-level=INFO", "--app=%(app)s", "--remote-webserver=%(remote_webserver)s", - "--xre-path=%(xre_path)s", "--utility-path=%(utility_path)s", - "--http-port=%(http_port)s", "--ssl-port=%(ssl_port)s", - "--certificate-path=%(certs_path)s", "--symbols-path=%(symbols_path)s", - "--quiet", "--log-raw=%(raw_log_file)s", - "--total-chunks=2", - "--test-manifest=gl.json", - ], - }, - "robocop": { - "run_filename": "runtestsremote.py", - "testsdir": "mochitest", - "options": ["--autorun", "--close-when-done", "--dm_trans=adb", - "--console-level=INFO", "--app=%(app)s", "--remote-webserver=%(remote_webserver)s", - "--xre-path=%(xre_path)s", "--utility-path=%(utility_path)s", - "--http-port=%(http_port)s", "--ssl-port=%(ssl_port)s", - "--certificate-path=%(certs_path)s", "--symbols-path=%(symbols_path)s", - "--quiet", "--log-raw=%(raw_log_file)s", - "--total-chunks=4", - "--robocop-path=../..", - "--robocop-ids=fennec_ids.txt", - "--robocop=robocop.ini", - ], - }, - "reftest": { - "run_filename": "remotereftest.py", - "testsdir": "reftest", - "options": [ "--app=%(app)s", "--ignore-window-size", - "--dm_trans=adb", - "--bootstrap", - "--remote-webserver=%(remote_webserver)s", "--xre-path=%(xre_path)s", - "--utility-path=%(utility_path)s", "--http-port=%(http_port)s", - "--ssl-port=%(ssl_port)s", "--httpd-path", "%(modules_dir)s", - "--symbols-path=%(symbols_path)s", - "--total-chunks=16", - "tests/layout/reftests/reftest.list", - ], - }, - "crashtest": { - "run_filename": "remotereftest.py", - "testsdir": "reftest", - "options": [ "--app=%(app)s", "--ignore-window-size", - "--dm_trans=adb", - "--bootstrap", - "--remote-webserver=%(remote_webserver)s", "--xre-path=%(xre_path)s", - "--utility-path=%(utility_path)s", "--http-port=%(http_port)s", - "--ssl-port=%(ssl_port)s", "--httpd-path", "%(modules_dir)s", - "--symbols-path=%(symbols_path)s", - "--total-chunks=2", - "tests/testing/crashtest/crashtests.list", - ], - }, - "jsreftest": { - "run_filename": "remotereftest.py", - "testsdir": "reftest", - "options": [ "--app=%(app)s", "--ignore-window-size", - "--dm_trans=adb", - "--bootstrap", - "--remote-webserver=%(remote_webserver)s", "--xre-path=%(xre_path)s", - "--utility-path=%(utility_path)s", "--http-port=%(http_port)s", - "--ssl-port=%(ssl_port)s", "--httpd-path", "%(modules_dir)s", - "--symbols-path=%(symbols_path)s", - "../jsreftest/tests/jstests.list", - "--total-chunks=6", - "--extra-profile-file=jsreftest/tests/user.js", - ], - }, - "xpcshell": { - "run_filename": "remotexpcshelltests.py", - "testsdir": "xpcshell", - "options": [ - "--dm_trans=adb", - "--xre-path=%(xre_path)s", "--testing-modules-dir=%(modules_dir)s", - "--apk=%(installer_path)s", "--no-logfiles", - "--symbols-path=%(symbols_path)s", - "--manifest=tests/xpcshell.ini", - "--log-raw=%(raw_log_file)s", - "--total-chunks=3", - ], - }, - }, # end suite_definitions -} diff --git a/testing/config/mozharness/android_arm_config.py b/testing/config/mozharness/android_arm_config.py deleted file mode 100644 index dc8dbac94e..0000000000 --- a/testing/config/mozharness/android_arm_config.py +++ /dev/null @@ -1,103 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -config = { - "suite_definitions": { - "mochitest": { - "run_filename": "runtestsremote.py", - "testsdir": "mochitest", - "options": ["--dm_trans=sut", "--app=%(app)s", "--remote-webserver=%(remote_webserver)s", - "--xre-path=%(xre_path)s", "--utility-path=%(utility_path)s", - "--deviceIP=%(device_ip)s", "--devicePort=%(device_port)s", - "--http-port=%(http_port)s", "--ssl-port=%(ssl_port)s", - "--certificate-path=%(certs_path)s", "--symbols-path=%(symbols_path)s", - "--quiet", "--log-raw=%(raw_log_file)s", - "--total-chunks=16", - "--run-only-tests=android23.json", - ], - }, - "mochitest-gl": { - "run_filename": "runtestsremote.py", - "testsdir": "mochitest", - "options": ["--dm_trans=sut", "--app=%(app)s", "--remote-webserver=%(remote_webserver)s", - "--xre-path=%(xre_path)s", "--utility-path=%(utility_path)s", - "--deviceIP=%(device_ip)s", "--devicePort=%(device_port)s", - "--http-port=%(http_port)s", "--ssl-port=%(ssl_port)s", - "--certificate-path=%(certs_path)s", "--symbols-path=%(symbols_path)s", - "--quiet", "--log-raw=%(raw_log_file)s", - "--total-chunks=4", "--subsuite=webgl", - ], - }, - "robocop": { - "run_filename": "runtestsremote.py", - "testsdir": "mochitest", - "options": ["--dm_trans=sut", "--app=%(app)s", "--remote-webserver=%(remote_webserver)s", - "--xre-path=%(xre_path)s", "--utility-path=%(utility_path)s", - "--deviceIP=%(device_ip)s", "--devicePort=%(device_port)s", - "--http-port=%(http_port)s", "--ssl-port=%(ssl_port)s", - "--certificate-path=%(certs_path)s", "--symbols-path=%(symbols_path)s", - "--quiet", "--log-raw=%(raw_log_file)s", - "--total-chunks=4", - "--robocop-apk=../../robocop.apk", - "--robocop-ids=fennec_ids.txt", - "--robocop-ini=robocop.ini", - ], - }, - "reftest": { - "run_filename": "remotereftest.py", - "testsdir": "reftest", - "options": [ "--app=%(app)s", "--ignore-window-size", - "--bootstrap", - "--remote-webserver=%(remote_webserver)s", "--xre-path=%(xre_path)s", - "--utility-path=%(utility_path)s", "--deviceIP=%(device_ip)s", - "--devicePort=%(device_port)s", "--http-port=%(http_port)s", - "--ssl-port=%(ssl_port)s", "--httpd-path", "%(modules_dir)s", - "--symbols-path=%(symbols_path)s", - "--total-chunks=16", - "tests/layout/reftests/reftest.list", - ], - }, - "crashtest": { - "run_filename": "remotereftest.py", - "testsdir": "reftest", - "options": [ "--app=%(app)s", "--ignore-window-size", - "--bootstrap", - "--remote-webserver=%(remote_webserver)s", "--xre-path=%(xre_path)s", - "--utility-path=%(utility_path)s", "--deviceIP=%(device_ip)s", - "--devicePort=%(device_port)s", "--http-port=%(http_port)s", - "--ssl-port=%(ssl_port)s", "--httpd-path", "%(modules_dir)s", - "--symbols-path=%(symbols_path)s", - "--total-chunks=2", - "tests/testing/crashtest/crashtests.list", - ], - }, - "jsreftest": { - "run_filename": "remotereftest.py", - "testsdir": "reftest", - "options": [ "--app=%(app)s", "--ignore-window-size", - "--bootstrap", - "--remote-webserver=%(remote_webserver)s", "--xre-path=%(xre_path)s", - "--utility-path=%(utility_path)s", "--deviceIP=%(device_ip)s", - "--devicePort=%(device_port)s", "--http-port=%(http_port)s", - "--ssl-port=%(ssl_port)s", "--httpd-path", "%(modules_dir)s", - "--symbols-path=%(symbols_path)s", - "../jsreftest/tests/jstests.list", - "--total-chunks=6", - "--extra-profile-file=jsreftest/tests/user.js", - ], - }, - "xpcshell": { - "run_filename": "remotexpcshelltests.py", - "testsdir": "xpcshell", - "options": ["--deviceIP=%(device_ip)s", "--devicePort=%(device_port)s", - "--xre-path=%(xre_path)s", "--testing-modules-dir=%(modules_dir)s", - "--apk=%(installer_path)s", "--no-logfiles", - "--symbols-path=%(symbols_path)s", - "--manifest=tests/xpcshell.ini", - "--log-raw=%(raw_log_file)s", - "--total-chunks=3", - ], - }, - }, # end suite_definitions -} diff --git a/testing/config/mozharness/android_panda_config.py b/testing/config/mozharness/android_panda_config.py deleted file mode 100644 index 6065e8d7c8..0000000000 --- a/testing/config/mozharness/android_panda_config.py +++ /dev/null @@ -1,138 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -config = { - "suite_definitions": { - "cppunittest": { - "options": [ - "--symbols-path=%(symbols_path)s", - "--xre-path=tests/bin", - "--dm_trans=sut", - "--deviceIP=%(device_ip)s", - "--localBinDir=../tests/bin", - "--apk=%(apk_path)s", - "--skip-manifest=../tests/cppunittests/android_cppunittest_manifest.txt" - ], - "run_filename": "remotecppunittests.py", - "testsdir": "cppunittest" - }, - "crashtest": { - "options": [ - "--deviceIP=%(device_ip)s", - "--xre-path=../hostutils/xre", - "--utility-path=../hostutils/bin", - "--app=%(app_name)s", - "--ignore-window-size", - "--bootstrap", - "--http-port=%(http_port)s", - "--ssl-port=%(ssl_port)s", - "--symbols-path=%(symbols_path)s", - "reftest/tests/testing/crashtest/crashtests.list" - ], - "run_filename": "remotereftest.py", - "testsdir": "reftest" - }, - "jittest": { - "options": [ - "bin/js", - "--remote", - "-j", - "1", - "--deviceTransport=sut", - "--deviceIP=%(device_ip)s", - "--localLib=../tests/bin", - "--no-slow", - "--no-progress", - "--format=automation", - "--jitflags=all" - ], - "run_filename": "jit_test.py", - "testsdir": "jit-test/jit-test" - }, - "jsreftest": { - "options": [ - "--deviceIP=%(device_ip)s", - "--xre-path=../hostutils/xre", - "--utility-path=../hostutils/bin", - "--app=%(app_name)s", - "--ignore-window-size", - "--bootstrap", - "--extra-profile-file=jsreftest/tests/user.js", - "jsreftest/tests/jstests.list", - "--http-port=%(http_port)s", - "--ssl-port=%(ssl_port)s", - "--symbols-path=%(symbols_path)s" - ], - "run_filename": "remotereftest.py", - "testsdir": "reftest" - }, - "mochitest": { - "options": [ - "--dm_trans=sut", - "--deviceIP=%(device_ip)s", - "--xre-path=../hostutils/xre", - "--utility-path=../hostutils/bin", - "--certificate-path=certs", - "--app=%(app_name)s", - "--http-port=%(http_port)s", - "--ssl-port=%(ssl_port)s", - "--run-only-tests=android.json", - "--symbols-path=%(symbols_path)s", - "--quiet", - "--log-raw=%(raw_log_file)s" - ], - "run_filename": "runtestsremote.py", - "testsdir": "mochitest" - }, - "reftest": { - "options": [ - "--deviceIP=%(device_ip)s", - "--xre-path=../hostutils/xre", - "--utility-path=../hostutils/bin", - "--app=%(app_name)s", - "--ignore-window-size", - "--bootstrap", - "--http-port=%(http_port)s", - "--ssl-port=%(ssl_port)s", - "--symbols-path=%(symbols_path)s", - "reftest/tests/layout/reftests/reftest.list" - ], - "run_filename": "remotereftest.py", - "testsdir": "reftest" - }, - "robocop": { - "options": [ - "--dm_trans=sut", - "--deviceIP=%(device_ip)s", - "--xre-path=../hostutils/xre", - "--utility-path=../hostutils/bin", - "--certificate-path=certs", - "--app=%(app_name)s", - "--console-level=INFO", - "--http-port=%(http_port)s", - "--ssl-port=%(ssl_port)s", - "--symbols-path=%(symbols_path)s", - "--robocop-ini=mochitest/robocop.ini" - ], - "run_filename": "runtestsremote.py", - "testsdir": "mochitest" - }, - "xpcshell": { - "options": [ - "--deviceIP=%(device_ip)s", - "--xre-path=../hostutils/xre", - "--manifest=xpcshell/tests/xpcshell.ini", - "--build-info-json=xpcshell/mozinfo.json", - "--testing-modules-dir=modules", - "--local-lib-dir=../fennec", - "--apk=../%(apk_name)s", - "--no-logfiles", - "--symbols-path=%(symbols_path)s", - "--log-raw=%(raw_log_file)s" - ], - "run_filename": "remotexpcshelltests.py", - "testsdir": "xpcshell" - } - } -} diff --git a/testing/config/mozharness/android_x86_config.py b/testing/config/mozharness/android_x86_config.py deleted file mode 100644 index 4097e96124..0000000000 --- a/testing/config/mozharness/android_x86_config.py +++ /dev/null @@ -1,39 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -config = { - "suite_definitions": { - "mochitest": { - "run_filename": "runtestsremote.py", - "options": ["--dm_trans=sut", "--app=%(app)s", "--remote-webserver=%(remote_webserver)s", - "--xre-path=%(xre_path)s", "--utility-path=%(utility_path)s", - "--deviceIP=%(device_ip)s", "--devicePort=%(device_port)s", - "--http-port=%(http_port)s", "--ssl-port=%(ssl_port)s", - "--certificate-path=%(certs_path)s", "--symbols-path=%(symbols_path)s", - "--quiet", "--log-raw=%(raw_log_file)s", - ], - }, - "reftest": { - "run_filename": "remotereftest.py", - "options": [ "--app=%(app)s", "--ignore-window-size", - "--bootstrap", - "--remote-webserver=%(remote_webserver)s", "--xre-path=%(xre_path)s", - "--utility-path=%(utility_path)s", "--deviceIP=%(device_ip)s", - "--devicePort=%(device_port)s", "--http-port=%(http_port)s", - "--ssl-port=%(ssl_port)s", "--httpd-path", "%(modules_dir)s", - "--symbols-path=%(symbols_path)s", - ], - }, - "xpcshell": { - "run_filename": "remotexpcshelltests.py", - "options": ["--deviceIP=%(device_ip)s", "--devicePort=%(device_port)s", - "--xre-path=%(xre_path)s", "--testing-modules-dir=%(modules_dir)s", - "--apk=%(installer_path)s", "--no-logfiles", - "--symbols-path=%(symbols_path)s", - "--manifest=tests/xpcshell.ini", - "--log-raw=%(raw_log_file)s", - ], - }, - }, # end suite_definitions -} diff --git a/testing/config/mozharness/b2g_desktop_config.py b/testing/config/mozharness/b2g_desktop_config.py deleted file mode 100644 index f613720850..0000000000 --- a/testing/config/mozharness/b2g_desktop_config.py +++ /dev/null @@ -1,40 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -config = { - "suite_definitions": { - "mochitest": { - "options": [ - "%(test_manifest)s", - "--total-chunks=%(total_chunks)s", - "--this-chunk=%(this_chunk)s", - "--profile=%(gaia_profile)s", - "--app=%(application)s", - "--desktop", - "--utility-path=%(utility_path)s", - "--certificate-path=%(cert_path)s", - "--symbols-path=%(symbols_path)s", - "--browser-arg=%(browser_arg)s", - "--quiet", - "--log-raw=%(raw_log_file)s" - ], - "run_filename": "runtestsb2g.py", - "testsdir": "mochitest" - }, - "reftest": { - "options": [ - "--desktop", - "--profile=%(gaia_profile)s", - "--appname=%(application)s", - "--total-chunks=%(total_chunks)s", - "--this-chunk=%(this_chunk)s", - "--browser-arg=%(browser_arg)s", - "--symbols-path=%(symbols_path)s", - "%(test_manifest)s" - ], - "run_filename": "runreftestsb2g.py", - "testsdir": "reftest" - } - } -} diff --git a/testing/config/mozharness/b2g_emulator_config.py b/testing/config/mozharness/b2g_emulator_config.py deleted file mode 100644 index 03630bf128..0000000000 --- a/testing/config/mozharness/b2g_emulator_config.py +++ /dev/null @@ -1,141 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -config = { - "suite_definitions": { - "cppunittest": { - "options": [ - "--dm_trans=adb", - "--symbols-path=%(symbols_path)s", - "--xre-path=%(xre_path)s", - "--addEnv", - "LD_LIBRARY_PATH=/vendor/lib:/system/lib:/system/b2g", - "--with-b2g-emulator=%(b2gpath)s", - "--skip-manifest=b2g_cppunittest_manifest.txt", - "." - ], - "run_filename": "remotecppunittests.py", - "testsdir": "cppunittest" - }, - "crashtest": { - "options": [ - "--adbpath=%(adbpath)s", - "--b2gpath=%(b2gpath)s", - "--emulator=%(emulator)s", - "--emulator-res=800x1000", - "--logdir=%(logcat_dir)s", - "--remote-webserver=%(remote_webserver)s", - "--ignore-window-size", - "--xre-path=%(xre_path)s", - "--symbols-path=%(symbols_path)s", - "--busybox=%(busybox)s", - "--total-chunks=%(total_chunks)s", - "--this-chunk=%(this_chunk)s", - "tests/testing/crashtest/crashtests.list" - ], - "run_filename": "runreftestb2g.py", - "testsdir": "reftest" - }, - "jsreftest": { - "options": [ - "--adbpath=%(adbpath)s", - "--b2gpath=%(b2gpath)s", - "--emulator=%(emulator)s", - "--emulator-res=800x1000", - "--logdir=%(logcat_dir)s", - "--remote-webserver=%(remote_webserver)s", - "--ignore-window-size", - "--xre-path=%(xre_path)s", - "--symbols-path=%(symbols_path)s", - "--busybox=%(busybox)s", - "--total-chunks=%(total_chunks)s", - "--this-chunk=%(this_chunk)s", - "--extra-profile-file=jsreftest/tests/user.js", - "jsreftest/tests/jstests.list" - ], - "run_filename": "remotereftest.py", - "testsdir": "reftest" - }, - "mochitest": { - "options": [ - "--adbpath=%(adbpath)s", - "--b2gpath=%(b2gpath)s", - "--emulator=%(emulator)s", - "--logdir=%(logcat_dir)s", - "--remote-webserver=%(remote_webserver)s", - "%(test_manifest)s", - "--xre-path=%(xre_path)s", - "--symbols-path=%(symbols_path)s", - "--busybox=%(busybox)s", - "--total-chunks=%(total_chunks)s", - "--this-chunk=%(this_chunk)s", - "--quiet", - "--log-raw=%(raw_log_file)s", - "--certificate-path=%(certificate_path)s", - "%(test_path)s" - ], - "run_filename": "runtestsb2g.py", - "testsdir": "mochitest" - }, - "mochitest-chrome": { - "options": [ - "--adbpath=%(adbpath)s", - "--b2gpath=%(b2gpath)s", - "--emulator=%(emulator)s", - "--logdir=%(logcat_dir)s", - "--remote-webserver=%(remote_webserver)s", - "--xre-path=%(xre_path)s", - "--symbols-path=%(symbols_path)s", - "--busybox=%(busybox)s", - "--total-chunks=%(total_chunks)s", - "--this-chunk=%(this_chunk)s", - "--quiet", - "--chrome", - "--log-raw=%(raw_log_file)s", - "--certificate-path=%(certificate_path)s", - "%(test_path)s" - ], - "run_filename": "runtestsb2g.py", - "testsdir": "mochitest" - }, - "reftest": { - "options": [ - "--adbpath=%(adbpath)s", - "--b2gpath=%(b2gpath)s", - "--emulator=%(emulator)s", - "--emulator-res=800x1000", - "--logdir=%(logcat_dir)s", - "--remote-webserver=%(remote_webserver)s", - "--ignore-window-size", - "--xre-path=%(xre_path)s", - "--symbols-path=%(symbols_path)s", - "--busybox=%(busybox)s", - "--total-chunks=%(total_chunks)s", - "--this-chunk=%(this_chunk)s", - "--enable-oop", - "tests/layout/reftests/reftest.list" - ], - "run_filename": "runreftestsb2g.py", - "testsdir": "reftest" - }, - "xpcshell": { - "options": [ - "--adbpath=%(adbpath)s", - "--b2gpath=%(b2gpath)s", - "--emulator=%(emulator)s", - "--logdir=%(logcat_dir)s", - "--manifest=tests/xpcshell.ini", - "--use-device-libs", - "--testing-modules-dir=%(modules_dir)s", - "--symbols-path=%(symbols_path)s", - "--busybox=%(busybox)s", - "--total-chunks=%(total_chunks)s", - "--this-chunk=%(this_chunk)s", - "--log-raw=%(raw_log_file)s" - ], - "run_filename": "runtestsb2g.py", - "testsdir": "xpcshell" - } - } -} \ No newline at end of file diff --git a/testing/config/mozharness/linux_config.py b/testing/config/mozharness/linux_config.py index 5c8d412e82..8613c70fa5 100644 --- a/testing/config/mozharness/linux_config.py +++ b/testing/config/mozharness/linux_config.py @@ -2,6 +2,10 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +# XXX Bug 1181261 - Please update config in testing/mozharness/config +# instead. This file is still needed for mulet mochitests, but should +# be removed once bug 1188330 is finished. + config = { "suite_definitions": { "cppunittest": { diff --git a/testing/config/mozharness/linux_mulet_config.py b/testing/config/mozharness/linux_mulet_config.py index 94dd4950a3..1bc5b0fb33 100644 --- a/testing/config/mozharness/linux_mulet_config.py +++ b/testing/config/mozharness/linux_mulet_config.py @@ -1,4 +1,9 @@ # This is used by mozharness' mulet_unittest.py + +# XXX Bug 1181261 - Please update config in testing/mozharness/config +# instead. This file is still needed for mulet reftests, but should +# be removed once bug 1188330 is finished. + config = { # testsuite options "reftest_options": [ diff --git a/testing/config/mozharness/mac_config.py b/testing/config/mozharness/mac_config.py deleted file mode 100644 index 59f3f449f0..0000000000 --- a/testing/config/mozharness/mac_config.py +++ /dev/null @@ -1,91 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -config = { - "suite_definitions": { - "cppunittest": { - "options": [ - "--symbols-path=%(symbols_path)s", - "--xre-path=%(abs_app_dir)s" - ], - "run_filename": "runcppunittests.py", - "testsdir": "cppunittest" - }, - "jittest": { - "options": [ - "tests/bin/js", - "--no-slow", - "--no-progress", - "--format=automation", - "--jitflags=all" - ], - "run_filename": "jit_test.py", - "testsdir": "jit-test/jit-test" - }, - "mochitest": { - "options": [ - "--appname=%(binary_path)s", - "--utility-path=tests/bin", - "--extra-profile-file=tests/bin/plugins", - "--symbols-path=%(symbols_path)s", - "--certificate-path=tests/certs", - "--quiet", - "--log-raw=%(raw_log_file)s" - ], - "run_filename": "runtests.py", - "testsdir": "mochitest" - }, - "mozbase": { - "options": [ - "-b", - "%(binary_path)s" - ], - "run_filename": "test.py", - "testsdir": "mozbase" - }, - "mozmill": { - "options": [ - "--binary=%(binary_path)s", - "--symbols-path=%(symbols_path)s" - ], - "run_filename": "runtestlist.py", - "testsdir": "mozmill" - }, - "reftest": { - "options": [ - "--appname=%(binary_path)s", - "--utility-path=tests/bin", - "--extra-profile-file=tests/bin/plugins", - "--symbols-path=%(symbols_path)s" - ], - "run_filename": "runreftest.py", - "testsdir": "reftest" - }, - "webapprt": { - "options": [ - "--app=%(app_path)s", - "--utility-path=tests/bin", - "--extra-profile-file=tests/bin/plugins", - "--symbols-path=%(symbols_path)s", - "--certificate-path=tests/certs", - "--autorun", - "--close-when-done", - "--console-level=INFO", - "--testing-modules-dir=tests/modules", - "--quiet" - ], - "run_filename": "runtests.py", - "testsdir": "mochitest" - }, - "xpcshell": { - "options": [ - "--symbols-path=%(symbols_path)s", - "--test-plugin-path=%(test_plugin_path)s", - "--log-raw=%(raw_log_file)s" - ], - "run_filename": "runxpcshelltests.py", - "testsdir": "xpcshell" - } - } -} diff --git a/testing/config/mozharness/marionette.py b/testing/config/mozharness/marionette.py deleted file mode 100644 index bb08bbf259..0000000000 --- a/testing/config/mozharness/marionette.py +++ /dev/null @@ -1,86 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -config = { - "suite_definitions": { - "gaiatest_desktop": { - "options": [ - "--restart", - "--timeout=%(timeout)s", - "--type=%(type)s", - "--testvars=%(testvars)s", - "--profile=%(profile)s", - "--symbols-path=%(symbols_path)s", - "--gecko-log=%(gecko_log)s", - "--xml-output=%(xml_output)s", - "--html-output=%(html_output)s", - "--log-raw=%(raw_log_file)s", - "--binary=%(binary)s", - "--address=%(address)s", - "--total-chunks=%(total_chunks)s", - "--this-chunk=%(this_chunk)s" - ], - "run_filename": "", - "testsdir": "" - }, - "gaiatest_emulator": { - "options": [ - "--restart", - "--timeout=%(timeout)s", - "--type=%(type)s", - "--testvars=%(testvars)s", - "--profile=%(profile)s", - "--symbols-path=%(symbols_path)s", - "--xml-output=%(xml_output)s", - "--html-output=%(html_output)s", - "--log-raw=%(raw_log_file)s", - "--logcat-dir=%(logcat_dir)s", - "--emulator=%(emulator)s", - "--homedir=%(homedir)s" - ], - "run_filename": "", - "testsdir": "" - }, - "marionette_desktop": { - "options": [ - "--type=%(type)s", - "--log-raw=%(raw_log_file)s", - "--binary=%(binary)s", - "--address=%(address)s", - "--symbols-path=%(symbols_path)s" - ], - "run_filename": "", - "testsdir": "" - }, - "marionette_emulator": { - "options": [ - "--type=%(type)s", - "--log-raw=%(raw_log_file)s", - "--logcat-dir=%(logcat_dir)s", - "--emulator=%(emulator)s", - "--homedir=%(homedir)s", - "--symbols-path=%(symbols_path)s" - ], - "run_filename": "", - "testsdir": "" - }, - "webapi_desktop": { - "options": [], - "run_filename": "", - "testsdir": "" - }, - "webapi_emulator": { - "options": [ - "--type=%(type)s", - "--log-raw=%(raw_log_file)s", - "--symbols-path=%(symbols_path)s", - "--logcat-dir=%(logcat_dir)s", - "--emulator=%(emulator)s", - "--homedir=%(homedir)s" - ], - "run_filename": "", - "testsdir": "" - } - } -} diff --git a/testing/config/mozharness/taskcluster_linux_config.py b/testing/config/mozharness/taskcluster_linux_config.py deleted file mode 100644 index d46a176b21..0000000000 --- a/testing/config/mozharness/taskcluster_linux_config.py +++ /dev/null @@ -1,41 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -config = { - "reftest_options": [ - "--appname=%(binary_path)s", "--utility-path=tests/bin", - "--extra-profile-file=tests/bin/plugins", "--symbols-path=%(symbols_path)s" - ], - "mochitest_options": [ - "--appname=%(binary_path)s", "--utility-path=tests/bin", - "--extra-profile-file=tests/bin/plugins", "--symbols-path=%(symbols_path)s", - "--certificate-path=tests/certs", "--setpref=webgl.force-enabled=true", - "--quiet", "--log-raw=%(raw_log_file)s" - ], - "webapprt_options": [ - "--app=%(app_path)s", "--utility-path=tests/bin", - "--extra-profile-file=tests/bin/plugins", "--symbols-path=%(symbols_path)s", - "--certificate-path=tests/certs", "--autorun", "--close-when-done", - "--console-level=INFO", "--testing-modules-dir=tests/modules", - "--quiet" - ], - "xpcshell_options": [ - "--symbols-path=%(symbols_path)s", - "--test-plugin-path=%(test_plugin_path)s" - ], - "cppunittest_options": [ - "--symbols-path=%(symbols_path)s", - "--xre-path=%(abs_app_dir)s" - ], - "jittest_options": [ - "tests/bin/js", - "--no-slow", - "--no-progress", - "--format=automation", - "--jitflags=all" - ], - "mozbase_options": [ - "-b", "%(binary_path)s" - ], -} diff --git a/testing/config/mozharness/try_arguments.py b/testing/config/mozharness/try_arguments.py deleted file mode 100644 index 7adbcb8276..0000000000 --- a/testing/config/mozharness/try_arguments.py +++ /dev/null @@ -1,15 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -# Because this list exposes new surface to our interface to try, and could -# easily produce unexpected results if misused, this should only include -# arguments likely to work with multiple harnesses, and will have unintended -# effects if conflicts with TryParser are introduced. -config = { - '--tag': { - 'action': 'append', - 'dest': 'tags', - 'default': None, - }, -} diff --git a/testing/config/mozharness/web_platform_tests_config.py b/testing/config/mozharness/web_platform_tests_config.py deleted file mode 100644 index cd0b455ff2..0000000000 --- a/testing/config/mozharness/web_platform_tests_config.py +++ /dev/null @@ -1,15 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -config = { - "options": [ - "--prefs-root=%(test_path)s/prefs", - "--processes=1", - "--config=%(test_path)s/wptrunner.ini", - "--ca-cert-path=%(test_path)s/certs/cacert.pem", - "--host-key-path=%(test_path)s/certs/web-platform.test.key", - "--host-cert-path=%(test_path)s/certs/web-platform.test.pem", - "--certutil-binary=%(test_install_path)s/bin/certutil", - ], -} diff --git a/testing/config/mozharness/windows_config.py b/testing/config/mozharness/windows_config.py deleted file mode 100644 index 59f3f449f0..0000000000 --- a/testing/config/mozharness/windows_config.py +++ /dev/null @@ -1,91 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -config = { - "suite_definitions": { - "cppunittest": { - "options": [ - "--symbols-path=%(symbols_path)s", - "--xre-path=%(abs_app_dir)s" - ], - "run_filename": "runcppunittests.py", - "testsdir": "cppunittest" - }, - "jittest": { - "options": [ - "tests/bin/js", - "--no-slow", - "--no-progress", - "--format=automation", - "--jitflags=all" - ], - "run_filename": "jit_test.py", - "testsdir": "jit-test/jit-test" - }, - "mochitest": { - "options": [ - "--appname=%(binary_path)s", - "--utility-path=tests/bin", - "--extra-profile-file=tests/bin/plugins", - "--symbols-path=%(symbols_path)s", - "--certificate-path=tests/certs", - "--quiet", - "--log-raw=%(raw_log_file)s" - ], - "run_filename": "runtests.py", - "testsdir": "mochitest" - }, - "mozbase": { - "options": [ - "-b", - "%(binary_path)s" - ], - "run_filename": "test.py", - "testsdir": "mozbase" - }, - "mozmill": { - "options": [ - "--binary=%(binary_path)s", - "--symbols-path=%(symbols_path)s" - ], - "run_filename": "runtestlist.py", - "testsdir": "mozmill" - }, - "reftest": { - "options": [ - "--appname=%(binary_path)s", - "--utility-path=tests/bin", - "--extra-profile-file=tests/bin/plugins", - "--symbols-path=%(symbols_path)s" - ], - "run_filename": "runreftest.py", - "testsdir": "reftest" - }, - "webapprt": { - "options": [ - "--app=%(app_path)s", - "--utility-path=tests/bin", - "--extra-profile-file=tests/bin/plugins", - "--symbols-path=%(symbols_path)s", - "--certificate-path=tests/certs", - "--autorun", - "--close-when-done", - "--console-level=INFO", - "--testing-modules-dir=tests/modules", - "--quiet" - ], - "run_filename": "runtests.py", - "testsdir": "mochitest" - }, - "xpcshell": { - "options": [ - "--symbols-path=%(symbols_path)s", - "--test-plugin-path=%(test_plugin_path)s", - "--log-raw=%(raw_log_file)s" - ], - "run_filename": "runxpcshelltests.py", - "testsdir": "xpcshell" - } - } -} diff --git a/testing/mach_commands.py b/testing/mach_commands.py index 42c12ab4bb..b62c7579d9 100644 --- a/testing/mach_commands.py +++ b/testing/mach_commands.py @@ -4,8 +4,10 @@ from __future__ import absolute_import, print_function, unicode_literals +import json import os import sys +import tempfile from mach.decorators import ( CommandArgument, @@ -14,6 +16,8 @@ from mach.decorators import ( ) from mozbuild.base import MachCommandBase +from mozbuild.base import MachCommandConditions as conditions +from argparse import ArgumentParser UNKNOWN_TEST = ''' @@ -291,29 +295,76 @@ class MachCommands(MachCommandBase): def run_cppunit_test(self, **params): import mozinfo from mozlog import commandline - import runcppunittests as cppunittests - log = commandline.setup_logging("cppunittest", {}, {"tbpl": sys.stdout}) - if len(params['test_files']) == 0: - testdir = os.path.join(self.distdir, 'cppunittests') - tests = cppunittests.extract_unittests_from_args([testdir], mozinfo.info) - else: - tests = cppunittests.extract_unittests_from_args(params['test_files'], mozinfo.info) - # See if we have crash symbols symbols_path = os.path.join(self.distdir, 'crashreporter-symbols') if not os.path.isdir(symbols_path): symbols_path = None - tester = cppunittests.CPPUnitTests() + # If no tests specified, run all tests in main manifest + tests = params['test_files'] + if len(tests) == 0: + tests = [os.path.join(self.distdir, 'cppunittests')] + manifest_path = os.path.join(self.topsrcdir, 'testing', 'cppunittest.ini') + else: + manifest_path = None + + if conditions.is_android(self): + from mozrunner.devices.android_device import verify_android_device + verify_android_device(self, install=False) + return self.run_android_test(tests, symbols_path, manifest_path, log) + + return self.run_desktop_test(tests, symbols_path, manifest_path, log) + + def run_desktop_test(self, tests, symbols_path, manifest_path, log): + import runcppunittests as cppunittests + from mozlog import commandline + + parser = cppunittests.CPPUnittestOptions() + commandline.add_logging_group(parser) + options, args = parser.parse_args() + + options.symbols_path = symbols_path + options.manifest_path = manifest_path + options.xre_path = self.bindir + try: - result = tester.run_tests(tests, self.bindir, symbols_path, interactive=True) + result = cppunittests.run_test_harness(options, tests) except Exception as e: log.error("Caught exception running cpp unit tests: %s" % str(e)) result = False + raise + + return 0 if result else 1 + + def run_android_test(self, tests, symbols_path, manifest_path, log): + import remotecppunittests as remotecppunittests + from mozlog import commandline + + parser = remotecppunittests.RemoteCPPUnittestOptions() + commandline.add_logging_group(parser) + options, args = parser.parse_args() + + options.symbols_path = symbols_path + options.manifest_path = manifest_path + options.xre_path = self.bindir + options.dm_trans = "adb" + options.local_lib = self.bindir.replace('bin', 'fennec') + for file in os.listdir(os.path.join(self.topobjdir, "dist")): + if file.endswith(".apk") and file.startswith("fennec"): + options.local_apk = os.path.join(self.topobjdir, "dist", file) + log.info("using APK: " + options.local_apk) + break + + try: + result = remotecppunittests.run_test_harness(options, tests) + except Exception as e: + log.error("Caught exception running cpp unit tests: %s" % str(e)) + result = False + raise return 0 if result else 1 @@ -499,3 +550,90 @@ class PushToTry(MachCommandBase): at.push_to_try(msg, verbose) return + + +def get_parser(argv=None): + parser = ArgumentParser() + parser.add_argument(dest="suite_name", + nargs=1, + choices=['mochitest'], + type=str, + help="The test for which chunk should be found. It corresponds " + "to the mach test invoked (only 'mochitest' currently).") + + parser.add_argument(dest="test_path", + nargs=1, + type=str, + help="The test (any mochitest) for which chunk should be found.") + + parser.add_argument('--total-chunks', + type=int, + dest='total_chunks', + required=True, + help='Total number of chunks to split tests into.', + default=None + ) + + parser.add_argument('-f', "--flavor", + dest="flavor", + type=str, + help="Flavor to which the test belongs to.") + + parser.add_argument('--chunk-by-runtime', + action='store_true', + dest='chunk_by_runtime', + help='Group tests such that each chunk has roughly the same runtime.', + default=False, + ) + + parser.add_argument('--chunk-by-dir', + type=int, + dest='chunk_by_dir', + help='Group tests together in the same chunk that are in the same top ' + 'chunkByDir directories.', + default=None, + ) + + return parser + + +@CommandProvider +class ChunkFinder(MachCommandBase): + @Command('find-test-chunk', category='testing', + description='Find which chunk a test belongs to (works for mochitest).', + parser=get_parser) + def chunk_finder(self, **kwargs): + flavor = kwargs['flavor'] + total_chunks = kwargs['total_chunks'] + test_path = kwargs['test_path'][0] + suite_name = kwargs['suite_name'][0] + _, dump_tests = tempfile.mkstemp() + args = { + 'totalChunks': total_chunks, + 'dump_tests': dump_tests, + 'chunkByDir': kwargs['chunk_by_dir'], + 'chunkByRuntime': kwargs['chunk_by_runtime'], + } + + found = False + for this_chunk in range(1, total_chunks+1): + args['thisChunk'] = this_chunk + try: + self._mach_context.commands.dispatch(suite_name, self._mach_context, flavor=flavor, resolve_tests=False, **args) + except SystemExit: + pass + except KeyboardInterrupt: + break + + fp = open(os.path.expanduser(args['dump_tests']), 'r') + tests = json.loads(fp.read())['active_tests'] + paths = [t['path'] for t in tests] + if test_path in paths: + print("The test %s is present in chunk number: %d (it may be skipped)." % (test_path, this_chunk)) + found = True + break + + if not found: + raise Exception("Test %s not found." % test_path) + # Clean up the file + os.remove(dump_tests) diff --git a/testing/mochitest/Makefile.in b/testing/mochitest/Makefile.in index dbba13a599..64eddfaa58 100644 --- a/testing/mochitest/Makefile.in +++ b/testing/mochitest/Makefile.in @@ -100,7 +100,7 @@ include $(topsrcdir)/config/android-common.mk stage-package-android: $(NSINSTALL) -D $(_DEST_DIR) $(call RELEASE_SIGN_ANDROID_APK,\ - $(DEPTH)/build/mobile/robocop/robocop-debug-unsigned-unaligned.apk,\ + $(DEPTH)/mobile/android/tests/browser/robocop/robocop-debug-unsigned-unaligned.apk,\ $(_DEST_DIR)/robocop.apk) stage-package: stage-package-android diff --git a/testing/mochitest/mach_commands.py b/testing/mochitest/mach_commands.py index 30f497fc57..0f0e8c6bdf 100644 --- a/testing/mochitest/mach_commands.py +++ b/testing/mochitest/mach_commands.py @@ -30,13 +30,6 @@ import mozpack.path as mozpath here = os.path.abspath(os.path.dirname(__file__)) -ADB_NOT_FOUND = ''' -The mochitest command requires the adb binary to be on your path. - -If you have a B2G build, this can be found in -'{}/out/host//bin'. -'''.lstrip() - GAIA_PROFILE_NOT_FOUND = ''' The mochitest command requires a non-debug gaia profile. Either pass in --profile, or set the GAIA_PROFILE environment variable. @@ -279,20 +272,14 @@ class MochitestRunner(MozbuildObject): options = Namespace(**kwargs) from manifestparser import TestManifest - manifest = TestManifest() - manifest.tests.extend(tests) - options.manifestFile = manifest + if tests: + manifest = TestManifest() + manifest.tests.extend(tests) + options.manifestFile = manifest if options.desktop: return mochitest.run_desktop_mochitests(options) - try: - which.which('adb') - except which.WhichError: - # TODO Find adb automatically if it isn't on the path - print(ADB_NOT_FOUND.format(options.b2gPath)) - return 1 - return mochitest.run_remote_mochitests(options) def run_desktop_test(self, context, tests=None, suite=None, **kwargs): @@ -335,13 +322,17 @@ class MochitestRunner(MozbuildObject): options.xrePath = self.get_webapp_runtime_xre_path() from manifestparser import TestManifest - manifest = TestManifest() - manifest.tests.extend(tests) - options.manifestFile = manifest + if tests: + manifest = TestManifest() + manifest.tests.extend(tests) + options.manifestFile = manifest - # XXX why is this such a special case? - if len(tests) == 1 and options.closeWhenDone and suite == 'plain': - options.closeWhenDone = False + # When developing mochitest-plain tests, it's often useful to be able to + # refresh the page to pick up modifications. Therefore leave the browser + # open if only running a single mochitest-plain test. This behaviour can + # be overridden by passing in --keep-open=false. + if len(tests) == 1 and options.keep_open is None and suite == 'plain': + options.keep_open = True # We need this to enable colorization of output. self.log_manager.enable_unstructured() @@ -364,12 +355,34 @@ class MochitestRunner(MozbuildObject): options = Namespace(**kwargs) from manifestparser import TestManifest - manifest = TestManifest() - manifest.tests.extend(tests) - options.manifestFile = manifest + if tests: + manifest = TestManifest() + manifest.tests.extend(tests) + options.manifestFile = manifest return runtestsremote.run_test_harness(options) + def run_robocop_test(self, context, tests, suite=None, **kwargs): + host_ret = verify_host_bin() + if host_ret != 0: + return host_ret + + import imp + path = os.path.join(self.mochitest_dir, 'runrobocop.py') + with open(path, 'r') as fh: + imp.load_module('runrobocop', fh, path, + ('.py', 'r', imp.PY_SOURCE)) + import runrobocop + + options = Namespace(**kwargs) + + from manifestparser import TestManifest + if tests: + manifest = TestManifest() + manifest.tests.extend(tests) + options.manifestFile = manifest + + return runrobocop.run_test_harness(options) # parser @@ -399,7 +412,7 @@ def setup_argument_parser(): # be done in this admittedly awkward place because # MochitestArgumentParser initialization fails if no device is found. from mozrunner.devices.android_device import verify_android_device - verify_android_device(build_obj, install=True) + verify_android_device(build_obj, install=True, xre=True) return MochitestArgumentParser() @@ -444,7 +457,7 @@ class MachCommands(MachCommandBase): metavar='{{{}}}'.format(', '.join(CANONICAL_FLAVORS)), choices=SUPPORTED_FLAVORS, help='Only run tests of this flavor.') - def run_mochitest_general(self, flavor=None, test_objects=None, **kwargs): + def run_mochitest_general(self, flavor=None, test_objects=None, resolve_tests=True, **kwargs): buildapp = None for app in SUPPORTED_APPS: if is_buildapp_in(app)(self): @@ -486,7 +499,9 @@ class MachCommands(MachCommandBase): test_paths = new_paths mochitest = self._spawn(MochitestRunner) - tests = mochitest.resolve_tests(test_paths, test_objects, cwd=self._mach_context.cwd) + tests = [] + if resolve_tests: + tests = mochitest.resolve_tests(test_paths, test_objects, cwd=self._mach_context.cwd) subsuite = kwargs.get('subsuite') if subsuite == 'default': @@ -515,6 +530,14 @@ class MachCommands(MachCommandBase): suites[key].append(test) + # This is a hack to introduce an option in mach to not send + # filtered tests to the mochitest harness. Mochitest harness will read + # the master manifest in that case. + if not resolve_tests: + for flavor in flavors: + key = (flavor, kwargs.get('subsuite')) + suites[key] = [] + if not suites: # Make it very clear why no tests were found if not unsupported: @@ -555,6 +578,7 @@ class MachCommands(MachCommandBase): print(NOW_RUNNING.format(msg)) harness_args = kwargs.copy() + harness_args['subsuite'] = subsuite harness_args.update(fobj.get('extra_args', {})) result = run_mochitest( @@ -589,8 +613,9 @@ class RobocopCommands(MachCommandBase): 'mochitest', 'robocop.ini') if not kwargs.get('robocopApk'): - kwargs['robocopApk'] = os.path.join(self.topobjdir, 'build', 'mobile', - 'robocop', 'robocop-debug.apk') + kwargs['robocopApk'] = os.path.join(self.topobjdir, 'mobile', 'android', + 'tests', 'browser', 'robocop', + 'robocop-debug.apk') from mozbuild.controller.building import BuildDriver self._ensure_state_subdir_exists('.') @@ -607,9 +632,12 @@ class RobocopCommands(MachCommandBase): flavor='instrumentation', subsuite='robocop')) mochitest = self._spawn(MochitestRunner) - return mochitest.run_android_test(self._mach_context, tests, 'robocop', **kwargs) + return mochitest.run_robocop_test(self._mach_context, tests, 'robocop', **kwargs) +# NOTE python/mach/mach/commands/commandinfo.py references this function +# by name. If this function is renamed or removed, that file should +# be updated accordingly as well. def REMOVED(cls): """Command no longer exists! Use |mach mochitest| instead. diff --git a/testing/mochitest/mochitest_options.py b/testing/mochitest/mochitest_options.py index e1581848c9..789075a09a 100644 --- a/testing/mochitest/mochitest_options.py +++ b/testing/mochitest/mochitest_options.py @@ -4,6 +4,7 @@ from abc import ABCMeta, abstractmethod, abstractproperty from argparse import ArgumentParser, SUPPRESS +from distutils.util import strtobool from urlparse import urlparse import os import tempfile @@ -66,10 +67,12 @@ class MochitestArguments(ArgumentContainer): "(to run recursively). If omitted, the entire suite is run.", }], [["--keep-open"], - {"action": "store_false", - "dest": "closeWhenDone", - "default": True, - "help": "Always keep the browser open after tests complete.", + {"nargs": "?", + "type": strtobool, + "const": "true", + "default": None, + "help": "Always keep the browser open after tests complete. Or always close the " + "browser with --keep-open=false", }], [["--appname"], {"dest": "app", @@ -787,7 +790,7 @@ class B2GArguments(ArgumentContainer): }], [["--adbpath"], {"dest": "adbPath", - "default": "adb", + "default": None, "help": "Path to adb binary.", "suppress": True, }], @@ -1016,12 +1019,6 @@ class AndroidArguments(ArgumentContainer): "default": "", "help": "name of the Robocop APK to use for ADB test running", }], - [["--robocop-ids"], - {"dest": "robocopIds", - "default": "", - "help": "name of the file containing the view ID map \ - (fennec_ids.txt)", - }], [["--remoteTestRoot"], {"dest": "remoteTestRoot", "default": None, @@ -1120,7 +1117,8 @@ class AndroidArguments(ArgumentContainer): options.robocopIni = os.path.abspath(options.robocopIni) if not options.robocopApk and build_obj: - options.robocopApk = os.path.join(build_obj.topobjdir, 'build', 'mobile', + options.robocopApk = os.path.join(build_obj.topobjdir, 'mobile', 'android', + 'tests', 'browser', 'robocop', 'robocop-debug.apk') if options.robocopApk != "": @@ -1130,13 +1128,6 @@ class AndroidArguments(ArgumentContainer): options.robocopApk) options.robocopApk = os.path.abspath(options.robocopApk) - if options.robocopIds != "": - if not os.path.exists(options.robocopIds): - parser.error( - "Unable to find specified robocop IDs file '%s'" % - options.robocopIds) - options.robocopIds = os.path.abspath(options.robocopIds) - # allow us to keep original application around for cleanup while # running robocop via 'am' options.remoteappname = options.app diff --git a/testing/mochitest/moz.build b/testing/mochitest/moz.build index 3e23bc0d59..593b31712b 100644 --- a/testing/mochitest/moz.build +++ b/testing/mochitest/moz.build @@ -70,6 +70,7 @@ TEST_HARNESS_FILES.testing.mochitest += [ 'nested_setup.js', 'pywebsocket_wrapper.py', 'redirect.html', + 'runrobocop.py', 'runtests.py', 'runtestsb2g.py', 'runtestsremote.py', diff --git a/testing/mochitest/runrobocop.py b/testing/mochitest/runrobocop.py new file mode 100644 index 0000000000..2a7d0c0018 --- /dev/null +++ b/testing/mochitest/runrobocop.py @@ -0,0 +1,554 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import json +import os +import shutil +import sys +import tempfile +import traceback + +sys.path.insert( + 0, os.path.abspath( + os.path.realpath( + os.path.dirname(__file__)))) + +from automation import Automation +from remoteautomation import RemoteAutomation, fennecLogcatFilters +from runtests import Mochitest, MessageLogger +from mochitest_options import MochitestArgumentParser + +from manifestparser import TestManifest +from manifestparser.filters import chunk_by_slice +import devicemanager +import mozinfo + +SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(__file__))) + + +class RobocopTestRunner(Mochitest): + """ + A test harness for Robocop. Robocop tests are UI tests for Firefox for Android, + based on the Robotium test framework. This harness leverages some functionality + from mochitest, for convenience. + """ + auto = None + dm = None + # Some robocop tests run for >60 seconds without generating any output. + NO_OUTPUT_TIMEOUT = 180 + + def __init__(self, automation, devmgr, options): + """ + Simple one-time initialization. + """ + Mochitest.__init__(self, options) + + self.auto = automation + self.dm = devmgr + self.dm.default_timeout = 320 + self.options = options + self.options.logFile = "robocop.log" + self.environment = self.auto.environment + self.deviceRoot = self.dm.getDeviceRoot() + self.remoteProfile = options.remoteTestRoot + "/profile" + self.remoteProfileCopy = options.remoteTestRoot + "/profile-copy" + self.auto.setRemoteProfile(self.remoteProfile) + self.remoteConfigFile = os.path.join( + self.deviceRoot, "robotium.config") + self.remoteLog = options.remoteLogFile + self.auto.setRemoteLog(self.remoteLog) + self.remoteScreenshots = "/mnt/sdcard/Robotium-Screenshots" + self.remoteNSPR = os.path.join(options.remoteTestRoot, "nspr") + self.auto.setServerInfo( + self.options.webServer, self.options.httpPort, self.options.sslPort) + self.localLog = options.logFile + self.localProfile = None + productPieces = self.options.remoteProductName.split('.') + if (productPieces is not None): + self.auto.setProduct(productPieces[0]) + else: + self.auto.setProduct(self.options.remoteProductName) + self.auto.setAppName(self.options.remoteappname) + self.certdbNew = True + self.remoteCopyAvailable = True + self.passed = 0 + self.failed = 0 + self.todo = 0 + + def startup(self): + """ + Second-stage initialization: One-time initialization which may require cleanup. + """ + # Despite our efforts to clean up servers started by this script, in practice + # we still see infrequent cases where a process is orphaned and interferes + # with future tests, typically because the old server is keeping the port in use. + # Try to avoid those failures by checking for and killing orphan servers before + # trying to start new ones. + self.killNamedOrphans('ssltunnel') + self.killNamedOrphans('xpcshell') + self.auto.deleteANRs() + self.auto.deleteTombstones() + self.dm.killProcess(self.options.app.split('/')[-1]) + self.dm.removeDir(self.remoteScreenshots) + self.dm.removeDir(self.remoteNSPR) + self.dm.mkDir(self.remoteNSPR) + self.dm.mkDir(os.path.dirname(self.options.remoteLogFile)) + # Add Android version (SDK level) to mozinfo so that manifest entries + # can be conditional on android_version. + androidVersion = self.dm.shellCheckOutput( + ['getprop', 'ro.build.version.sdk']) + self.log.info( + "Android sdk version '%s'; will use this to filter manifests" % + str(androidVersion)) + mozinfo.info['android_version'] = androidVersion + if (self.options.dm_trans == 'adb' and self.options.robocopApk): + self.dm._checkCmd(["install", "-r", self.options.robocopApk]) + self.log.debug("Robocop APK %s installed" % + self.options.robocopApk) + # Display remote diagnostics; if running in mach, keep output terse. + if self.options.log_mach is None: + self.printDeviceInfo() + self.setupLocalPaths() + self.buildProfile() + # ignoreSSLTunnelExts is a workaround for bug 1109310 + self.startServers( + self.options, + debuggerInfo=None, + ignoreSSLTunnelExts=True) + self.log.debug("Servers started") + + def cleanup(self): + """ + Cleanup at end of job run. + """ + self.log.debug("Cleaning up...") + self.stopServers() + self.dm.killProcess(self.options.app.split('/')[-1]) + blobberUploadDir = os.environ.get('MOZ_UPLOAD_DIR', None) + if blobberUploadDir: + self.log.debug("Pulling any remote nspr logs and screenshots to %s." % + blobberUploadDir) + self.dm.getDirectory(self.remoteNSPR, blobberUploadDir) + self.dm.getDirectory(self.remoteScreenshots, blobberUploadDir) + Mochitest.cleanup(self, self.options) + if self.localProfile: + os.system("rm -Rf %s" % self.localProfile) + self.dm.removeDir(self.remoteProfile) + self.dm.removeDir(self.remoteProfileCopy) + self.dm.removeDir(self.remoteScreenshots) + self.dm.removeDir(self.remoteNSPR) + self.dm.removeFile(self.remoteConfigFile) + if self.dm.fileExists(self.remoteLog): + self.dm.removeFile(self.remoteLog) + self.log.debug("Cleanup complete.") + + def findPath(self, paths, filename=None): + for path in paths: + p = path + if filename: + p = os.path.join(p, filename) + if os.path.exists(self.getFullPath(p)): + return path + return None + + def makeLocalAutomation(self): + localAutomation = Automation() + localAutomation.IS_WIN32 = False + localAutomation.IS_LINUX = False + localAutomation.IS_MAC = False + localAutomation.UNIXISH = False + hostos = sys.platform + if (hostos == 'mac' or hostos == 'darwin'): + localAutomation.IS_MAC = True + elif (hostos == 'linux' or hostos == 'linux2'): + localAutomation.IS_LINUX = True + localAutomation.UNIXISH = True + elif (hostos == 'win32' or hostos == 'win64'): + localAutomation.BIN_SUFFIX = ".exe" + localAutomation.IS_WIN32 = True + return localAutomation + + def setupLocalPaths(self): + """ + Setup xrePath and utilityPath and verify xpcshell. + + This is similar to switchToLocalPaths in runtestsremote.py. + """ + localAutomation = self.makeLocalAutomation() + paths = [ + self.options.xrePath, + localAutomation.DIST_BIN, + self.auto._product, + os.path.join('..', self.auto._product) + ] + self.options.xrePath = self.findPath(paths) + if self.options.xrePath is None: + self.log.error( + "unable to find xulrunner path for %s, please specify with --xre-path" % + os.name) + sys.exit(1) + self.log.debug("using xre path %s" % self.options.xrePath) + xpcshell = "xpcshell" + if (os.name == "nt"): + xpcshell += ".exe" + if self.options.utilityPath: + paths = [self.options.utilityPath, self.options.xrePath] + else: + paths = [self.options.xrePath] + self.options.utilityPath = self.findPath(paths, xpcshell) + if self.options.utilityPath is None: + self.log.error( + "unable to find utility path for %s, please specify with --utility-path" % + os.name) + sys.exit(1) + self.log.debug("using utility path %s" % self.options.utilityPath) + xpcshell_path = os.path.join(self.options.utilityPath, xpcshell) + if localAutomation.elf_arm(xpcshell_path): + self.log.error('xpcshell at %s is an ARM binary; please use ' + 'the --utility-path argument to specify the path ' + 'to a desktop version.' % xpcshell_path) + sys.exit(1) + self.log.debug("xpcshell found at %s" % xpcshell_path) + + def buildProfile(self): + """ + Build a profile locally, keep it locally for use by servers and + push a copy to the remote profile-copy directory. + + This is similar to buildProfile in runtestsremote.py. + """ + self.options.extraPrefs.append('browser.search.suggest.enabled=true') + self.options.extraPrefs.append('browser.search.suggest.prompted=true') + self.options.extraPrefs.append('layout.css.devPixelsPerPx=1.0') + self.options.extraPrefs.append('browser.chrome.dynamictoolbar=false') + self.options.extraPrefs.append('browser.snippets.enabled=false') + self.options.extraPrefs.append('browser.casting.enabled=true') + self.options.extraPrefs.append('extensions.autoupdate.enabled=false') + manifest = Mochitest.buildProfile(self, self.options) + self.localProfile = self.options.profilePath + self.log.debug("Profile created at %s" % self.localProfile) + # some files are not needed for robocop; save time by not pushing + shutil.rmtree(os.path.join(self.localProfile, 'webapps')) + desktop_extensions = ['mochikit@mozilla.org', 'worker-test@mozilla.org', 'workerbootstrap-test@mozilla.org'] + for ext in desktop_extensions: + shutil.rmtree(os.path.join(self.localProfile, 'extensions', 'staged', ext)) + os.remove(os.path.join(self.localProfile, 'userChrome.css')) + try: + self.dm.pushDir(self.localProfile, self.remoteProfileCopy) + except devicemanager.DMError: + self.log.error( + "Automation Error: Unable to copy profile to device.") + raise + + return manifest + + def setupRemoteProfile(self): + """ + Remove any remote profile and re-create it. + """ + self.log.debug("Updating remote profile at %s" % self.remoteProfile) + self.dm.removeDir(self.remoteProfile) + if self.remoteCopyAvailable: + try: + self.dm.shellCheckOutput( + ['cp', '-r', self.remoteProfileCopy, self.remoteProfile], + root=True, timeout=60) + except devicemanager.DMError: + # For instance, cp is not available on some older versions of + # Android. + self.log.info( + "Unable to copy remote profile; falling back to push.") + self.remoteCopyAvailable = False + if not self.remoteCopyAvailable: + self.dm.pushDir(self.localProfile, self.remoteProfile) + + def parseLocalLog(self): + """ + Read and parse the local log file, noting any failures. + """ + with open(self.localLog) as currentLog: + data = currentLog.readlines() + os.unlink(self.localLog) + start_found = False + end_found = False + fail_found = False + for line in data: + try: + message = json.loads(line) + if not isinstance(message, dict) or 'action' not in message: + continue + except ValueError: + continue + if message['action'] == 'test_end': + end_found = True + start_found = False + break + if start_found and not end_found: + if 'status' in message: + if 'expected' in message: + self.failed += 1 + elif message['status'] == 'PASS': + self.passed += 1 + elif message['status'] == 'FAIL': + self.todo += 1 + if message['action'] == 'test_start': + start_found = True + if 'expected' in message: + fail_found = True + result = 0 + if fail_found: + result = 1 + if not end_found: + self.log.info( + "PROCESS-CRASH | Automation Error: Missing end of test marker (process crashed?)") + result = 1 + return result + + def logTestSummary(self): + """ + Print a summary of all tests run to stdout, for treeherder parsing + (logging via self.log does not work here). + """ + print("0 INFO TEST-START | Shutdown") + print("1 INFO Passed: %s" % (self.passed)) + print("2 INFO Failed: %s" % (self.failed)) + print("3 INFO Todo: %s" % (self.todo)) + print("4 INFO SimpleTest FINISHED") + if self.failed > 0: + return 1 + return 0 + + def printDeviceInfo(self, printLogcat=False): + """ + Log remote device information and logcat (if requested). + + This is similar to printDeviceInfo in runtestsremote.py + """ + try: + if printLogcat: + logcat = self.dm.getLogcat( + filterOutRegexps=fennecLogcatFilters) + self.log.info( + '\n' + + ''.join(logcat).decode( + 'utf-8', + 'replace')) + self.log.info("Device info:") + devinfo = self.dm.getInfo() + for category in devinfo: + if type(devinfo[category]) is list: + self.log.info(" %s:" % category) + for item in devinfo[category]: + self.log.info(" %s" % item) + else: + self.log.info(" %s: %s" % (category, devinfo[category])) + self.log.info("Test root: %s" % self.dm.deviceRoot) + except devicemanager.DMError: + self.log.warning("Error getting device information") + + def setupRobotiumConfig(self, browserEnv): + """ + Create robotium.config and push it to the device. + """ + fHandle = tempfile.NamedTemporaryFile(suffix='.config', + prefix='robotium-', + dir=os.getcwd(), + delete=False) + fHandle.write("profile=%s\n" % (self.remoteProfile)) + fHandle.write("logfile=%s\n" % (self.options.remoteLogFile)) + fHandle.write("host=http://mochi.test:8888/tests\n") + fHandle.write( + "rawhost=http://%s:%s/tests\n" % + (self.options.remoteWebServer, self.options.httpPort)) + if browserEnv: + envstr = "" + delim = "" + for key, value in browserEnv.items(): + try: + value.index(',') + self.log.error( + "setupRobotiumConfig: browserEnv - Found a ',' in our value, unable to process value. key=%s,value=%s" % + (key, value)) + self.log.error("browserEnv=%s" % browserEnv) + except ValueError: + envstr += "%s%s=%s" % (delim, key, value) + delim = "," + fHandle.write("envvars=%s\n" % envstr) + fHandle.close() + self.dm.removeFile(self.remoteConfigFile) + self.dm.pushFile(fHandle.name, self.remoteConfigFile) + os.unlink(fHandle.name) + + def buildBrowserEnv(self): + """ + Return an environment dictionary suitable for remote use. + + This is similar to buildBrowserEnv in runtestsremote.py. + """ + browserEnv = self.environment( + xrePath=None, + debugger=None) + # remove desktop environment not used on device + if "MOZ_WIN_INHERIT_STD_HANDLES_PRE_VISTA" in browserEnv: + del browserEnv["MOZ_WIN_INHERIT_STD_HANDLES_PRE_VISTA"] + if "XPCOM_MEM_BLOAT_LOG" in browserEnv: + del browserEnv["XPCOM_MEM_BLOAT_LOG"] + browserEnv["NSPR_LOG_FILE"] = os.path.join( + self.remoteNSPR, + self.nsprLogName) + return browserEnv + + def runSingleTest(self, test): + """ + Run the specified test. + """ + self.log.debug("Running test %s" % test['name']) + self.nsprLogName = "nspr-%s.log" % test['name'] + browserEnv = self.buildBrowserEnv() + self.setupRobotiumConfig(browserEnv) + self.setupRemoteProfile() + self.options.app = "am" + if self.options.autorun: + # This launches a test (using "am instrument") and instructs + # Fennec to /quit/ the browser (using Robocop:Quit) and to + # /finish/ all opened activities. + browserArgs = [ + "instrument", + "-w", + "-e", "quit_and_finish", "1", + "-e", "deviceroot", self.deviceRoot, + "-e", "class", + "org.mozilla.gecko.tests.%s" % test['name'].split('.java')[0], + "org.mozilla.roboexample.test/org.mozilla.gecko.FennecInstrumentationTestRunner"] + else: + # This does not launch a test at all. It launches an activity + # that starts Fennec and then waits indefinitely, since cat + # never returns. + browserArgs = ["start", + "-n", "org.mozilla.roboexample.test/org.mozilla.gecko.LaunchFennecWithConfigurationActivity", + "&&", "cat"] + self.dm.default_timeout = sys.maxint # Forever. + self.log.info("") + self.log.info("Serving mochi.test Robocop root at http://%s:%s/tests/robocop/" % + (self.options.remoteWebServer, self.options.httpPort)) + self.log.info("") + result = -1 + log_result = -1 + try: + self.dm.recordLogcat() + result = self.auto.runApp( + None, browserEnv, "am", self.localProfile, browserArgs, timeout=self.NO_OUTPUT_TIMEOUT) + self.log.debug("runApp completes with status %d" % result) + if result != 0: + self.log.error("runApp() exited with code %s" % result) + if self.dm.fileExists(self.remoteLog): + self.dm.getFile(self.remoteLog, self.localLog) + self.dm.removeFile(self.remoteLog) + self.log.debug("Remote log %s retrieved to %s" % + (self.remoteLog, self.localLog)) + else: + self.log.warning( + "Unable to retrieve log file (%s) from remote device" % + self.remoteLog) + log_result = self.parseLocalLog() + if result != 0 or log_result != 0: + # Display remote diagnostics; if running in mach, keep output + # terse. + if self.options.log_mach is None: + self.printDeviceInfo(printLogcat=True) + except: + self.log.error( + "Automation Error: Exception caught while running tests") + traceback.print_exc() + result = 1 + self.log.debug("Test %s completes with status %d (log status %d)" % + (test['name'], int(result), int(log_result))) + return result + + def runTests(self): + self.startup() + if isinstance(self.options.manifestFile, TestManifest): + mp = self.options.manifestFile + else: + mp = TestManifest(strict=False) + mp.read(self.options.robocopIni) + filters = [] + if self.options.totalChunks: + filters.append( + chunk_by_slice(self.options.thisChunk, self.options.totalChunks)) + robocop_tests = mp.active_tests( + exists=False, filters=filters, **mozinfo.info) + if not self.options.autorun: + # Force a single loop iteration. The iteration will start Fennec and + # the httpd server, but not actually run a test. + self.options.test_paths = [robocop_tests[0]['name']] + active_tests = [] + for test in robocop_tests: + if self.options.test_paths and test['name'] not in self.options.test_paths: + continue + if 'disabled' in test: + self.log.info('TEST-INFO | skipping %s | %s' % + (test['name'], test['disabled'])) + continue + active_tests.append(test) + self.log.suite_start([t['name'] for t in active_tests]) + worstTestResult = None + for test in active_tests: + result = self.runSingleTest(test) + if worstTestResult is None or worstTestResult == 0: + worstTestResult = result + if worstTestResult is None: + self.log.warning( + "No tests run. Did you pass an invalid TEST_PATH?") + worstTestResult = 1 + else: + print "INFO | runtests.py | Test summary: start." + logResult = self.logTestSummary() + print "INFO | runtests.py | Test summary: end." + if worstTestResult == 0: + worstTestResult = logResult + return worstTestResult + + +def run_test_harness(options): + if options is None: + raise ValueError( + "Invalid options specified, use --help for a list of valid options") + message_logger = MessageLogger(logger=None) + process_args = {'messageLogger': message_logger} + auto = RemoteAutomation(None, "fennec", processArgs=process_args) + auto.setDeviceManager(options.dm) + runResult = -1 + robocop = RobocopTestRunner(auto, options.dm, options) + try: + message_logger.logger = robocop.log + message_logger.buffering = False + robocop.message_logger = message_logger + robocop.log.debug("options=%s" % vars(options)) + runResult = robocop.runTests() + except KeyboardInterrupt: + robocop.log.info("runrobocop.py | Received keyboard interrupt") + runResult = -1 + except: + traceback.print_exc() + robocop.log.error( + "runrobocop.py | Received unexpected exception while running tests") + runResult = 1 + finally: + try: + robocop.cleanup() + except devicemanager.DMError: + # ignore device error while cleaning up + pass + message_logger.finish() + return runResult + + +def main(args=sys.argv[1:]): + parser = MochitestArgumentParser(app='android') + options = parser.parse_args(args) + return run_test_harness(options) + +if __name__ == "__main__": + sys.exit(main()) diff --git a/testing/mochitest/runtests.py b/testing/mochitest/runtests.py index 3e7c7d65bf..b376f7a632 100644 --- a/testing/mochitest/runtests.py +++ b/testing/mochitest/runtests.py @@ -337,7 +337,7 @@ class MochitestServer(object): if isinstance(options, Namespace): options = vars(options) self._log = logger - self._closeWhenDone = options['closeWhenDone'] + self._keep_open = bool(options['keep_open']) self._utilityPath = options['utilityPath'] self._xrePath = options['xrePath'] self._profileDir = options['profilePath'] @@ -395,7 +395,7 @@ class MochitestServer(object): "server": self.webServer, "testPrefix": self.testPrefix, "displayResults": str( - not self._closeWhenDone).lower()}, + self._keep_open).lower()}, "-f", os.path.join( SCRIPT_DIR, @@ -600,7 +600,7 @@ class MochitestUtilsMixin(object): self.urlOpts.append("timeout=%d" % options.timeout) if options.maxTimeouts: self.urlOpts.append("maxTimeouts=%d" % options.maxTimeouts) - if options.closeWhenDone: + if not options.keep_open: self.urlOpts.append("closeWhenDone=1") if options.webapprtContent: self.urlOpts.append("testRoot=webapprtContent") @@ -2204,6 +2204,11 @@ class Mochitest(MochitestUtilsMixin): if self.urlOpts: testURL += "?" + "&".join(self.urlOpts) + # On Mac, pass the path to the runtime, to ensure the test app + # uses that specific runtime instead of another one on the system. + if mozinfo.isMac and options.webapprtChrome: + options.browserArgs.extend(('-runtime', os.path.dirname(os.path.dirname(options.xrePath)))) + if options.webapprtContent: options.browserArgs.extend(('-test-mode', testURL)) testURL = None @@ -2525,6 +2530,8 @@ class Mochitest(MochitestUtilsMixin): d = dict((k, v) for k, v in options.__dict__.items() if (v is None) or isinstance(v,(basestring,numbers.Number))) d['testRoot'] = self.testRoot + if not options.keep_open: + d['closeWhenDone'] = '1' content = json.dumps(d) with open(os.path.join(options.profilePath, "testConfig.js"), "w") as config: diff --git a/testing/mochitest/runtestsremote.py b/testing/mochitest/runtestsremote.py index 8126c54d22..2e4960fbc6 100644 --- a/testing/mochitest/runtestsremote.py +++ b/testing/mochitest/runtestsremote.py @@ -66,10 +66,6 @@ class MochiRemote(Mochitest): self.remoteLog) self._dm.removeDir(self.remoteProfile) self._dm.removeDir(self.remoteChromeTestDir) - # Don't leave an old robotium.config hanging around; the - # profile it references was just deleted! - deviceRoot = self._dm.getDeviceRoot() - self._dm.removeFile(os.path.join(deviceRoot, "robotium.config")) blobberUploadDir = os.environ.get('MOZ_UPLOAD_DIR', None) if blobberUploadDir: self._dm.getDirectory(self.remoteNSPR, blobberUploadDir) @@ -178,29 +174,6 @@ class MochiRemote(Mochitest): self.localProfile = options.profilePath self._dm.removeDir(self.remoteProfile) - # we do not need this for robotium based tests, lets save a LOT of time - if options.robocopIni: - shutil.rmtree(os.path.join(options.profilePath, 'webapps')) - shutil.rmtree( - os.path.join( - options.profilePath, - 'extensions', - 'staged', - 'mochikit@mozilla.org')) - shutil.rmtree( - os.path.join( - options.profilePath, - 'extensions', - 'staged', - 'worker-test@mozilla.org')) - shutil.rmtree( - os.path.join( - options.profilePath, - 'extensions', - 'staged', - 'workerbootstrap-test@mozilla.org')) - os.remove(os.path.join(options.profilePath, 'userChrome.css')) - try: self._dm.pushDir(options.profilePath, self.remoteProfile) except devicemanager.DMError: @@ -220,38 +193,18 @@ class MochiRemote(Mochitest): env["MOZ_HIDE_RESULTS_TABLE"] = "1" retVal = Mochitest.buildURLOptions(self, options, env) - if not options.robocopIni: - # we really need testConfig.js (for browser chrome) - try: - self._dm.pushDir(options.profilePath, self.remoteProfile) - except devicemanager.DMError: - self.log.error( - "Automation Error: Unable to copy profile to device.") - raise + # we really need testConfig.js (for browser chrome) + try: + self._dm.pushDir(options.profilePath, self.remoteProfile) + except devicemanager.DMError: + self.log.error( + "Automation Error: Unable to copy profile to device.") + raise options.profilePath = self.remoteProfile options.logFile = self.localLog return retVal - def getTestsToRun(self, options): - if options.robocopIni != "": - # Skip over tests filtering if we run robocop tests. - return None - else: - return super(MochiRemote, self).getTestsToRun(options) - - def buildTestPath(self, options, testsToFilter=None): - if options.robocopIni != "": - # Skip over manifest building if we just want to run - # robocop tests. - return self.buildTestURL(options) - else: - return super( - MochiRemote, - self).buildTestPath( - options, - testsToFilter) - def getChromeTestDir(self, options): local = super(MochiRemote, self).getChromeTestDir(options) local = os.path.join(local, "chrome") @@ -264,105 +217,6 @@ class MochiRemote(Mochitest): def getLogFilePath(self, logFile): return logFile - # In the future we could use LogParser: - # http://hg.mozilla.org/automation/logparser/ - def addLogData(self): - with open(self.localLog) as currentLog: - data = currentLog.readlines() - start_found = False - end_found = False - fail_found = False - for line in data: - try: - message = json.loads(line) - if not isinstance(message, dict) or 'action' not in message: - continue - except ValueError: - continue - - if message['action'] == 'test_end': - end_found = True - start_found = False - break - - if start_found and not end_found: - self.logMessages.append(message) - - if message['action'] == 'test_start': - start_found = True - if 'expected' in message: - fail_found = True - result = 0 - if fail_found: - result = 1 - if not end_found: - self.log.info( - "PROCESS-CRASH | Automation Error: Missing end of test marker (process crashed?)") - result = 1 - return result - - def printLog(self): - passed = 0 - failed = 0 - todo = 0 - incr = 1 - logFile = [] - logFile.append("0 INFO SimpleTest START") - for message in self.logMessages: - if 'status' not in message: - continue - - if 'expected' in message: - failed += 1 - elif message['status'] == 'PASS': - passed += 1 - elif message['status'] == 'FAIL': - todo += 1 - incr += 1 - - logFile.append("%s INFO TEST-START | Shutdown" % incr) - incr += 1 - logFile.append("%s INFO Passed: %s" % (incr, passed)) - incr += 1 - logFile.append("%s INFO Failed: %s" % (incr, failed)) - incr += 1 - logFile.append("%s INFO Todo: %s" % (incr, todo)) - incr += 1 - logFile.append("%s INFO SimpleTest FINISHED" % incr) - - # TODO: Consider not printing to stdout because we might be duplicating - # output - print '\n'.join(logFile) - with open(self.localLog, 'w') as localLog: - localLog.write('\n'.join(logFile)) - - if failed > 0: - return 1 - return 0 - - def printScreenshots(self, screenShotDir): - # TODO: This can be re-written after completion of bug 749421 - if not self._dm.dirExists(screenShotDir): - self.log.info( - "SCREENSHOT: No ScreenShots directory available: " + - screenShotDir) - return - - printed = 0 - for name in self._dm.listFiles(screenShotDir): - fullName = screenShotDir + "/" + name - self.log.info("SCREENSHOT: FOUND: [%s]" % fullName) - try: - image = self._dm.pullFile(fullName) - encoded = base64.b64encode(image) - self.log.info("SCREENSHOT: data:image/jpg;base64,%s" % encoded) - printed += 1 - except: - self.log.info("SCREENSHOT: Could not be parsed") - pass - - self.log.info("SCREENSHOT: TOTAL PRINTED: [%s]" % printed) - def printDeviceInfo(self, printLogcat=False): try: if printLogcat: @@ -386,44 +240,6 @@ class MochiRemote(Mochitest): except devicemanager.DMError: self.log.warning("Error getting device information") - def buildRobotiumConfig(self, options, browserEnv): - deviceRoot = self._dm.deviceRoot - fHandle = tempfile.NamedTemporaryFile(suffix='.config', - prefix='robotium-', - dir=os.getcwd(), - delete=False) - fHandle.write("profile=%s\n" % (self.remoteProfile)) - fHandle.write("logfile=%s\n" % (options.remoteLogFile)) - fHandle.write("host=http://mochi.test:8888/tests\n") - fHandle.write( - "rawhost=http://%s:%s/tests\n" % - (options.remoteWebServer, options.httpPort)) - - if browserEnv: - envstr = "" - delim = "" - for key, value in browserEnv.items(): - try: - value.index(',') - self.log.error( - "buildRobotiumConfig: browserEnv - Found a ',' in our value, unable to process value. key=%s,value=%s" % - (key, value)) - self.log.error("browserEnv=%s" % browserEnv) - except ValueError: - envstr += "%s%s=%s" % (delim, key, value) - delim = "," - - fHandle.write("envvars=%s\n" % envstr) - fHandle.close() - - self._dm.removeFile(os.path.join(deviceRoot, "robotium.config")) - self._dm.pushFile( - fHandle.name, - os.path.join( - deviceRoot, - "robotium.config")) - os.unlink(fHandle.name) - def getGMPPluginPath(self, options): # TODO: bug 1149374 return None @@ -443,7 +259,6 @@ class MochiRemote(Mochitest): browserEnv["NSPR_LOG_FILE"] = os.path.join( self.remoteNSPR, self.nsprLogName) - self.buildRobotiumConfig(options, browserEnv) return browserEnv def runApp(self, *args, **kwargs): @@ -535,221 +350,22 @@ def main(args): procName = options.app.split('/')[-1] dm.killProcess(procName) - if options.robocopIni != "": - # turning buffering off as it's not used in robocop - message_logger.buffering = False - - # sut may wait up to 300 s for a robocop am process before returning - dm.default_timeout = 320 - if isinstance(options.manifestFile, TestManifest): - mp = options.manifestFile - else: - mp = TestManifest(strict=False) - mp.read(options.robocopIni) - - filters = [] - if options.totalChunks: - filters.append( - chunk_by_slice(options.thisChunk, options.totalChunks)) - robocop_tests = mp.active_tests(exists=False, filters=filters, **mozinfo.info) - - options.extraPrefs.append('browser.search.suggest.enabled=true') - options.extraPrefs.append('browser.search.suggest.prompted=true') - options.extraPrefs.append('layout.css.devPixelsPerPx=1.0') - options.extraPrefs.append('browser.chrome.dynamictoolbar=false') - options.extraPrefs.append('browser.snippets.enabled=false') - options.extraPrefs.append('browser.casting.enabled=true') - - if (options.dm_trans == 'adb' and options.robocopApk): - dm._checkCmd(["install", "-r", options.robocopApk]) - - if not options.autorun: - # Force a single loop iteration. The iteration will start Fennec and - # the httpd server, but not actually run a test. - options.test_paths = [robocop_tests[0]['name']] - - retVal = None - # Filtering tests - active_tests = [] - for test in robocop_tests: - if options.test_paths and test['name'] not in options.test_paths: - continue - - if 'disabled' in test: - log.info( - 'TEST-INFO | skipping %s | %s' % - (test['name'], test['disabled'])) - continue - - active_tests.append(test) - - log.suite_start([t['name'] for t in active_tests]) - - for test in active_tests: - # When running in a loop, we need to create a fresh profile for - # each cycle - if mochitest.localProfile: - options.profilePath = mochitest.localProfile - os.system("rm -Rf %s" % options.profilePath) - options.profilePath = None - mochitest.localProfile = options.profilePath - - options.app = "am" - mochitest.nsprLogName = "nspr-%s.log" % test['name'] - if options.autorun: - # This launches a test (using "am instrument") and instructs - # Fennec to /quit/ the browser (using Robocop:Quit) and to - # /finish/ all opened activities. - options.browserArgs = [ - "instrument", - "-w", - "-e", "quit_and_finish", "1", - "-e", "deviceroot", deviceRoot, - "-e", - "class"] - options.browserArgs.append( - "org.mozilla.gecko.tests.%s" % - test['name'].split('.java')[0]) - options.browserArgs.append( - "org.mozilla.roboexample.test/org.mozilla.gecko.FennecInstrumentationTestRunner") - else: - # This does not launch a test at all. It launches an activity - # that starts Fennec and then waits indefinitely, since cat - # never returns. - options.browserArgs = ["start", - "-n", "org.mozilla.roboexample.test/org.mozilla.gecko.LaunchFennecWithConfigurationActivity", - "&&", "cat"] - dm.default_timeout = sys.maxint # Forever. - - mochitest.log.info("") - mochitest.log.info("Serving mochi.test Robocop root at http://%s:%s/tests/robocop/" % - (options.remoteWebServer, options.httpPort)) - mochitest.log.info("") - - # If the test is for checking the import from bookmarks then make - # sure there is data to import - if test['name'] == "testImportFromAndroid": - - # Get the OS so we can run the insert in the apropriate - # database and following the correct table schema - osInfo = dm.getInfo("os") - devOS = " ".join(osInfo['os']) - - if ("pandaboard" in devOS): - delete = [ - 'execsu', - 'sqlite3', - "/data/data/com.android.browser/databases/browser2.db \'delete from bookmarks where _id > 14;\'"] - else: - delete = [ - 'execsu', - 'sqlite3', - "/data/data/com.android.browser/databases/browser.db \'delete from bookmarks where _id > 14;\'"] - if (options.dm_trans == "sut"): - dm._runCmds([{"cmd": " ".join(delete)}]) - - # Insert the bookmarks - log.info( - "Insert bookmarks in the default android browser database") - for i in range(20): - if ("pandaboard" in devOS): - cmd = [ - 'execsu', - 'sqlite3', - "/data/data/com.android.browser/databases/browser2.db 'insert or replace into bookmarks(_id,title,url,folder,parent,position) values (" + - str( - 30 + - i) + - ",\"Bookmark" + - str(i) + - "\",\"http://www.bookmark" + - str(i) + - ".com\",0,1," + - str( - 100 + - i) + - ");'"] - else: - cmd = [ - 'execsu', - 'sqlite3', - "/data/data/com.android.browser/databases/browser.db 'insert into bookmarks(title,url,bookmark) values (\"Bookmark" + - str(i) + - "\",\"http://www.bookmark" + - str(i) + - ".com\",1);'"] - if (options.dm_trans == "sut"): - dm._runCmds([{"cmd": " ".join(cmd)}]) - try: - screenShotDir = "/mnt/sdcard/Robotium-Screenshots" - dm.removeDir(screenShotDir) - dm.recordLogcat() - result = mochitest.runTests(options) - if result != 0: - log.error("runTests() exited with code %s" % result) - log_result = mochitest.addLogData() - if result != 0 or log_result != 0: - mochitest.printDeviceInfo(printLogcat=True) - mochitest.printScreenshots(screenShotDir) - # Ensure earlier failures aren't overwritten by success on this - # run - if retVal is None or retVal == 0: - retVal = result - except: - log.error( - "Automation Error: Exception caught while running tests") - traceback.print_exc() - mochitest.stopServers() - try: - mochitest.cleanup(options) - except devicemanager.DMError: - # device error cleaning up... oh well! - pass - retVal = 1 - break - finally: - # Clean-up added bookmarks - if test['name'] == "testImportFromAndroid": - if ("pandaboard" in devOS): - cmd_del = [ - 'execsu', - 'sqlite3', - "/data/data/com.android.browser/databases/browser2.db \'delete from bookmarks where _id > 14;\'"] - else: - cmd_del = [ - 'execsu', - 'sqlite3', - "/data/data/com.android.browser/databases/browser.db \'delete from bookmarks where _id > 14;\'"] - if (options.dm_trans == "sut"): - dm._runCmds([{"cmd": " ".join(cmd_del)}]) - if retVal is None: - log.warning("No tests run. Did you pass an invalid TEST_PATH?") - retVal = 1 - else: - # if we didn't have some kind of error running the tests, make - # sure the tests actually passed - print "INFO | runtests.py | Test summary: start." - overallResult = mochitest.printLog() - print "INFO | runtests.py | Test summary: end." - if retVal == 0: - retVal = overallResult - else: - mochitest.nsprLogName = "nspr.log" + mochitest.nsprLogName = "nspr.log" + try: + dm.recordLogcat() + retVal = mochitest.runTests(options) + except: + log.error("Automation Error: Exception caught while running tests") + traceback.print_exc() + mochitest.stopServers() try: - dm.recordLogcat() - retVal = mochitest.runTests(options) - except: - log.error("Automation Error: Exception caught while running tests") - traceback.print_exc() - mochitest.stopServers() - try: - mochitest.cleanup(options) - except devicemanager.DMError: - # device error cleaning up... oh well! - pass - retVal = 1 + mochitest.cleanup(options) + except devicemanager.DMError: + # device error cleaning up... oh well! + pass + retVal = 1 - mochitest.printDeviceInfo(printLogcat=True) + mochitest.printDeviceInfo(printLogcat=True) message_logger.finish() diff --git a/testing/mozbase/mozrunner/mozrunner/devices/android_device.py b/testing/mozbase/mozrunner/mozrunner/devices/android_device.py index 1a88e52598..07846c4167 100644 --- a/testing/mozbase/mozrunner/mozrunner/devices/android_device.py +++ b/testing/mozbase/mozrunner/mozrunner/devices/android_device.py @@ -2,11 +2,14 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +import glob import os +import platform import psutil import re import shutil import signal +import sys import telnetlib import time import urllib2 @@ -19,6 +22,12 @@ EMULATOR_HOME_DIR = os.path.join(os.path.expanduser('~'), '.mozbuild', 'android- TOOLTOOL_URL = 'https://raw.githubusercontent.com/mozilla/build-tooltool/master/tooltool.py' +TRY_URL = 'https://hg.mozilla.org/try/raw-file/default' + +MANIFEST_URL = '%s/testing/config/tooltool-manifests' % TRY_URL + +verbose_logging = False + class AvdInfo(object): """ Simple class to contain an AVD description. @@ -70,13 +79,16 @@ AVD_DICT = { 20701, 20700) } -def verify_android_device(build_obj, install=False): +def verify_android_device(build_obj, install=False, xre=False): """ Determine if any Android device is connected via adb. If no device is found, prompt to start an emulator. If a device is found or an emulator started and 'install' is specified, also check whether Firefox is installed on the device; if not, prompt to install Firefox. + If 'xre' is specified, also check with MOZ_HOST_BIN is set + to a valid xre/host-utils directory; if not, prompt to set + one up. Returns True if the emulator was started or another device was already connected. """ @@ -90,9 +102,9 @@ def verify_android_device(build_obj, install=False): "No Android devices connected. Start an emulator? (Y/n) ").strip() if response.lower().startswith('y') or response == '': if not emulator.check_avd(): - print("Fetching AVD. This may take a while...") + _log_info("Fetching AVD. This may take a while...") emulator.update_avd() - print("Starting emulator running %s..." % + _log_info("Starting emulator running %s..." % emulator.get_avd_description()) emulator.start() emulator.wait_for_start() @@ -118,9 +130,58 @@ def verify_android_device(build_obj, install=False): "It looks like Firefox is not installed on this device.\n" "Install Firefox? (Y/n) ").strip() if response.lower().startswith('y') or response == '': - print("Installing Firefox. This may take a while...") + _log_info("Installing Firefox. This may take a while...") build_obj._run_make(directory=".", target='install', ensure_exit_code=False) + + if device_verified and xre: + # Check whether MOZ_HOST_BIN has been set to a valid xre; if not, + # prompt to install one. + xre_path = os.environ.get('MOZ_HOST_BIN') + err = None + if not xre_path: + err = 'environment variable MOZ_HOST_BIN is not set to a directory containing host xpcshell' + elif not os.path.isdir(xre_path): + err = '$MOZ_HOST_BIN does not specify a directory' + elif not os.path.isfile(os.path.join(xre_path, 'xpcshell')): + err = '$MOZ_HOST_BIN/xpcshell does not exist' + if err: + xre_path = glob.glob(os.path.join(EMULATOR_HOME_DIR, 'host-utils*')) + for path in xre_path: + if os.path.isdir(path) and os.path.isfile(os.path.join(path, 'xpcshell')): + os.environ['MOZ_HOST_BIN'] = path + err = None + break + if err: + _log_info("Host utilities not found: %s" % err) + response = raw_input( + "Download and setup your host utilities? (Y/n) ").strip() + if response.lower().startswith('y') or response == '': + _log_info("Installing host utilities. This may take a while...") + _download_file(TOOLTOOL_URL, 'tooltool.py', EMULATOR_HOME_DIR) + if 'darwin' in str(sys.platform).lower(): + plat = 'macosx64' + elif 'linux' in str(sys.platform).lower(): + if '64' in platform.architecture()[0]: + plat = 'linux64' + else: + plat = 'linux32' + else: + plat = None + _log_warning("Unable to install host utilities -- your platform is not supported!") + if plat: + url = '%s/%s/hostutils.manifest' % (MANIFEST_URL, plat) + _download_file(url, 'releng.manifest', EMULATOR_HOME_DIR) + _tooltool_fetch() + xre_path = glob.glob(os.path.join(EMULATOR_HOME_DIR, 'host-utils*')) + for path in xre_path: + if os.path.isdir(path) and os.path.isfile(os.path.join(path, 'xpcshell')): + os.environ['MOZ_HOST_BIN'] = path + err = None + break + if err: + _log_warning("Unable to install host utilities.") + return device_verified @@ -142,9 +203,10 @@ class AndroidEmulator(object): """ def __init__(self, avd_type='4.3', verbose=False, substs=None): + global verbose_logging self.emulator_log = None self.emulator_path = 'emulator' - self.verbose = verbose + verbose_logging = verbose self.substs = substs self.avd_type = self._get_avd_type(avd_type) self.avd_info = AVD_DICT[self.avd_type] @@ -153,7 +215,7 @@ class AndroidEmulator(object): adb_path = 'adb' self.dm = DeviceManagerADB(autoconnect=False, adbPath=adb_path, retryLimit=1) self.dm.default_timeout = 10 - self._log_debug("Emulator created with type %s" % self.avd_type) + _log_debug("Emulator created with type %s" % self.avd_type) def __del__(self): if self.emulator_log: @@ -196,7 +258,7 @@ class AndroidEmulator(object): if force and os.path.exists(avd): shutil.rmtree(avd) if os.path.exists(avd): - self._log_debug("AVD found at %s" % avd) + _log_debug("AVD found at %s" % avd) return True return False @@ -215,9 +277,10 @@ class AndroidEmulator(object): if force and os.path.exists(avd): shutil.rmtree(avd) if not os.path.exists(avd): - self._fetch_tooltool() - self._fetch_tooltool_manifest() - self._tooltool_fetch() + _download_file(TOOLTOOL_URL, 'tooltool.py', EMULATOR_HOME_DIR) + url = '%s/%s' % (TRY_URL, self.avd_info.tooltool_manifest) + _download_file(url, 'releng.manifest', EMULATOR_HOME_DIR) + _tooltool_fetch() self._update_avd_paths() def start(self): @@ -234,15 +297,15 @@ class AndroidEmulator(object): command += self.avd_info.extra_args log_path = os.path.join(EMULATOR_HOME_DIR, 'emulator.log') self.emulator_log = open(log_path, 'w') - self._log_debug("Starting the emulator with this command: %s" % + _log_debug("Starting the emulator with this command: %s" % ' '.join(command)) - self._log_debug("Emulator output will be written to '%s'" % + _log_debug("Emulator output will be written to '%s'" % log_path) self.proc = ProcessHandler( command, storeOutput=False, processOutputLine=outputHandler, env=env) self.proc.run() - self._log_debug("Emulator started with pid %d" % + _log_debug("Emulator started with pid %d" % int(self.proc.proc.pid)) def wait_for_start(self): @@ -251,20 +314,20 @@ class AndroidEmulator(object): to adb, and Android has booted. """ if not self.proc: - self._log_warning("Emulator not started!") + _log_warning("Emulator not started!") return False if self.proc.proc.poll() is not None: - self._log_warning("Emulator has already completed!") + _log_warning("Emulator has already completed!") return False - self._log_debug("Waiting for device status...") + _log_debug("Waiting for device status...") while(('emulator-5554', 'device') not in self.dm.devices()): time.sleep(10) if self.proc.proc.poll() is not None: - self._log_warning("Emulator has already completed!") + _log_warning("Emulator has already completed!") return False - self._log_debug("Device status verified.") + _log_debug("Device status verified.") - self._log_debug("Checking that Android has booted...") + _log_debug("Checking that Android has booted...") complete = False while(not complete): output = '' @@ -279,9 +342,9 @@ class AndroidEmulator(object): else: time.sleep(10) if self.proc.proc.poll() is not None: - self._log_warning("Emulator has already completed!") + _log_warning("Emulator has already completed!") return False - self._log_debug("Android boot status verified.") + _log_debug("Android boot status verified.") if not self._verify_emulator(): return False @@ -313,35 +376,6 @@ class AndroidEmulator(object): """ return self.avd_info.description - def _log_debug(self, text): - if self.verbose: - print "DEBUG: %s" % text - - def _log_warning(self, text): - print "WARNING: %s" % text - - def _fetch_tooltool(self): - self._download_file(TOOLTOOL_URL, 'tooltool.py', EMULATOR_HOME_DIR) - - def _fetch_tooltool_manifest(self): - url = 'https://hg.mozilla.org/%s/raw-file/%s/%s' % ( - "try", "default", self.avd_info.tooltool_manifest) - self._download_file(url, 'releng.manifest', EMULATOR_HOME_DIR) - - def _tooltool_fetch(self): - def outputHandler(line): - self._log_debug(line) - command = ['python', 'tooltool.py', 'fetch', '-m', 'releng.manifest'] - proc = ProcessHandler( - command, processOutputLine=outputHandler, storeOutput=False, - cwd=EMULATOR_HOME_DIR) - proc.run() - try: - proc.wait() - except: - if proc.poll() is None: - proc.kill(signal.SIGTERM) - def _update_avd_paths(self): avd_path = os.path.join(EMULATOR_HOME_DIR, "avd") ini_file = os.path.join(avd_path, "test-1.ini") @@ -352,20 +386,6 @@ class AndroidEmulator(object): os.rename(avd_dir, avd_dir_new) self._replace_ini_contents(ini_file_new) - def _download_file(self, url, filename, path): - f = urllib2.urlopen(url) - if not os.path.isdir(path): - try: - os.makedirs(path) - except Exception, e: - self._log_warning(str(e)) - return False - local_file = open(os.path.join(path, filename), 'wb') - local_file.write(f.read()) - local_file.close() - self._log_debug("Downloaded %s to %s/%s" % (url, path, filename)) - return True - def _replace_ini_contents(self, path): with open(path, "r") as f: lines = f.readlines() @@ -381,10 +401,10 @@ class AndroidEmulator(object): f.write(line) def _telnet_cmd(self, telnet, command): - self._log_debug(">>> " + command) + _log_debug(">>> " + command) telnet.write('%s\n' % command) result = telnet.read_until('OK', 10) - self._log_debug("<<< " + result) + _log_debug("<<< " + result) return result def _verify_emulator(self): @@ -411,16 +431,16 @@ class AndroidEmulator(object): tn.read_all() telnet_ok = True else: - self._log_warning("Unable to connect to port %d" % port) + _log_warning("Unable to connect to port %d" % port) except: - self._log_warning("Trying again after unexpected exception") + _log_warning("Trying again after unexpected exception") finally: if tn is not None: tn.close() if not telnet_ok: time.sleep(10) if self.proc.proc.poll() is not None: - self._log_warning("Emulator has already completed!") + _log_warning("Emulator has already completed!") return False return telnet_ok @@ -430,25 +450,25 @@ class AndroidEmulator(object): try: tn = telnetlib.Telnet('localhost', self.avd_info.sut_port, 10) if tn is not None: - self._log_debug( + _log_debug( "Connected to port %d" % self.avd_info.sut_port) res = tn.read_until('$>', 10) if res.find('$>') == -1: - self._log_debug("Unexpected SUT response: %s" % res) + _log_debug("Unexpected SUT response: %s" % res) else: - self._log_debug("SUT response: %s" % res) + _log_debug("SUT response: %s" % res) sut_ok = True tn.write('quit\n') tn.read_all() except: - self._log_debug("Caught exception while verifying sutagent") + _log_debug("Caught exception while verifying sutagent") finally: if tn is not None: tn.close() if not sut_ok: time.sleep(10) if self.proc.proc.poll() is not None: - self._log_warning("Emulator has already completed!") + _log_warning("Emulator has already completed!") return False return sut_ok @@ -471,26 +491,19 @@ class AndroidEmulator(object): var = 'ANDROID_PLATFORM_TOOLS' found = False - # Is exe on PATH? - exe_path = find_executable(exe) - if exe_path: - found = True - else: - self._log_debug("Unable to find executable on PATH") - if not found: - # Can exe be found in the Android SDK? - try: - android_sdk_root = os.environ['ANDROID_SDK_ROOT'] - exe_path = os.path.join( - android_sdk_root, subdir, exe) - if os.path.exists(exe_path): - found = True - else: - self._log_debug( - "Unable to find executable at %s" % exe_path) - except KeyError: - self._log_debug("ANDROID_SDK_ROOT not set") + # Can exe be found in the Android SDK? + try: + android_sdk_root = os.environ['ANDROID_SDK_ROOT'] + exe_path = os.path.join( + android_sdk_root, subdir, exe) + if os.path.exists(exe_path): + found = True + else: + _log_debug( + "Unable to find executable at %s" % exe_path) + except KeyError: + _log_debug("ANDROID_SDK_ROOT not set") if not found and self.substs: # Can exe be found in ANDROID_TOOLS/ANDROID_PLATFORM_TOOLS? @@ -500,23 +513,71 @@ class AndroidEmulator(object): if os.path.exists(exe_path): found = True else: - self._log_debug( + _log_debug( "Unable to find executable at %s" % exe_path) except KeyError: - self._log_debug("%s not set" % var) + _log_debug("%s not set" % var) if not found: # Can exe be found in the default bootstrap location? + mozbuild_path = os.environ.get('MOZBUILD_STATE_PATH', + os.path.expanduser(os.path.join('~', '.mozbuild'))) exe_path = os.path.join( - '~', '.mozbuild', 'android-sdk-linux', subdir, exe) + mozbuild_path, 'android-sdk-linux', subdir, exe) if os.path.exists(exe_path): found = True else: - self._log_debug( + _log_debug( "Unable to find executable at %s" % exe_path) + if not found: + # Is exe on PATH? + exe_path = find_executable(exe) + if exe_path: + found = True + else: + _log_debug("Unable to find executable on PATH") + if found: - self._log_debug("%s found at %s" % (exe, exe_path)) + _log_debug("%s found at %s" % (exe, exe_path)) else: exe_path = None return exe_path + +def _log_debug(text): + if verbose_logging: + print "DEBUG: %s" % text + +def _log_warning(text): + print "WARNING: %s" % text + +def _log_info(text): + print "%s" % text + +def _download_file(url, filename, path): + f = urllib2.urlopen(url) + if not os.path.isdir(path): + try: + os.makedirs(path) + except Exception, e: + _log_warning(str(e)) + return False + local_file = open(os.path.join(path, filename), 'wb') + local_file.write(f.read()) + local_file.close() + _log_debug("Downloaded %s to %s/%s" % (url, path, filename)) + return True + +def _tooltool_fetch(): + def outputHandler(line): + _log_debug(line) + command = ['python', 'tooltool.py', 'fetch', '-o', '-m', 'releng.manifest'] + proc = ProcessHandler( + command, processOutputLine=outputHandler, storeOutput=False, + cwd=EMULATOR_HOME_DIR) + proc.run() + try: + proc.wait() + except: + if proc.poll() is None: + proc.kill(signal.SIGTERM) diff --git a/testing/mozharness/configs/android/android_panda_releng.py b/testing/mozharness/configs/android/android_panda_releng.py index 3abec99342..99428c5b33 100644 --- a/testing/mozharness/configs/android/android_panda_releng.py +++ b/testing/mozharness/configs/android/android_panda_releng.py @@ -14,8 +14,6 @@ config = { "verify_path": "/builds/sut_tools/verify.py", "install_app_path": "/builds/sut_tools/installApp.py", "logcat_path": "/builds/sut_tools/logcat.py", - # test harness options are located in the goanna tree - "in_tree_config": "config/mozharness/android_panda_config.py", "all_mochitest_suites": { "mochitest-1": ["--total-chunks=8", "--this-chunk=1"], "mochitest-2": ["--total-chunks=8", "--this-chunk=2"], @@ -74,6 +72,140 @@ config = { "http://pypi.pvt.build.mozilla.org/pub", "http://pypi.pub.build.mozilla.org/pub", ], + "suite_definitions": { + "cppunittest": { + "options": [ + "--symbols-path=%(symbols_path)s", + "--xre-path=tests/bin", + "--dm_trans=sut", + "--deviceIP=%(device_ip)s", + "--localBinDir=../tests/bin", + "--apk=%(apk_path)s", + "--skip-manifest=../tests/cppunittests/android_cppunittest_manifest.txt" + ], + "run_filename": "remotecppunittests.py", + "testsdir": "cppunittest" + }, + "crashtest": { + "options": [ + "--deviceIP=%(device_ip)s", + "--xre-path=../hostutils/xre", + "--utility-path=../hostutils/bin", + "--app=%(app_name)s", + "--ignore-window-size", + "--bootstrap", + "--http-port=%(http_port)s", + "--ssl-port=%(ssl_port)s", + "--symbols-path=%(symbols_path)s", + "reftest/tests/testing/crashtest/crashtests.list" + ], + "run_filename": "remotereftest.py", + "testsdir": "reftest" + }, + "jittest": { + "options": [ + "bin/js", + "--remote", + "-j", + "1", + "--deviceTransport=sut", + "--deviceIP=%(device_ip)s", + "--localLib=../tests/bin", + "--no-slow", + "--no-progress", + "--format=automation", + "--jitflags=all" + ], + "run_filename": "jit_test.py", + "testsdir": "jit-test/jit-test" + }, + "jsreftest": { + "options": [ + "--deviceIP=%(device_ip)s", + "--xre-path=../hostutils/xre", + "--utility-path=../hostutils/bin", + "--app=%(app_name)s", + "--ignore-window-size", + "--bootstrap", + "--extra-profile-file=jsreftest/tests/user.js", + "jsreftest/tests/jstests.list", + "--http-port=%(http_port)s", + "--ssl-port=%(ssl_port)s", + "--symbols-path=%(symbols_path)s" + ], + "run_filename": "remotereftest.py", + "testsdir": "reftest" + }, + "mochitest": { + "options": [ + "--dm_trans=sut", + "--deviceIP=%(device_ip)s", + "--xre-path=../hostutils/xre", + "--utility-path=../hostutils/bin", + "--certificate-path=certs", + "--app=%(app_name)s", + "--http-port=%(http_port)s", + "--ssl-port=%(ssl_port)s", + "--symbols-path=%(symbols_path)s", + "--quiet", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--screenshot-on-fail", + ], + "run_filename": "runtestsremote.py", + "testsdir": "mochitest" + }, + "reftest": { + "options": [ + "--deviceIP=%(device_ip)s", + "--xre-path=../hostutils/xre", + "--utility-path=../hostutils/bin", + "--app=%(app_name)s", + "--ignore-window-size", + "--bootstrap", + "--http-port=%(http_port)s", + "--ssl-port=%(ssl_port)s", + "--symbols-path=%(symbols_path)s", + "reftest/tests/layout/reftests/reftest.list" + ], + "run_filename": "remotereftest.py", + "testsdir": "reftest" + }, + "robocop": { + "options": [ + "--dm_trans=sut", + "--deviceIP=%(device_ip)s", + "--xre-path=../hostutils/xre", + "--utility-path=../hostutils/bin", + "--certificate-path=certs", + "--app=%(app_name)s", + "--console-level=INFO", + "--http-port=%(http_port)s", + "--ssl-port=%(ssl_port)s", + "--symbols-path=%(symbols_path)s", + "--robocop-ini=mochitest/robocop.ini" + ], + "run_filename": "runrobocop.py", + "testsdir": "mochitest" + }, + "xpcshell": { + "options": [ + "--deviceIP=%(device_ip)s", + "--xre-path=../hostutils/xre", + "--manifest=xpcshell/tests/xpcshell.ini", + "--build-info-json=xpcshell/mozinfo.json", + "--testing-modules-dir=modules", + "--local-lib-dir=../fennec", + "--apk=../%(apk_name)s", + "--no-logfiles", + "--symbols-path=%(symbols_path)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + ], + "run_filename": "remotexpcshelltests.py", + "testsdir": "xpcshell" + } + }, "pip_index": False, "buildbot_json_path": "buildprops.json", "mobile_imaging_format": "http://mobile-imaging", diff --git a/testing/mozharness/configs/android/androidarm.py b/testing/mozharness/configs/android/androidarm.py index 44d971222e..d8786a1d29 100644 --- a/testing/mozharness/configs/android/androidarm.py +++ b/testing/mozharness/configs/android/androidarm.py @@ -54,6 +54,156 @@ config = { "sut_port1": 20701, "sut_port2": 20700 }, + "suite_definitions": { + "mochitest": { + "run_filename": "runtestsremote.py", + "testsdir": "mochitest", + "options": [ + "--dm_trans=sut", + "--app=%(app)s", + "--remote-webserver=%(remote_webserver)s", + "--xre-path=%(xre_path)s", + "--utility-path=%(utility_path)s", + "--deviceIP=%(device_ip)s", + "--devicePort=%(device_port)s", + "--http-port=%(http_port)s", + "--ssl-port=%(ssl_port)s", + "--certificate-path=%(certs_path)s", + "--symbols-path=%(symbols_path)s", + "--quiet", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--screenshot-on-fail", + ], + }, + "mochitest-gl": { + "run_filename": "runtestsremote.py", + "testsdir": "mochitest", + "options": [ + "--dm_trans=sut", + "--app=%(app)s", + "--remote-webserver=%(remote_webserver)s", + "--xre-path=%(xre_path)s", + "--utility-path=%(utility_path)s", + "--deviceIP=%(device_ip)s", + "--devicePort=%(device_port)s", + "--http-port=%(http_port)s", + "--ssl-port=%(ssl_port)s", + "--certificate-path=%(certs_path)s", + "--symbols-path=%(symbols_path)s", + "--quiet", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--screenshot-on-fail", + "--total-chunks=4", + "--subsuite=webgl", + ], + }, + "robocop": { + "run_filename": "runrobocop.py", + "testsdir": "mochitest", + "options": [ + "--dm_trans=sut", + "--app=%(app)s", + "--remote-webserver=%(remote_webserver)s", + "--xre-path=%(xre_path)s", + "--utility-path=%(utility_path)s", + "--deviceIP=%(device_ip)s", + "--devicePort=%(device_port)s", + "--http-port=%(http_port)s", + "--ssl-port=%(ssl_port)s", + "--certificate-path=%(certs_path)s", + "--symbols-path=%(symbols_path)s", + "--quiet", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--total-chunks=4", + "--robocop-apk=../../robocop.apk", + "--robocop-ini=robocop.ini", + ], + }, + "reftest": { + "run_filename": "remotereftest.py", + "testsdir": "reftest", + "options": [ + "--app=%(app)s", + "--ignore-window-size", + "--bootstrap", + "--remote-webserver=%(remote_webserver)s", + "--xre-path=%(xre_path)s", + "--utility-path=%(utility_path)s", + "--deviceIP=%(device_ip)s", + "--devicePort=%(device_port)s", + "--http-port=%(http_port)s", + "--ssl-port=%(ssl_port)s", + "--httpd-path", + "%(modules_dir)s", + "--symbols-path=%(symbols_path)s", + "--total-chunks=16", + "tests/layout/reftests/reftest.list", + ], + }, + "crashtest": { + "run_filename": "remotereftest.py", + "testsdir": "reftest", + "options": [ + "--app=%(app)s", + "--ignore-window-size", + "--bootstrap", + "--remote-webserver=%(remote_webserver)s", + "--xre-path=%(xre_path)s", + "--utility-path=%(utility_path)s", + "--deviceIP=%(device_ip)s", + "--devicePort=%(device_port)s", + "--http-port=%(http_port)s", + "--ssl-port=%(ssl_port)s", + "--httpd-path", + "%(modules_dir)s", + "--symbols-path=%(symbols_path)s", + "--total-chunks=2", + "tests/testing/crashtest/crashtests.list", + ], + }, + "jsreftest": { + "run_filename": "remotereftest.py", + "testsdir": "reftest", + "options": [ + "--app=%(app)s", + "--ignore-window-size", + "--bootstrap", + "--remote-webserver=%(remote_webserver)s", + "--xre-path=%(xre_path)s", + "--utility-path=%(utility_path)s", + "--deviceIP=%(device_ip)s", + "--devicePort=%(device_port)s", + "--http-port=%(http_port)s", + "--ssl-port=%(ssl_port)s", + "--httpd-path", + "%(modules_dir)s", + "--symbols-path=%(symbols_path)s", + "../jsreftest/tests/jstests.list", + "--total-chunks=6", + "--extra-profile-file=jsreftest/tests/user.js", + ], + }, + "xpcshell": { + "run_filename": "remotexpcshelltests.py", + "testsdir": "xpcshell", + "options": [ + "--deviceIP=%(device_ip)s", + "--devicePort=%(device_port)s", + "--xre-path=%(xre_path)s", + "--testing-modules-dir=%(modules_dir)s", + "--apk=%(installer_path)s", + "--no-logfiles", + "--symbols-path=%(symbols_path)s", + "--manifest=tests/xpcshell.ini", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--total-chunks=3", + ], + }, + }, # end suite_definitions "test_suite_definitions": { "jsreftest-1": { "category": "jsreftest", diff --git a/testing/mozharness/configs/android/androidarm_4_3.py b/testing/mozharness/configs/android/androidarm_4_3.py index c48302b906..bd3c1d2cab 100644 --- a/testing/mozharness/configs/android/androidarm_4_3.py +++ b/testing/mozharness/configs/android/androidarm_4_3.py @@ -54,12 +54,160 @@ config = { 'stop-emulator', ], "emulator": { - "name": "test-1", - "device_id": "emulator-5554", - "http_port": "8854", # starting http port to use for the mochitest server - "ssl_port": "4454", # starting ssl port to use for the server - "emulator_port": 5554, + "name": "test-1", + "device_id": "emulator-5554", + "http_port": "8854", # starting http port to use for the mochitest server + "ssl_port": "4454", # starting ssl port to use for the server + "emulator_port": 5554, + }, + "suite_definitions": { + "mochitest": { + "run_filename": "runtestsremote.py", + "testsdir": "mochitest", + "options": [ + "--dm_trans=adb", + "--app=%(app)s", + "--remote-webserver=%(remote_webserver)s", + "--xre-path=%(xre_path)s", + "--utility-path=%(utility_path)s", + "--http-port=%(http_port)s", + "--ssl-port=%(ssl_port)s", + "--certificate-path=%(certs_path)s", + "--symbols-path=%(symbols_path)s", + "--quiet", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--screenshot-on-fail", + ], }, + "mochitest-gl": { + "run_filename": "runtestsremote.py", + "testsdir": "mochitest", + "options": [ + "--dm_trans=adb", + "--app=%(app)s", + "--remote-webserver=%(remote_webserver)s", + "--xre-path=%(xre_path)s", + "--utility-path=%(utility_path)s", + "--http-port=%(http_port)s", + "--ssl-port=%(ssl_port)s", + "--certificate-path=%(certs_path)s", + "--symbols-path=%(symbols_path)s", + "--quiet", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--screenshot-on-fail", + "--total-chunks=4", + "--subsuite=webgl", + ], + }, + "robocop": { + "run_filename": "runrobocop.py", + "testsdir": "mochitest", + "options": [ + "--dm_trans=adb", + "--app=%(app)s", + "--remote-webserver=%(remote_webserver)s", + "--xre-path=%(xre_path)s", + "--utility-path=%(utility_path)s", + "--http-port=%(http_port)s", + "--ssl-port=%(ssl_port)s", + "--certificate-path=%(certs_path)s", + "--symbols-path=%(symbols_path)s", + "--quiet", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--total-chunks=4", + "--robocop-apk=../../robocop.apk", + "--robocop-ini=robocop.ini", + ], + }, + "reftest": { + "run_filename": "remotereftest.py", + "testsdir": "reftest", + "options": [ + "--app=%(app)s", + "--ignore-window-size", + "--dm_trans=adb", + "--bootstrap", + "--remote-webserver=%(remote_webserver)s", + "--xre-path=%(xre_path)s", + "--utility-path=%(utility_path)s", + "--http-port=%(http_port)s", + "--ssl-port=%(ssl_port)s", + "--httpd-path", "%(modules_dir)s", + "--symbols-path=%(symbols_path)s", + "--total-chunks=16", + "tests/layout/reftests/reftest.list", + ], + }, + "crashtest": { + "run_filename": "remotereftest.py", + "testsdir": "reftest", + "options": [ + "--app=%(app)s", + "--ignore-window-size", + "--dm_trans=adb", + "--bootstrap", + "--remote-webserver=%(remote_webserver)s", + "--xre-path=%(xre_path)s", + "--utility-path=%(utility_path)s", + "--http-port=%(http_port)s", + "--ssl-port=%(ssl_port)s", + "--httpd-path", + "%(modules_dir)s", + "--symbols-path=%(symbols_path)s", + "--total-chunks=2", + "tests/testing/crashtest/crashtests.list", + ], + }, + "jsreftest": { + "run_filename": "remotereftest.py", + "testsdir": "reftest", + "options": [ + "--app=%(app)s", + "--ignore-window-size", + "--dm_trans=adb", + "--bootstrap", + "--remote-webserver=%(remote_webserver)s", "--xre-path=%(xre_path)s", + "--utility-path=%(utility_path)s", "--http-port=%(http_port)s", + "--ssl-port=%(ssl_port)s", "--httpd-path", "%(modules_dir)s", + "--symbols-path=%(symbols_path)s", + "../jsreftest/tests/jstests.list", + "--total-chunks=6", + "--extra-profile-file=jsreftest/tests/user.js", + ], + }, + "xpcshell": { + "run_filename": "remotexpcshelltests.py", + "testsdir": "xpcshell", + "options": [ + "--dm_trans=adb", + "--xre-path=%(xre_path)s", + "--testing-modules-dir=%(modules_dir)s", + "--apk=%(installer_path)s", + "--no-logfiles", + "--symbols-path=%(symbols_path)s", + "--manifest=tests/xpcshell.ini", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--total-chunks=3", + ], + }, + "cppunittest": { + "run_filename": "remotecppunittests.py", + "testsdir": "cppunittest", + "options": [ + "--symbols-path=%(symbols_path)s", + "--xre-path=%(xre_path)s", + "--dm_trans=adb", + "--localBinDir=../bin", + "--apk=%(installer_path)s", + ".", + ], + }, + + }, # end suite_definitions "test_suite_definitions": { "jsreftest-1": { "category": "jsreftest", diff --git a/testing/mozharness/configs/android/androidx86.py b/testing/mozharness/configs/android/androidx86.py index 8b303c4262..281feef96b 100644 --- a/testing/mozharness/configs/android/androidx86.py +++ b/testing/mozharness/configs/android/androidx86.py @@ -81,6 +81,57 @@ config = { "sut_port2": 20706 } ], + "suite_definitions": { + "mochitest": { + "run_filename": "runtestsremote.py", + "options": ["--dm_trans=sut", + "--app=%(app)s", + "--remote-webserver=%(remote_webserver)s", + "--xre-path=%(xre_path)s", + "--utility-path=%(utility_path)s", + "--deviceIP=%(device_ip)s", + "--devicePort=%(device_port)s", + "--http-port=%(http_port)s", + "--ssl-port=%(ssl_port)s", + "--certificate-path=%(certs_path)s", + "--symbols-path=%(symbols_path)s", + "--quiet", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--screenshot-on-fail", + ], + }, + "reftest": { + "run_filename": "remotereftest.py", + "options": ["--app=%(app)s", + "--ignore-window-size", + "--bootstrap", + "--remote-webserver=%(remote_webserver)s", + "--xre-path=%(xre_path)s", + "--utility-path=%(utility_path)s", + "--deviceIP=%(device_ip)s", + "--devicePort=%(device_port)s", + "--http-port=%(http_port)s", + "--ssl-port=%(ssl_port)s", + "--httpd-path", "%(modules_dir)s", + "--symbols-path=%(symbols_path)s", + ], + }, + "xpcshell": { + "run_filename": "remotexpcshelltests.py", + "options": ["--deviceIP=%(device_ip)s", + "--devicePort=%(device_port)s", + "--xre-path=%(xre_path)s", + "--testing-modules-dir=%(modules_dir)s", + "--apk=%(installer_path)s", + "--no-logfiles", + "--symbols-path=%(symbols_path)s", + "--manifest=tests/xpcshell.ini", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + ], + }, + }, # end suite_definitions "test_suite_definitions": { "jsreftest": { "category": "reftest", diff --git a/testing/mozharness/configs/b2g/desktop_automation_config.py b/testing/mozharness/configs/b2g/desktop_automation_config.py index b443e3374b..80c3c3f6b2 100644 --- a/testing/mozharness/configs/b2g/desktop_automation_config.py +++ b/testing/mozharness/configs/b2g/desktop_automation_config.py @@ -40,6 +40,39 @@ config = { "mochitest": "runtestsb2g.py", "reftest": "runreftestb2g.py", }, - # test harness options are located in the goanna tree - "in_tree_config": "config/mozharness/b2g_desktop_config.py", + "suite_definitions": { + "mochitest": { + "options": [ + "--total-chunks=%(total_chunks)s", + "--this-chunk=%(this_chunk)s", + "--profile=%(gaia_profile)s", + "--app=%(application)s", + "--desktop", + "--utility-path=%(utility_path)s", + "--certificate-path=%(cert_path)s", + "--symbols-path=%(symbols_path)s", + "--browser-arg=%(browser_arg)s", + "--quiet", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--screenshot-on-fail", + ], + "run_filename": "runtestsb2g.py", + "testsdir": "mochitest" + }, + "reftest": { + "options": [ + "--desktop", + "--profile=%(gaia_profile)s", + "--appname=%(application)s", + "--total-chunks=%(total_chunks)s", + "--this-chunk=%(this_chunk)s", + "--browser-arg=%(browser_arg)s", + "--symbols-path=%(symbols_path)s", + "%(test_manifest)s" + ], + "run_filename": "runreftestsb2g.py", + "testsdir": "reftest" + } + }, } diff --git a/testing/mozharness/configs/b2g/emulator_automation_config.py b/testing/mozharness/configs/b2g/emulator_automation_config.py index f2042bf622..efe8254997 100644 --- a/testing/mozharness/configs/b2g/emulator_automation_config.py +++ b/testing/mozharness/configs/b2g/emulator_automation_config.py @@ -46,7 +46,147 @@ config = { "xpcshell": "runtestsb2g.py", "cppunittest": "remotecppunittests.py" }, - # test harness options are located in the goanna tree - "in_tree_config": "config/mozharness/b2g_emulator_config.py", + "suite_definitions": { + "cppunittest": { + "options": [ + "--dm_trans=adb", + "--symbols-path=%(symbols_path)s", + "--xre-path=%(xre_path)s", + "--addEnv", + "LD_LIBRARY_PATH=/vendor/lib:/system/lib:/system/b2g", + "--with-b2g-emulator=%(b2gpath)s", + "--emulator=%(emulator)s", + "." + ], + "run_filename": "remotecppunittests.py", + "testsdir": "cppunittest" + }, + "crashtest": { + "options": [ + "--adbpath=%(adbpath)s", + "--b2gpath=%(b2gpath)s", + "--emulator=%(emulator)s", + "--emulator-res=800x1000", + "--logdir=%(logcat_dir)s", + "--remote-webserver=%(remote_webserver)s", + "--ignore-window-size", + "--xre-path=%(xre_path)s", + "--symbols-path=%(symbols_path)s", + "--busybox=%(busybox)s", + "--total-chunks=%(total_chunks)s", + "--this-chunk=%(this_chunk)s", + "--suite=crashtest", + ], + "tests": ["tests/testing/crashtest/crashtests.list",], + "run_filename": "runreftestb2g.py", + "testsdir": "reftest" + }, + "jsreftest": { + "options": [ + "--adbpath=%(adbpath)s", + "--b2gpath=%(b2gpath)s", + "--emulator=%(emulator)s", + "--emulator-res=800x1000", + "--logdir=%(logcat_dir)s", + "--remote-webserver=%(remote_webserver)s", + "--ignore-window-size", + "--xre-path=%(xre_path)s", + "--symbols-path=%(symbols_path)s", + "--busybox=%(busybox)s", + "--total-chunks=%(total_chunks)s", + "--this-chunk=%(this_chunk)s", + "--extra-profile-file=jsreftest/tests/user.js", + ], + "tests": ["jsreftest/tests/jstests.list",], + "run_filename": "remotereftest.py", + "testsdir": "reftest" + }, + "mochitest": { + "options": [ + "--adbpath=%(adbpath)s", + "--b2gpath=%(b2gpath)s", + "--emulator=%(emulator)s", + "--logdir=%(logcat_dir)s", + "--remote-webserver=%(remote_webserver)s", + "--xre-path=%(xre_path)s", + "--utility-path=%(utility_path)s", + "--symbols-path=%(symbols_path)s", + "--busybox=%(busybox)s", + "--total-chunks=%(total_chunks)s", + "--this-chunk=%(this_chunk)s", + "--quiet", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--certificate-path=%(certificate_path)s", + "--screenshot-on-fail", + ], + "tests": ["%(test_path)s"], + "run_filename": "runtestsb2g.py", + "testsdir": "mochitest" + }, + "mochitest-chrome": { + "options": [ + "--adbpath=%(adbpath)s", + "--b2gpath=%(b2gpath)s", + "--emulator=%(emulator)s", + "--logdir=%(logcat_dir)s", + "--remote-webserver=%(remote_webserver)s", + "--xre-path=%(xre_path)s", + "--utility-path=%(utility_path)s", + "--symbols-path=%(symbols_path)s", + "--busybox=%(busybox)s", + "--total-chunks=%(total_chunks)s", + "--this-chunk=%(this_chunk)s", + "--quiet", + "--chrome", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--certificate-path=%(certificate_path)s", + "--screenshot-on-fail", + ], + "tests": ["%(test_path)s"], + "run_filename": "runtestsb2g.py", + "testsdir": "mochitest" + }, + "reftest": { + "options": [ + "--adbpath=%(adbpath)s", + "--b2gpath=%(b2gpath)s", + "--emulator=%(emulator)s", + "--emulator-res=800x1000", + "--logdir=%(logcat_dir)s", + "--remote-webserver=%(remote_webserver)s", + "--ignore-window-size", + "--xre-path=%(xre_path)s", + "--symbols-path=%(symbols_path)s", + "--busybox=%(busybox)s", + "--total-chunks=%(total_chunks)s", + "--this-chunk=%(this_chunk)s", + "--enable-oop", + ], + "tests": ["tests/layout/reftests/reftest.list",], + "run_filename": "runreftestsb2g.py", + "testsdir": "reftest" + }, + "xpcshell": { + "options": [ + "--adbpath=%(adbpath)s", + "--b2gpath=%(b2gpath)s", + "--emulator=%(emulator)s", + "--logdir=%(logcat_dir)s", + "--manifest=tests/xpcshell.ini", + "--use-device-libs", + "--testing-modules-dir=%(modules_dir)s", + "--symbols-path=%(symbols_path)s", + "--busybox=%(busybox)s", + "--total-chunks=%(total_chunks)s", + "--this-chunk=%(this_chunk)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + ], + "run_filename": "runtestsb2g.py", + "testsdir": "xpcshell" + } + }, "vcs_output_timeout": 1760, } diff --git a/testing/mozharness/configs/b2g/mulet_config.py b/testing/mozharness/configs/b2g/mulet_config.py index 4d718123d9..548dd68aa9 100644 --- a/testing/mozharness/configs/b2g/mulet_config.py +++ b/testing/mozharness/configs/b2g/mulet_config.py @@ -9,5 +9,18 @@ config = { 'install', 'run-tests', ], - "in_tree_config": "config/mozharness/linux_mulet_config.py", + # testsuite options + "reftest_options": [ + "--mulet", + "--profile=%(gaia_profile)s", + "--appname=%(application)s", + "--total-chunks=%(total_chunks)s", + "--this-chunk=%(this_chunk)s", + "--symbols-path=%(symbols_path)s", + "--enable-oop", + "%(test_manifest)s" + ], + "run_file_names": { + "reftest": "runreftestb2g.py", + }, } diff --git a/testing/mozharness/configs/luciddream/linux_config.py b/testing/mozharness/configs/luciddream/linux_config.py index bbb5c5c2e5..566f305c3f 100644 --- a/testing/mozharness/configs/luciddream/linux_config.py +++ b/testing/mozharness/configs/luciddream/linux_config.py @@ -29,7 +29,29 @@ config = { ], "pip_index": False, - "in_tree_config": "config/mozharness/linux_config.py", + "suite_definitions": { + "luciddream-emulator": { + "options": [ + "--startup-timeout=300", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--browser-path=%(browser_path)s", + "--b2gpath=%(emulator_path)s", + "%(test_manifest)s" + ], + }, + "luciddream-b2gdt": { + "options": [ + "--startup-timeout=300", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--browser-path=%(browser_path)s", + "--b2g-desktop-path=%(fxos_desktop_path)s", + "--gaia-profile=%(gaia_profile)s", + "%(test_manifest)s" + ], + }, + }, "buildbot_json_path": "buildprops.json", @@ -37,8 +59,6 @@ config = { "https://blobupload.elasticbeanstalk.com", ], "blob_uploader_auth_file": os.path.join(os.getcwd(), "oauth.txt"), - # will handle in-tree config as subsequent patch - # "in_tree_config": "config/mozharness/luciddream.py", "download_symbols": "ondemand", "download_minidump_stackwalk": True, "tooltool_cache": "/builds/tooltool_cache", diff --git a/testing/mozharness/configs/marionette/automation_emulator_config.py b/testing/mozharness/configs/marionette/automation_emulator_config.py index ba8bd2f6e3..346d4f4b4d 100644 --- a/testing/mozharness/configs/marionette/automation_emulator_config.py +++ b/testing/mozharness/configs/marionette/automation_emulator_config.py @@ -1,6 +1,7 @@ # This is a template config file for marionette production. import os + HG_SHARE_BASE_DIR = "/builds/hg-shared" config = { @@ -39,5 +40,90 @@ config = { "https://blobupload.elasticbeanstalk.com", ], "blob_uploader_auth_file" : os.path.join(os.getcwd(), "oauth.txt"), - "in_tree_config": "config/mozharness/marionette.py", + }, + "suite_definitions": { + "gaiatest_desktop": { + "options": [ + "--restart", + "--timeout=%(timeout)s", + "--type=%(type)s", + "--testvars=%(testvars)s", + "--profile=%(profile)s", + "--symbols-path=%(symbols_path)s", + "--gecko-log=%(gecko_log)s", + "--xml-output=%(xml_output)s", + "--html-output=%(html_output)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--binary=%(binary)s", + "--address=%(address)s", + "--total-chunks=%(total_chunks)s", + "--this-chunk=%(this_chunk)s" + ], + "run_filename": "", + "testsdir": "" + }, + "gaiatest_emulator": { + "options": [ + "--restart", + "--timeout=%(timeout)s", + "--type=%(type)s", + "--testvars=%(testvars)s", + "--profile=%(profile)s", + "--symbols-path=%(symbols_path)s", + "--xml-output=%(xml_output)s", + "--html-output=%(html_output)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--logcat-dir=%(logcat_dir)s", + "--emulator=%(emulator)s", + "--homedir=%(homedir)s" + ], + "run_filename": "", + "testsdir": "" + }, + "marionette_desktop": { + "options": [ + "--type=%(type)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--binary=%(binary)s", + "--address=%(address)s", + "--symbols-path=%(symbols_path)s" + ], + "run_filename": "", + "testsdir": "" + }, + "marionette_emulator": { + "options": [ + "--type=%(type)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--logcat-dir=%(logcat_dir)s", + "--emulator=%(emulator)s", + "--homedir=%(homedir)s", + "--symbols-path=%(symbols_path)s" + ], + "run_filename": "", + "testsdir": "" + }, + "webapi_desktop": { + "options": [], + "run_filename": "", + "testsdir": "" + }, + "webapi_emulator": { + "options": [ + "--type=%(type)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--symbols-path=%(symbols_path)s", + "--logcat-dir=%(logcat_dir)s", + "--emulator=%(emulator)s", + "--homedir=%(homedir)s" + ], + "run_filename": "", + "testsdir": "" + } + }, } diff --git a/testing/mozharness/configs/marionette/gaia_ui_test_prod_config.py b/testing/mozharness/configs/marionette/gaia_ui_test_prod_config.py index 2de32d461b..5b41c1f77e 100644 --- a/testing/mozharness/configs/marionette/gaia_ui_test_prod_config.py +++ b/testing/mozharness/configs/marionette/gaia_ui_test_prod_config.py @@ -2,6 +2,7 @@ import os import platform + HG_SHARE_BASE_DIR = "/builds/hg-shared" if platform.system().lower() == 'darwin': @@ -48,6 +49,90 @@ config = { ], "blob_uploader_auth_file": os.path.join(os.getcwd(), "oauth.txt"), "vcs_output_timeout": 1760, - "in_tree_config": "config/mozharness/marionette.py", "tooltool_cache": "/builds/tooltool_cache", + "suite_definitions": { + "gaiatest_desktop": { + "options": [ + "--restart", + "--timeout=%(timeout)s", + "--type=%(type)s", + "--testvars=%(testvars)s", + "--profile=%(profile)s", + "--symbols-path=%(symbols_path)s", + "--gecko-log=%(gecko_log)s", + "--xml-output=%(xml_output)s", + "--html-output=%(html_output)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--binary=%(binary)s", + "--address=%(address)s", + "--total-chunks=%(total_chunks)s", + "--this-chunk=%(this_chunk)s" + ], + "run_filename": "", + "testsdir": "" + }, + "gaiatest_emulator": { + "options": [ + "--restart", + "--timeout=%(timeout)s", + "--type=%(type)s", + "--testvars=%(testvars)s", + "--profile=%(profile)s", + "--symbols-path=%(symbols_path)s", + "--xml-output=%(xml_output)s", + "--html-output=%(html_output)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--logcat-dir=%(logcat_dir)s", + "--emulator=%(emulator)s", + "--homedir=%(homedir)s" + ], + "run_filename": "", + "testsdir": "" + }, + "marionette_desktop": { + "options": [ + "--type=%(type)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--binary=%(binary)s", + "--address=%(address)s", + "--symbols-path=%(symbols_path)s" + ], + "run_filename": "", + "testsdir": "" + }, + "marionette_emulator": { + "options": [ + "--type=%(type)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--logcat-dir=%(logcat_dir)s", + "--emulator=%(emulator)s", + "--homedir=%(homedir)s", + "--symbols-path=%(symbols_path)s" + ], + "run_filename": "", + "testsdir": "" + }, + "webapi_desktop": { + "options": [], + "run_filename": "", + "testsdir": "" + }, + "webapi_emulator": { + "options": [ + "--type=%(type)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--symbols-path=%(symbols_path)s", + "--logcat-dir=%(logcat_dir)s", + "--emulator=%(emulator)s", + "--homedir=%(homedir)s" + ], + "run_filename": "", + "testsdir": "" + } + }, } diff --git a/testing/mozharness/configs/marionette/prod_config.py b/testing/mozharness/configs/marionette/prod_config.py index 13d7b2fd82..4342408e97 100644 --- a/testing/mozharness/configs/marionette/prod_config.py +++ b/testing/mozharness/configs/marionette/prod_config.py @@ -36,8 +36,92 @@ config = { "https://blobupload.elasticbeanstalk.com", ], "blob_uploader_auth_file" : os.path.join(os.getcwd(), "oauth.txt"), - "in_tree_config": "config/mozharness/marionette.py", "download_symbols": "ondemand", "download_minidump_stackwalk": True, "tooltool_cache": "/builds/tooltool_cache", + "suite_definitions": { + "gaiatest_desktop": { + "options": [ + "--restart", + "--timeout=%(timeout)s", + "--type=%(type)s", + "--testvars=%(testvars)s", + "--profile=%(profile)s", + "--symbols-path=%(symbols_path)s", + "--gecko-log=%(gecko_log)s", + "--xml-output=%(xml_output)s", + "--html-output=%(html_output)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--binary=%(binary)s", + "--address=%(address)s", + "--total-chunks=%(total_chunks)s", + "--this-chunk=%(this_chunk)s" + ], + "run_filename": "", + "testsdir": "" + }, + "gaiatest_emulator": { + "options": [ + "--restart", + "--timeout=%(timeout)s", + "--type=%(type)s", + "--testvars=%(testvars)s", + "--profile=%(profile)s", + "--symbols-path=%(symbols_path)s", + "--xml-output=%(xml_output)s", + "--html-output=%(html_output)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--logcat-dir=%(logcat_dir)s", + "--emulator=%(emulator)s", + "--homedir=%(homedir)s" + ], + "run_filename": "", + "testsdir": "" + }, + "marionette_desktop": { + "options": [ + "--type=%(type)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--binary=%(binary)s", + "--address=%(address)s", + "--symbols-path=%(symbols_path)s" + ], + "run_filename": "", + "testsdir": "" + }, + "marionette_emulator": { + "options": [ + "--type=%(type)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--logcat-dir=%(logcat_dir)s", + "--emulator=%(emulator)s", + "--homedir=%(homedir)s", + "--symbols-path=%(symbols_path)s" + ], + "run_filename": "", + "testsdir": "" + }, + "webapi_desktop": { + "options": [], + "run_filename": "", + "testsdir": "" + }, + "webapi_emulator": { + "options": [ + "--type=%(type)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--symbols-path=%(symbols_path)s", + "--logcat-dir=%(logcat_dir)s", + "--emulator=%(emulator)s", + "--homedir=%(homedir)s" + ], + "run_filename": "", + "testsdir": "" + } + }, } diff --git a/testing/mozharness/configs/marionette/test_config.py b/testing/mozharness/configs/marionette/test_config.py index 2092b00d79..a04ae37979 100644 --- a/testing/mozharness/configs/marionette/test_config.py +++ b/testing/mozharness/configs/marionette/test_config.py @@ -17,5 +17,89 @@ config = { 'install', 'run-marionette', ], - "in_tree_config": "config/mozharness/marionette.py", + "suite_definitions": { + "gaiatest_desktop": { + "options": [ + "--restart", + "--timeout=%(timeout)s", + "--type=%(type)s", + "--testvars=%(testvars)s", + "--profile=%(profile)s", + "--symbols-path=%(symbols_path)s", + "--gecko-log=%(gecko_log)s", + "--xml-output=%(xml_output)s", + "--html-output=%(html_output)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--binary=%(binary)s", + "--address=%(address)s", + "--total-chunks=%(total_chunks)s", + "--this-chunk=%(this_chunk)s" + ], + "run_filename": "", + "testsdir": "" + }, + "gaiatest_emulator": { + "options": [ + "--restart", + "--timeout=%(timeout)s", + "--type=%(type)s", + "--testvars=%(testvars)s", + "--profile=%(profile)s", + "--symbols-path=%(symbols_path)s", + "--xml-output=%(xml_output)s", + "--html-output=%(html_output)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--logcat-dir=%(logcat_dir)s", + "--emulator=%(emulator)s", + "--homedir=%(homedir)s" + ], + "run_filename": "", + "testsdir": "" + }, + "marionette_desktop": { + "options": [ + "--type=%(type)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--binary=%(binary)s", + "--address=%(address)s", + "--symbols-path=%(symbols_path)s" + ], + "run_filename": "", + "testsdir": "" + }, + "marionette_emulator": { + "options": [ + "--type=%(type)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--logcat-dir=%(logcat_dir)s", + "--emulator=%(emulator)s", + "--homedir=%(homedir)s", + "--symbols-path=%(symbols_path)s" + ], + "run_filename": "", + "testsdir": "" + }, + "webapi_desktop": { + "options": [], + "run_filename": "", + "testsdir": "" + }, + "webapi_emulator": { + "options": [ + "--type=%(type)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--symbols-path=%(symbols_path)s", + "--logcat-dir=%(logcat_dir)s", + "--emulator=%(emulator)s", + "--homedir=%(homedir)s" + ], + "run_filename": "", + "testsdir": "" + } + }, } diff --git a/testing/mozharness/configs/marionette/windows_config.py b/testing/mozharness/configs/marionette/windows_config.py index c54e83eecb..aa76a2f6e4 100644 --- a/testing/mozharness/configs/marionette/windows_config.py +++ b/testing/mozharness/configs/marionette/windows_config.py @@ -39,7 +39,91 @@ config = { "https://blobupload.elasticbeanstalk.com", ], "blob_uploader_auth_file" : os.path.join(os.getcwd(), "oauth.txt"), - "in_tree_config": "config/mozharness/marionette.py", "download_minidump_stackwalk": True, "download_symbols": "ondemand", + "suite_definitions": { + "gaiatest_desktop": { + "options": [ + "--restart", + "--timeout=%(timeout)s", + "--type=%(type)s", + "--testvars=%(testvars)s", + "--profile=%(profile)s", + "--symbols-path=%(symbols_path)s", + "--gecko-log=%(gecko_log)s", + "--xml-output=%(xml_output)s", + "--html-output=%(html_output)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--binary=%(binary)s", + "--address=%(address)s", + "--total-chunks=%(total_chunks)s", + "--this-chunk=%(this_chunk)s" + ], + "run_filename": "", + "testsdir": "" + }, + "gaiatest_emulator": { + "options": [ + "--restart", + "--timeout=%(timeout)s", + "--type=%(type)s", + "--testvars=%(testvars)s", + "--profile=%(profile)s", + "--symbols-path=%(symbols_path)s", + "--xml-output=%(xml_output)s", + "--html-output=%(html_output)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--logcat-dir=%(logcat_dir)s", + "--emulator=%(emulator)s", + "--homedir=%(homedir)s" + ], + "run_filename": "", + "testsdir": "" + }, + "marionette_desktop": { + "options": [ + "--type=%(type)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--binary=%(binary)s", + "--address=%(address)s", + "--symbols-path=%(symbols_path)s" + ], + "run_filename": "", + "testsdir": "" + }, + "marionette_emulator": { + "options": [ + "--type=%(type)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--logcat-dir=%(logcat_dir)s", + "--emulator=%(emulator)s", + "--homedir=%(homedir)s", + "--symbols-path=%(symbols_path)s" + ], + "run_filename": "", + "testsdir": "" + }, + "webapi_desktop": { + "options": [], + "run_filename": "", + "testsdir": "" + }, + "webapi_emulator": { + "options": [ + "--type=%(type)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--symbols-path=%(symbols_path)s", + "--logcat-dir=%(logcat_dir)s", + "--emulator=%(emulator)s", + "--homedir=%(homedir)s" + ], + "run_filename": "", + "testsdir": "" + } + }, } diff --git a/testing/mozharness/configs/unittests/linux_unittest.py b/testing/mozharness/configs/unittests/linux_unittest.py index fda5b1e567..9db5a83fc5 100644 --- a/testing/mozharness/configs/unittests/linux_unittest.py +++ b/testing/mozharness/configs/unittests/linux_unittest.py @@ -55,8 +55,116 @@ config = { "mozbase": ["mozbase/*"], "mozmill": ["mozmill/*"], }, - # test harness options are located in the goanna tree - "in_tree_config": "config/mozharness/linux_config.py", + "suite_definitions": { + "cppunittest": { + "options": [ + "--symbols-path=%(symbols_path)s", + "--xre-path=%(abs_app_dir)s" + ], + "run_filename": "runcppunittests.py", + "testsdir": "cppunittest" + }, + "jittest": { + "options": [ + "tests/bin/js", + "--no-slow", + "--no-progress", + "--format=automation", + "--jitflags=all" + ], + "run_filename": "jit_test.py", + "testsdir": "jit-test/jit-test" + }, + "luciddream-emulator": { + "options": [ + "--startup-timeout=300", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--browser-path=%(browser_path)s", + "--b2gpath=%(emulator_path)s", + "%(test_manifest)s" + ], + }, + "luciddream-b2gdt": { + "options": [ + "--startup-timeout=300", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--browser-path=%(browser_path)s", + "--b2g-desktop-path=%(fxos_desktop_path)s", + "--gaia-profile=%(gaia_profile)s", + "%(test_manifest)s" + ], + }, + "mochitest": { + "options": [ + "--appname=%(binary_path)s", + "--utility-path=tests/bin", + "--extra-profile-file=tests/bin/plugins", + "--symbols-path=%(symbols_path)s", + "--certificate-path=tests/certs", + "--setpref=webgl.force-enabled=true", + "--quiet", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--use-test-media-devices", + "--screenshot-on-fail", + ], + "run_filename": "runtests.py", + "testsdir": "mochitest" + }, + "mozbase": { + "options": [ + "-b", + "%(binary_path)s" + ], + "run_filename": "test.py", + "testsdir": "mozbase" + }, + "mozmill": { + "options": [ + "--binary=%(binary_path)s", + "--symbols-path=%(symbols_path)s" + ], + "run_filename": "runtestlist.py", + "testsdir": "mozmill" + }, + "reftest": { + "options": [ + "--appname=%(binary_path)s", + "--utility-path=tests/bin", + "--extra-profile-file=tests/bin/plugins", + "--symbols-path=%(symbols_path)s" + ], + "run_filename": "runreftest.py", + "testsdir": "reftest" + }, + "webapprt": { + "options": [ + "--app=%(app_path)s", + "--utility-path=tests/bin", + "--extra-profile-file=tests/bin/plugins", + "--symbols-path=%(symbols_path)s", + "--certificate-path=tests/certs", + "--console-level=INFO", + "--testing-modules-dir=tests/modules", + "--quiet" + ], + "run_filename": "runtests.py", + "testsdir": "mochitest" + }, + "xpcshell": { + "options": [ + "--symbols-path=%(symbols_path)s", + "--test-plugin-path=%(test_plugin_path)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--utility-path=tests/bin", + ], + "run_filename": "runxpcshelltests.py", + "testsdir": "xpcshell" + } + }, # local mochi suites "all_mochitest_suites": { "plain1": ["--total-chunks=5", "--this-chunk=1", "--chunk-by-dir=4"], diff --git a/testing/mozharness/configs/unittests/mac_unittest.py b/testing/mozharness/configs/unittests/mac_unittest.py index 5774d02637..9204c35863 100644 --- a/testing/mozharness/configs/unittests/mac_unittest.py +++ b/testing/mozharness/configs/unittests/mac_unittest.py @@ -44,8 +44,104 @@ config = { "mozbase": ["mozbase/*"], "mozmill": ["mozmill/*"], }, - # test harness options are located in the goanna tree - "in_tree_config": "config/mozharness/mac_config.py", + "suite_definitions": { + "cppunittest": { + "options": [ + "--symbols-path=%(symbols_path)s", + "--xre-path=%(abs_res_dir)s" + ], + "run_filename": "runcppunittests.py", + "testsdir": "cppunittest" + }, + "jittest": { + "options": [ + "tests/bin/js", + "--no-slow", + "--no-progress", + "--format=automation", + "--jitflags=all" + ], + "run_filename": "jit_test.py", + "testsdir": "jit-test/jit-test" + }, + "mochitest": { + "options": [ + "--appname=%(binary_path)s", + "--utility-path=tests/bin", + "--extra-profile-file=tests/bin/plugins", + "--symbols-path=%(symbols_path)s", + "--certificate-path=tests/certs", + "--quiet", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--screenshot-on-fail", + ], + "run_filename": "runtests.py", + "testsdir": "mochitest" + }, + "mozbase": { + "options": [ + "-b", + "%(binary_path)s" + ], + "run_filename": "test.py", + "testsdir": "mozbase" + }, + "mozmill": { + "options": [ + "--binary=%(binary_path)s", + "--testing-modules-dir=test/modules", + "--symbols-path=%(symbols_path)s" + ], + "run_filename": "runtestlist.py", + "testsdir": "mozmill" + }, + "reftest": { + "options": [ + "--appname=%(binary_path)s", + "--utility-path=tests/bin", + "--extra-profile-file=tests/bin/plugins", + "--symbols-path=%(symbols_path)s" + ], + "run_filename": "runreftest.py", + "testsdir": "reftest" + }, + "webapprt": { + "options": [ + "--app=%(app_path)s", + "--xre-path=%(abs_res_dir)s", + "--utility-path=tests/bin", + "--extra-profile-file=tests/bin/plugins", + "--symbols-path=%(symbols_path)s", + "--certificate-path=tests/certs", + "--console-level=INFO", + "--testing-modules-dir=tests/modules", + "--quiet" + ], + "run_filename": "runtests.py", + "testsdir": "mochitest" + }, + "xpcshell": { + "options": [ + "--symbols-path=%(symbols_path)s", + "--test-plugin-path=%(test_plugin_path)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--utility-path=tests/bin", + ], + "run_filename": "runxpcshelltests.py", + "testsdir": "xpcshell" + }, + "gtest": { + "options": [ + "--xre-path=%(abs_res_dir)s", + "--cwd=%(gtest_dir)s", + "--symbols-path=%(symbols_path)s", + "%(binary_path)s", + ], + "run_filename": "rungtests.py", + }, + }, # local mochi suites "all_mochitest_suites": { "plain1": ["--total-chunks=5", "--this-chunk=1", "--chunk-by-dir=4"], diff --git a/testing/mozharness/configs/unittests/win_unittest.py b/testing/mozharness/configs/unittests/win_unittest.py index b075aadfff..00a5890a22 100644 --- a/testing/mozharness/configs/unittests/win_unittest.py +++ b/testing/mozharness/configs/unittests/win_unittest.py @@ -53,8 +53,94 @@ config = { "mozbase": ["mozbase/*"], "mozmill": ["mozmill/*"], }, - # test harness options are located in the goanna tree - "in_tree_config": "config/mozharness/windows_config.py", + "suite_definitions": { + "cppunittest": { + "options": [ + "--symbols-path=%(symbols_path)s", + "--xre-path=%(abs_app_dir)s" + ], + "run_filename": "runcppunittests.py", + "testsdir": "cppunittest" + }, + "jittest": { + "options": [ + "tests/bin/js", + "--no-slow", + "--no-progress", + "--format=automation", + "--jitflags=all" + ], + "run_filename": "jit_test.py", + "testsdir": "jit-test/jit-test" + }, + "mochitest": { + "options": [ + "--appname=%(binary_path)s", + "--utility-path=tests/bin", + "--extra-profile-file=tests/bin/plugins", + "--symbols-path=%(symbols_path)s", + "--certificate-path=tests/certs", + "--quiet", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--screenshot-on-fail", + ], + "run_filename": "runtests.py", + "testsdir": "mochitest" + }, + "mozbase": { + "options": [ + "-b", + "%(binary_path)s" + ], + "run_filename": "test.py", + "testsdir": "mozbase" + }, + "mozmill": { + "options": [ + "--binary=%(binary_path)s", + "--symbols-path=%(symbols_path)s" + ], + "run_filename": "runtestlist.py", + "testsdir": "mozmill" + }, + "reftest": { + "options": [ + "--appname=%(binary_path)s", + "--utility-path=tests/bin", + "--extra-profile-file=tests/bin/plugins", + "--symbols-path=%(symbols_path)s" + ], + "run_filename": "runreftest.py", + "testsdir": "reftest" + }, + "webapprt": { + "options": [ + "--app=%(app_path)s", + "--utility-path=tests/bin", + "--extra-profile-file=tests/bin/plugins", + "--symbols-path=%(symbols_path)s", + "--certificate-path=tests/certs", + "--console-level=INFO", + "--testing-modules-dir=tests/modules", + "--quiet" + ], + "run_filename": "runtests.py", + "testsdir": "mochitest" + }, + "xpcshell": { + "options": [ + "--symbols-path=%(symbols_path)s", + "--test-plugin-path=%(test_plugin_path)s", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--utility-path=tests/bin", + ], + "run_filename": "runxpcshelltests.py", + "testsdir": "xpcshell" + } + }, + # local mochi suites "all_mochitest_suites": { diff --git a/testing/mozharness/configs/web_platform_tests/prod_config.py b/testing/mozharness/configs/web_platform_tests/prod_config.py index a5168a8959..552821e221 100644 --- a/testing/mozharness/configs/web_platform_tests/prod_config.py +++ b/testing/mozharness/configs/web_platform_tests/prod_config.py @@ -6,10 +6,15 @@ import os config = { - # test harness options are located in the goanna tree - "in_tree_config": "config/mozharness/web_platform_tests_config.py", - - "options": [], + "options": [ + "--prefs-root=%(test_path)s/prefs", + "--processes=1", + "--config=%(test_path)s/wptrunner.ini", + "--ca-cert-path=%(test_path)s/certs/cacert.pem", + "--host-key-path=%(test_path)s/certs/web-platform.test.key", + "--host-cert-path=%(test_path)s/certs/web-platform.test.pem", + "--certutil-binary=%(test_install_path)s/bin/certutil", + ], "exes": { 'python': '/tools/buildbot/bin/python', diff --git a/testing/mozharness/configs/web_platform_tests/prod_config_windows.py b/testing/mozharness/configs/web_platform_tests/prod_config_windows.py index b673f38d3e..7c0f525feb 100644 --- a/testing/mozharness/configs/web_platform_tests/prod_config_windows.py +++ b/testing/mozharness/configs/web_platform_tests/prod_config_windows.py @@ -10,8 +10,15 @@ import os import sys config = { - # test harness options are located in the goanna tree - "in_tree_config": "config/mozharness/web_platform_tests_config.py", + "options": [ + "--prefs-root=%(test_path)s/prefs", + "--processes=1", + "--config=%(test_path)s/wptrunner.ini", + "--ca-cert-path=%(test_path)s/certs/cacert.pem", + "--host-key-path=%(test_path)s/certs/web-platform.test.key", + "--host-cert-path=%(test_path)s/certs/web-platform.test.pem", + "--certutil-binary=%(test_install_path)s/bin/certutil", + ], "exes": { 'python': sys.executable, @@ -22,8 +29,6 @@ config = { 'tooltool.py': [sys.executable, 'C:/mozilla-build/tooltool.py'], }, - "options": [], - "find_links": [ "http://pypi.pvt.build.mozilla.org/pub", "http://pypi.pub.build.mozilla.org/pub", diff --git a/testing/mozharness/configs/web_platform_tests/test_config.py b/testing/mozharness/configs/web_platform_tests/test_config.py index 094d847923..29dd8014b3 100644 --- a/testing/mozharness/configs/web_platform_tests/test_config.py +++ b/testing/mozharness/configs/web_platform_tests/test_config.py @@ -5,10 +5,15 @@ # ***** END LICENSE BLOCK ***** config = { - # test harness options are located in the goanna tree - "in_tree_config": "config/mozharness/web_platform_tests_config.py", - - "options": [], + "options": [ + "--prefs-root=%(test_path)s/prefs", + "--processes=1", + "--config=%(test_path)s/wptrunner.ini", + "--ca-cert-path=%(test_path)s/certs/cacert.pem", + "--host-key-path=%(test_path)s/certs/web-platform.test.key", + "--host-cert-path=%(test_path)s/certs/web-platform.test.pem", + "--certutil-binary=%(test_install_path)s/bin/certutil", + ], "default_actions": [ 'clobber', diff --git a/testing/mozharness/configs/web_platform_tests/test_config_windows.py b/testing/mozharness/configs/web_platform_tests/test_config_windows.py index 60ad71c19c..d83c136ea2 100644 --- a/testing/mozharness/configs/web_platform_tests/test_config_windows.py +++ b/testing/mozharness/configs/web_platform_tests/test_config_windows.py @@ -8,8 +8,15 @@ import os import sys config = { - # test harness options are located in the goanna tree - "in_tree_config": "config/mozharness/web_platform_tests_config.py", + "options": [ + "--prefs-root=%(test_path)s/prefs", + "--processes=1", + "--config=%(test_path)s/wptrunner.ini", + "--ca-cert-path=%(test_path)s/certs/cacert.pem", + "--host-key-path=%(test_path)s/certs/web-platform.test.key", + "--host-cert-path=%(test_path)s/certs/web-platform.test.pem", + "--certutil-binary=%(test_install_path)s/bin/certutil", + ], "exes": { 'python': sys.executable, @@ -19,8 +26,6 @@ config = { '%s/build/venv/scripts/mozinstall-script.py' % os.getcwd()], }, - "options": [], - "default_actions": [ 'clobber', 'download-and-extract', diff --git a/testing/mozharness/mozharness/mozilla/testing/testbase.py b/testing/mozharness/mozharness/mozilla/testing/testbase.py index c1741d3142..6d3bc0a7e0 100755 --- a/testing/mozharness/mozharness/mozilla/testing/testbase.py +++ b/testing/mozharness/mozharness/mozilla/testing/testbase.py @@ -99,7 +99,6 @@ class TestingMixin(VirtualenvMixin, BuildbotMixin, ResourceMonitoringMixin, Tool test_url = None test_packages_url = None test_zip_path = None - tree_config = ReadOnlyDict({}) symbols_url = None symbols_path = None jsshell_url = None @@ -134,13 +133,6 @@ class TestingMixin(VirtualenvMixin, BuildbotMixin, ResourceMonitoringMixin, Tool else: return self.download_proxied_file(*args, **kwargs) - def query_value(self, key): - """ - This function allows us to check for a value - in the self.tree_config first and then on self.config - """ - return self.tree_config.get(key, self.config.get(key)) - def query_build_dir_url(self, file_name): """ Resolve a file name to a potential url in the build upload directory where @@ -451,52 +443,13 @@ You can set this by: halt_on_failure=True, success_codes=[0, 11], fatal_exit_code=3) - def _read_tree_config(self): - """Reads an in-tree config file""" - dirs = self.query_abs_dirs() - test_install_dir = dirs.get('abs_test_install_dir', - os.path.join(dirs['abs_work_dir'], 'tests')) - - if 'in_tree_config' in self.config: - rel_tree_config_path = self.config['in_tree_config'] - tree_config_path = os.path.join(test_install_dir, rel_tree_config_path) - - if not os.path.isfile(tree_config_path): - self.fatal("The in-tree configuration file '%s' does not exist!" - "It must be added to '%s'. See bug 1035551 for more details." % - (tree_config_path, os.path.join('goanna', 'testing', rel_tree_config_path))) - - try: - self.tree_config.update(parse_config_file(tree_config_path)) - except: - msg = "There was a problem parsing the in-tree configuration file '%s'!" % \ - os.path.join('goanna', 'testing', rel_tree_config_path) - self.exception(message=msg, level=FATAL) - - self.dump_config(file_path=os.path.join(dirs['abs_log_dir'], 'treeconfig.json'), - config=self.tree_config) - - if (self.buildbot_config and 'properties' in self.buildbot_config and - self.buildbot_config['properties'].get('branch') == 'try'): - try_config_path = os.path.join(test_install_dir, 'config', 'mozharness', - 'try_arguments.py') - known_try_arguments = parse_config_file(try_config_path) - comments = self.buildbot_config['sourcestamp']['changes'][-1]['comments'] - if not comments and 'try_syntax' in self.buildbot_config['properties']: - # If we don't find try syntax in the usual place, check for it in an - # alternate property available to tools using self-serve. - comments = self.buildbot_config['properties']['try_syntax'] - self.parse_extra_try_arguments(comments, known_try_arguments) - - self.tree_config.lock() - def structured_output(self, suite_category): """Defines whether structured logging is in use in this configuration. This may need to be replaced with data from a different config at the resolution of bug 1070041 and related bugs. """ - return ('structured_suites' in self.tree_config and - suite_category in self.tree_config['structured_suites']) + return ('structured_suites' in self.config and + suite_category in self.config['structured_suites']) def get_test_output_parser(self, suite_category, strict=False, fallback_parser_class=DesktopUnittestOutputParser, @@ -577,7 +530,6 @@ You can set this by: suite_categories = suite_categories or ['common'] self._download_test_packages(suite_categories, target_unzip_dirs) - self._read_tree_config() self._download_installer() if self.config.get('download_symbols'): self._download_and_extract_symbols() @@ -737,10 +689,6 @@ Did you run with --create-virtualenv? Is mozinstall in virtualenv_modules?""") def preflight_run_tests(self): """preflight commands for all tests""" - # If the in tree config hasn't been loaded by a previous step, load it here. - if len(self.tree_config) == 0: - self._read_tree_config() - c = self.config if c.get('run_cmd_checks_enabled'): self._run_cmd_checks(c.get('preflight_run_cmd_suites', [])) diff --git a/testing/mozharness/mozharness/mozilla/testing/try_tools.py b/testing/mozharness/mozharness/mozilla/testing/try_tools.py index 95e64ed0d8..c4e3c3be56 100644 --- a/testing/mozharness/mozharness/mozilla/testing/try_tools.py +++ b/testing/mozharness/mozharness/mozilla/testing/try_tools.py @@ -9,6 +9,8 @@ import argparse import os import re +from mozharness.base.script import PostScriptAction +from mozharness.base.transfer import TransferMixin class TryToolsMixin(object): """Utility functions for an interface between try syntax and out test harnesses. @@ -16,13 +18,57 @@ class TryToolsMixin(object): harness_extra_args = None try_test_paths = [] + known_try_arguments = { + '--tag': { + 'action': 'append', + 'dest': 'tags', + 'default': None, + }, + } - def parse_extra_try_arguments(self, msg, known_try_arguments): - """Given a commit message, parse to extract additional arguments to pass - on to the test harness command line. + def _extract_try_message(self): + msg = None + if "try_message" in self.config and self.config["try_message"]: + msg = self.config["try_message"] + else: + if self.buildbot_config['sourcestamp']['changes']: + msg = self.buildbot_config['sourcestamp']['changes'][-1]['comments'] + + if msg is None or len(msg) == 1024: + # This commit message was potentially truncated, get the full message + # from hg. + props = self.buildbot_config['properties'] + rev = props['revision'] + repo = props['repo_path'] + url = 'https://hg.mozilla.org/%s/json-pushes?changeset=%s&full=1' % (repo, rev) + + pushinfo = self.load_json_from_url(url) + for k, v in pushinfo.items(): + if isinstance(v, dict) and 'changesets' in v: + msg = v['changesets'][-1]['desc'] + + if not msg and 'try_syntax' in self.buildbot_config['properties']: + # If we don't find try syntax in the usual place, check for it in an + # alternate property available to tools using self-serve. + msg = self.buildbot_config['properties']['try_syntax'] + + return msg + + @PostScriptAction('download-and-extract') + def set_extra_try_arguments(self, action, success=None): + """Finds a commit message and parses it for extra arguments to pass to the test + harness command line and test paths used to filter manifests. Extracting arguments from a commit message taken directly from the try_parser. """ + if (not self.buildbot_config or 'properties' not in self.buildbot_config or + self.buildbot_config['properties'].get('branch') != 'try'): + return + + msg = self._extract_try_message() + if not msg: + return + all_try_args = None for line in msg.splitlines(): if 'try: ' in line: @@ -51,7 +97,7 @@ class TryToolsMixin(object): return label_dict[val] return '--%s' % val.replace('_', '-') - for label, opts in known_try_arguments.iteritems(): + for label, opts in self.known_try_arguments.iteritems(): if 'action' in opts and opts['action'] not in ('append', 'store', 'store_true', 'store_false'): self.fatal('Try syntax does not support passing custom or store_const ' diff --git a/testing/mozharness/scripts/android_emulator_unittest.py b/testing/mozharness/scripts/android_emulator_unittest.py index 480f8ba5c2..608ed7defb 100644 --- a/testing/mozharness/scripts/android_emulator_unittest.py +++ b/testing/mozharness/scripts/android_emulator_unittest.py @@ -123,7 +123,7 @@ class AndroidEmulatorTest(BlobUploadMixin, TestingMixin, EmulatorMixin, VCSMixin dirs = self.query_abs_dirs() suite_category = self.test_suite_definitions[self.test_suite]["category"] try: - test_dir = self.tree_config["suite_definitions"][suite_category]["testsdir"] + test_dir = self.config["suite_definitions"][suite_category]["testsdir"] except: test_dir = suite_category return os.path.join(dirs['abs_test_install_dir'], test_dir) @@ -438,16 +438,15 @@ class AndroidEmulatorTest(BlobUploadMixin, TestingMixin, EmulatorMixin, VCSMixin dirs = self.query_abs_dirs() suite_category = self.test_suite_definitions[self.test_suite]["category"] - if suite_category not in self.tree_config["suite_definitions"]: - self.fatal("Key '%s' not defined in the in-tree config! Please add it to '%s'. " - "See bug 981030 for more details." % (suite_category, - os.path.join('goanna', 'testing', self.config['in_tree_config']))) + if suite_category not in self.config["suite_definitions"]: + self.fatal("Key '%s' not defined in the config!" % suite_category) + cmd = [ self.query_python_path('python'), '-u', os.path.join( self._query_tests_dir(), - self.tree_config["suite_definitions"][suite_category]["run_filename"] + self.config["suite_definitions"][suite_category]["run_filename"] ), ] @@ -474,7 +473,7 @@ class AndroidEmulatorTest(BlobUploadMixin, TestingMixin, EmulatorMixin, VCSMixin 'device_ip': c['device_ip'], 'device_port': str(self.emulator['sut_port1']), }) - for option in self.tree_config["suite_definitions"][suite_category]["options"]: + for option in self.config["suite_definitions"][suite_category]["options"]: cmd.extend([option % str_format_values]) for arg in self.test_suite_definitions[self.test_suite]["extra_args"]: diff --git a/testing/mozharness/scripts/android_panda.py b/testing/mozharness/scripts/android_panda.py index 6cee2ee3cb..a25774e70c 100644 --- a/testing/mozharness/scripts/android_panda.py +++ b/testing/mozharness/scripts/android_panda.py @@ -432,7 +432,7 @@ class PandaTest(TestingMixin, MercurialScript, BlobUploadMixin, MozpoolMixin, Bu c = self.config dirs = self.query_abs_dirs() options = [] - run_file = self.tree_config["suite_definitions"][suite_category]["run_filename"] + run_file = c["suite_definitions"][suite_category]["run_filename"] base_cmd = ['python', '-u'] base_cmd.append(os.path.join((dirs["abs_%s_dir" % suite_category]), run_file)) self.device_ip = socket.gethostbyname(self.mozpool_device) @@ -469,14 +469,9 @@ class PandaTest(TestingMixin, MercurialScript, BlobUploadMixin, MozpoolMixin, Bu 'apk_path': self.apk_path, 'raw_log_file': raw_log_file, } - if '%s_options' % suite_category in self.tree_config: - for option in self.tree_config['%s_options' % suite_category]: - options.append(option % str_format_values) - abs_base_cmd = base_cmd + options - return abs_base_cmd - elif "suite_definitions" in self.tree_config and \ - suite_category in self.tree_config["suite_definitions"]: # new in-tree format - for option in self.tree_config["suite_definitions"][suite_category]["options"]: + if "suite_definitions" in c and \ + suite_category in c["suite_definitions"]: # new in-tree format + for option in c["suite_definitions"][suite_category]["options"]: options.append(option % str_format_values) abs_base_cmd = base_cmd + options return abs_base_cmd @@ -484,8 +479,7 @@ class PandaTest(TestingMixin, MercurialScript, BlobUploadMixin, MozpoolMixin, Bu self.warning("Suite options for %s could not be determined." "\nIf you meant to have options for this suite, " "please make sure they are specified in your " - "tree config under %s_options" % - (suite_category, suite_category)) + "config." % suite_category) ###### helper methods def _pre_config_lock(self, rw_config): diff --git a/testing/mozharness/scripts/androidx86_emulator_unittest.py b/testing/mozharness/scripts/androidx86_emulator_unittest.py index afa947ed06..55e111c443 100644 --- a/testing/mozharness/scripts/androidx86_emulator_unittest.py +++ b/testing/mozharness/scripts/androidx86_emulator_unittest.py @@ -124,7 +124,7 @@ class AndroidEmulatorTest(BlobUploadMixin, TestingMixin, EmulatorMixin, VCSMixin dirs = self.query_abs_dirs() suite_category = self.test_suite_definitions[suite_name]["category"] try: - test_dir = self.tree_config["suite_definitions"][suite_category]["testsdir"] + test_dir = self.config["suite_definitions"][suite_category]["testsdir"] except: test_dir = suite_category @@ -404,16 +404,15 @@ class AndroidEmulatorTest(BlobUploadMixin, TestingMixin, EmulatorMixin, VCSMixin dirs = self.query_abs_dirs() suite_category = self.test_suite_definitions[suite_name]["category"] - if suite_category not in self.tree_config["suite_definitions"]: - self.fatal("Key '%s' not defined in the in-tree config! Please add it to '%s'. " - "See bug 981030 for more details." % (suite_category, - os.path.join('goanna', 'testing', self.config['in_tree_config']))) + if suite_category not in c["suite_definitions"]: + self.fatal("Key '%s' not defined in the config!" % suite_category) + cmd = [ self.query_python_path('python'), '-u', os.path.join( self._query_tests_dir(suite_name), - self.tree_config["suite_definitions"][suite_category]["run_filename"] + c["suite_definitions"][suite_category]["run_filename"] ), ] @@ -440,7 +439,7 @@ class AndroidEmulatorTest(BlobUploadMixin, TestingMixin, EmulatorMixin, VCSMixin 'device_ip': c['device_ip'], 'device_port': str(emulator['sut_port1']), }) - for option in self.tree_config["suite_definitions"][suite_category]["options"]: + for option in c["suite_definitions"][suite_category]["options"]: cmd.extend([option % str_format_values]) for arg in self.test_suite_definitions[suite_name]["extra_args"]: diff --git a/testing/mozharness/scripts/b2g_desktop_unittest.py b/testing/mozharness/scripts/b2g_desktop_unittest.py index a0c9c7098a..036258196c 100755 --- a/testing/mozharness/scripts/b2g_desktop_unittest.py +++ b/testing/mozharness/scripts/b2g_desktop_unittest.py @@ -124,16 +124,6 @@ class B2GDesktopTest(BlobUploadMixin, TestingMixin, MercurialScript): @PreScriptAction('create-virtualenv') def _pre_create_virtualenv(self, action): - if self.tree_config.get('use_puppetagain_packages'): - requirements = [os.path.join('tests', 'b2g', - 'b2g-unittest-requirements.txt')] - - self.register_virtualenv_module('mozinstall', - requirements=requirements) - self.register_virtualenv_module('marionette', - url=os.path.join('tests', 'marionette'), requirements=requirements) - return - dirs = self.query_abs_dirs() requirements = os.path.join(dirs['abs_config_dir'], 'marionette_requirements.txt') @@ -143,7 +133,7 @@ class B2GDesktopTest(BlobUploadMixin, TestingMixin, MercurialScript): def _query_abs_base_cmd(self, suite): dirs = self.query_abs_dirs() cmd = [self.query_python_path('python')] - cmd.append(self.query_value("run_file_names")[suite]) + cmd.append(self.config["run_file_names"][suite]) raw_log_file = os.path.join(dirs['abs_blob_upload_dir'], '%s_raw.log' % suite) @@ -160,23 +150,10 @@ class B2GDesktopTest(BlobUploadMixin, TestingMixin, MercurialScript): 'raw_log_file': raw_log_file, } - missing_key = True - if "suite_definitions" in self.tree_config: # new structure - if suite in self.tree_config["suite_definitions"]: - missing_key = False - options = self.tree_config["suite_definitions"][suite]["options"] - else: - suite_options = '%s_options' % suite - if suite_options in self.tree_config: - missing_key = False - options = self.tree_config[suite_options] - - if missing_key: - self.fatal("'%s' not defined in the in-tree config! Please add it to '%s'. " - "See bug 981030 for more details." % - (suite, - os.path.join('gecko', 'testing', self.config['in_tree_config']))) + if suite not in self.config["suite_definitions"]: + self.fatal("'%s' not defined in the config!" % suite), + options = self.config["suite_definitions"][suite]["options"] if options: for option in options: option = option % str_format_values diff --git a/testing/mozharness/scripts/b2g_emulator_unittest.py b/testing/mozharness/scripts/b2g_emulator_unittest.py index 781e8f2be0..70a0c2cb05 100755 --- a/testing/mozharness/scripts/b2g_emulator_unittest.py +++ b/testing/mozharness/scripts/b2g_emulator_unittest.py @@ -212,21 +212,6 @@ class B2GEmulatorTest(TestingMixin, VCSMixin, BaseScript, BlobUploadMixin): @PreScriptAction('create-virtualenv') def _pre_create_virtualenv(self, action): - if self.tree_config.get('use_puppetagain_packages'): - requirements = [os.path.join('tests', 'b2g', - 'b2g-unittest-requirements.txt')] - - self.register_virtualenv_module( - 'mozinstall', - requirements=requirements - ) - self.register_virtualenv_module( - 'marionette', - url=os.path.join('tests', 'marionette'), - requirements=requirements - ) - return - dirs = self.query_abs_dirs() requirements = os.path.join(dirs['abs_test_install_dir'], 'config', @@ -283,22 +268,10 @@ class B2GEmulatorTest(TestingMixin, VCSMixin, BaseScript, BlobUploadMixin): 'raw_log_file': raw_log_file, } - missing_key = True - if "suite_definitions" in self.tree_config: # new structure - if suite in self.tree_config["suite_definitions"]: - missing_key = False - options = self.tree_config["suite_definitions"][suite]["options"] - else: - suite_options = '%s_options' % suite - if suite_options in self.tree_config: - missing_key = False - options = self.tree_config[suite_options] - - if missing_key: - self.fatal("Key '%s' not defined in the in-tree config! Please add it to '%s'." \ - "See bug 981030 for more details." % (suite, - os.path.join('gecko', 'testing', self.config['in_tree_config']))) + if suite not in self.config["suite_definitions"]: + self.fatal("Key '%s' not defined in the config!" % suite) + options = self.config["suite_definitions"][suite]["options"] if options: for option in options: option = option % str_format_values diff --git a/testing/mozharness/scripts/desktop_unittest.py b/testing/mozharness/scripts/desktop_unittest.py index ed93a6abae..c160a97920 100755 --- a/testing/mozharness/scripts/desktop_unittest.py +++ b/testing/mozharness/scripts/desktop_unittest.py @@ -246,7 +246,7 @@ class DesktopUnittest(TestingMixin, MercurialScript, BlobUploadMixin, MozbaseMix abs_app_dir = self.query_abs_app_dir() if self._is_darwin(): - res_subdir = self.tree_config.get("mac_res_subdir", "Resources") + res_subdir = self.config.get("mac_res_subdir", "Resources") self.abs_res_dir = os.path.join(os.path.dirname(abs_app_dir), res_subdir) else: self.abs_res_dir = abs_app_dir @@ -364,23 +364,10 @@ class DesktopUnittest(TestingMixin, MercurialScript, BlobUploadMixin, MozbaseMix abs_res_plugins_dir = os.path.join(abs_res_dir, 'plugins') str_format_values['test_plugin_path'] = abs_res_plugins_dir - missing_key = True - if "suite_definitions" in self.tree_config: # new structure - if suite_category in self.tree_config["suite_definitions"]: - missing_key = False - options = self.tree_config["suite_definitions"][suite_category]["options"] - else: - suite_options = '%s_options' % suite_category - if suite_options in self.tree_config: - missing_key = False - options = self.tree_config[suite_options] - - if missing_key: - self.fatal("'%s' not defined in the in-tree config! Please add it to '%s'. " - "See bug 981030 for more details." % - (suite_category, - os.path.join('goanna', 'testing', self.config['in_tree_config']))) + if suite_category not in c["suite_definitions"]: + self.fatal("'%s' not defined in the config!") + options = c["suite_definitions"][suite_category]["options"] if options: for option in options: option = option % str_format_values diff --git a/testing/mozharness/scripts/luciddream_unittest.py b/testing/mozharness/scripts/luciddream_unittest.py index 2d802d3e19..fde76c9b40 100644 --- a/testing/mozharness/scripts/luciddream_unittest.py +++ b/testing/mozharness/scripts/luciddream_unittest.py @@ -249,7 +249,7 @@ class LuciddreamTest(TestingMixin, MercurialScript, MozbaseMixin, BaseScript, str_format_values['gaia_profile'] = os.path.join(dirs['abs_gaia_dir'], 'profile') suite = 'luciddream-emulator' if self.config.get('emulator_url') else 'luciddream-b2gdt' - options = self.tree_config['suite_definitions'][suite]['options'] + options = self.config['suite_definitions'][suite]['options'] for option in options: option = option % str_format_values if not option.endswith('None'): diff --git a/testing/mozharness/scripts/marionette.py b/testing/mozharness/scripts/marionette.py index 1f1eb02c8b..856d5eebc4 100755 --- a/testing/mozharness/scripts/marionette.py +++ b/testing/mozharness/scripts/marionette.py @@ -226,18 +226,6 @@ class MarionetteTest(TestingMixin, MercurialScript, BlobUploadMixin, TransferMix @PreScriptAction('create-virtualenv') def _configure_marionette_virtualenv(self, action): - # XXX Bug 981030 - hack to unbreak b2g18. Remove when b2g18 no longer supported - try: - branch = self.buildbot_config['properties']['branch'] - except: - branch = None - if self.tree_config.get('use_puppetagain_packages') or branch in ('mozilla-b2g18', 'mozilla-b2g18_v1_1_0_hd'): - self.register_virtualenv_module('mozinstall') - self.register_virtualenv_module( - 'marionette', os.path.join('tests', 'marionette')) - - return - dirs = self.query_abs_dirs() requirements = os.path.join(dirs['abs_test_install_dir'], 'config', @@ -307,7 +295,7 @@ class MarionetteTest(TestingMixin, MercurialScript, BlobUploadMixin, TransferMix # tests. This method will need to change if this does. if is_emulator and not is_gaiatest: testsuite = 'webapi' - return '_'.join([testsuite, platform, 'options']) + return '{}_{}'.format(testsuite, platform) def download_and_extract(self): super(MarionetteTest, self).download_and_extract() @@ -328,12 +316,6 @@ class MarionetteTest(TestingMixin, MercurialScript, BlobUploadMixin, TransferMix else: super(MarionetteTest, self).install() - def preflight_run_marionette(self): - """preflight commands for all tests""" - # If the in tree config hasn't been loaded by a previous step, load it here. - if not self.tree_config: - self._read_tree_config() - def run_marionette(self): """ Run the Marionette tests @@ -437,23 +419,17 @@ class MarionetteTest(TestingMixin, MercurialScript, BlobUploadMixin, TransferMix cmd.append('--gecko-log=%s' % os.path.join(dirs["abs_blob_upload_dir"], 'gecko.log')) - options_group = self._get_options_group(self.config.get('emulator'), - self.config.get('gaiatest')) - if self.config.get("structured_output"): config_fmt_args["raw_log_file"]= "-" - if options_group not in self.tree_config: - # This allows using the new in-tree format - options_group = options_group.split("_options")[0] - if options_group not in self.tree_config["suite_definitions"]: - self.fatal("%s is not defined in the in-tree config" % - options_group) - for s in self.tree_config["suite_definitions"][options_group]["options"]: - cmd.append(s % config_fmt_args) - else: - for s in self.tree_config[options_group]: - cmd.append(s % config_fmt_args) + options_group = self._get_options_group(self.config.get('emulator'), + self.config.get('gaiatest')) + + if options_group not in self.config["suite_definitions"]: + self.fatal("%s is not defined in the config!" % options_group) + + for s in self.config["suite_definitions"][options_group]["options"]: + cmd.append(s % config_fmt_args) if self.mkdir_p(dirs["abs_blob_upload_dir"]) == -1: # Make sure that the logging directory exists diff --git a/testing/mozharness/scripts/mulet_unittest.py b/testing/mozharness/scripts/mulet_unittest.py index 7c4fefeaf7..bbf548a6c3 100644 --- a/testing/mozharness/scripts/mulet_unittest.py +++ b/testing/mozharness/scripts/mulet_unittest.py @@ -59,11 +59,6 @@ class MuletUnittest(B2GDesktopTest, GaiaMixin, TransferMixin): if not self.binary_path: self.fatal("Use --binary-path as it is needed for _query_abs_dir().") - # This is if we don't run all actions since we set this inside - # of download-and-extract() - if not self.tree_config: - self._read_tree_config() - def run_tests(self): """ Run the unit test suite. diff --git a/testing/mozharness/scripts/web_platform_tests.py b/testing/mozharness/scripts/web_platform_tests.py index 07a582b147..fd325739fb 100755 --- a/testing/mozharness/scripts/web_platform_tests.py +++ b/testing/mozharness/scripts/web_platform_tests.py @@ -132,7 +132,7 @@ class WebPlatformTest(TestingMixin, MercurialScript, BlobUploadMixin): if val: base_cmd.append("--%s=%s" % (opt.replace("_", "-"), val)) - options = list(c.get("options", [])) + list(self.tree_config["options"]) + options = list(c.get("options", [])) str_format_values = { 'binary_path': self.binary_path, diff --git a/testing/remotecppunittests.py b/testing/remotecppunittests.py index ce7d9c20a3..cb521f6dc8 100644 --- a/testing/remotecppunittests.py +++ b/testing/remotecppunittests.py @@ -114,7 +114,8 @@ class RemoteCPPUnitTests(cppunittests.CPPUnitTests): return env - def run_one_test(self, prog, env, symbols_path=None, interactive=False): + def run_one_test(self, prog, env, symbols_path=None, interactive=False, + timeout_factor=1): """ Run a single C++ unit test program remotely. @@ -123,6 +124,7 @@ class RemoteCPPUnitTests(cppunittests.CPPUnitTests): * env: The environment to use for running the program. * symbols_path: A path to a directory containing Breakpad-formatted symbol files for producing stack traces on crash. + * timeout_factor: An optional test-specific timeout multiplier. Return True if the program exits with a zero status, False otherwise. """ @@ -130,8 +132,9 @@ class RemoteCPPUnitTests(cppunittests.CPPUnitTests): remote_bin = posixpath.join(self.remote_bin_dir, basename) self.log.test_start(basename) buf = StringIO.StringIO() + test_timeout = cppunittests.CPPUnitTests.TEST_PROC_TIMEOUT * timeout_factor returncode = self.device.shell([remote_bin], buf, env=env, cwd=self.remote_home_dir, - timeout=cppunittests.CPPUnitTests.TEST_PROC_TIMEOUT) + timeout=test_timeout) self.log.process_output(basename, "\n%s" % buf.getvalue(), command=[remote_bin]) with mozfile.TemporaryDirectory() as tempdir: @@ -192,13 +195,14 @@ class RemoteCPPUnittestOptions(cppunittests.CPPUnittestOptions): self.add_option("--remoteTestRoot", action = "store", type = "string", dest = "remote_test_root", help = "remote directory to use as test root (eg. /data/local/tests)") - self.add_option("--with-b2g-emulator", action = "store", - type = "string", dest = "with_b2g_emulator", - help = "Start B2G Emulator (specify path to b2g home)") # /data/local/tests is used because it is usually not possible to set +x permissions # on binaries on /mnt/sdcard defaults["remote_test_root"] = "/data/local/tests" + self.add_option("--with-b2g-emulator", action = "store", + type = "string", dest = "with_b2g_emulator", + help = "Start B2G Emulator (specify path to b2g home)") + self.add_option("--addEnv", action = "append", type = "string", dest = "add_env", help = "additional remote environment variable definitions (eg. --addEnv \"somevar=something\")") @@ -206,22 +210,7 @@ class RemoteCPPUnittestOptions(cppunittests.CPPUnittestOptions): self.set_defaults(**defaults) -def main(): - parser = RemoteCPPUnittestOptions() - mozlog.commandline.add_logging_group(parser) - options, args = parser.parse_args() - if not args: - print >>sys.stderr, """Usage: %s [...]""" % sys.argv[0] - sys.exit(1) - if options.local_lib is not None and not os.path.isdir(options.local_lib): - print >>sys.stderr, """Error: --localLib directory %s not found""" % options.local_lib - sys.exit(1) - if options.local_apk is not None and not os.path.isfile(options.local_apk): - print >>sys.stderr, """Error: --apk file %s not found""" % options.local_apk - sys.exit(1) - if not options.xre_path: - print >>sys.stderr, """Error: --xre-path is required""" - sys.exit(1) +def run_test_harness(options, args): if options.with_b2g_emulator: from mozrunner import B2GEmulatorRunner runner = B2GEmulatorRunner(b2g_home=options.with_b2g_emulator) @@ -249,21 +238,44 @@ def main(): print "Error: you must provide a device IP to connect to via the --deviceIP option" sys.exit(1) - log = mozlog.commandline.setup_logging("remotecppunittests", options, - {"tbpl": sys.stdout}) - options.xre_path = os.path.abspath(options.xre_path) cppunittests.update_mozinfo() - progs = cppunittests.extract_unittests_from_args(args, mozinfo.info) - tester = RemoteCPPUnitTests(dm, options, progs) + progs = cppunittests.extract_unittests_from_args(args, + mozinfo.info, + options.manifest_path) + tester = RemoteCPPUnitTests(dm, options, [item[0] for item in progs]) try: result = tester.run_tests(progs, options.xre_path, options.symbols_path) + finally: + if options.with_b2g_emulator: + runner.cleanup() + runner.wait() + return result + +def main(): + parser = RemoteCPPUnittestOptions() + mozlog.commandline.add_logging_group(parser) + options, args = parser.parse_args() + if not args: + print >>sys.stderr, """Usage: %s [...]""" % sys.argv[0] + sys.exit(1) + if options.local_lib is not None and not os.path.isdir(options.local_lib): + print >>sys.stderr, """Error: --localLib directory %s not found""" % options.local_lib + sys.exit(1) + if options.local_apk is not None and not os.path.isfile(options.local_apk): + print >>sys.stderr, """Error: --apk file %s not found""" % options.local_apk + sys.exit(1) + if not options.xre_path: + print >>sys.stderr, """Error: --xre-path is required""" + sys.exit(1) + + log = mozlog.commandline.setup_logging("remotecppunittests", options, + {"tbpl": sys.stdout}) + try: + result = run_test_harness(options, args) except Exception, e: log.error(str(e)) result = False - if options.with_b2g_emulator: - runner.cleanup() - runner.wait() sys.exit(0 if result else 1) if __name__ == '__main__': diff --git a/testing/runcppunittests.py b/testing/runcppunittests.py index c182ea204c..03b724e950 100644 --- a/testing/runcppunittests.py +++ b/testing/runcppunittests.py @@ -24,7 +24,8 @@ class CPPUnitTests(object): # Time (seconds) in which process will be killed if it produces no output. TEST_PROC_NO_OUTPUT_TIMEOUT = 300 - def run_one_test(self, prog, env, symbols_path=None, interactive=False): + def run_one_test(self, prog, env, symbols_path=None, interactive=False, + timeout_factor=1): """ Run a single C++ unit test program. @@ -33,6 +34,7 @@ class CPPUnitTests(object): * env: The environment to use for running the program. * symbols_path: A path to a directory containing Breakpad-formatted symbol files for producing stack traces on crash. + * timeout_factor: An optional test-specific timeout multiplier. Return True if the program exits with a zero status, False otherwise. """ @@ -53,7 +55,8 @@ class CPPUnitTests(object): processOutputLine=lambda _: None) #TODO: After bug 811320 is fixed, don't let .run() kill the process, # instead use a timeout in .wait() and then kill to get a stack. - proc.run(timeout=CPPUnitTests.TEST_PROC_TIMEOUT, + test_timeout = CPPUnitTests.TEST_PROC_TIMEOUT * timeout_factor + proc.run(timeout=test_timeout, outputTimeout=CPPUnitTests.TEST_PROC_NO_OUTPUT_TIMEOUT) proc.wait() if proc.output: @@ -133,7 +136,7 @@ class CPPUnitTests(object): Run a set of C++ unit test programs. Arguments: - * programs: An iterable containing paths to test programs. + * programs: An iterable containing (test path, test timeout factor) tuples * xre_path: A path to a directory containing a XUL Runtime Environment. * symbols_path: A path to a directory containing Breakpad-formatted symbol files for producing stack traces on crash. @@ -148,7 +151,10 @@ class CPPUnitTests(object): pass_count = 0 fail_count = 0 for prog in programs: - single_result = self.run_one_test(prog, env, symbols_path, interactive) + test_path = prog[0] + timeout_factor = prog[1] + single_result = self.run_one_test(test_path, env, symbols_path, + interactive, timeout_factor) if single_result: pass_count += 1 else: @@ -172,33 +178,41 @@ class CPPUnittestOptions(OptionParser): action = "store", type = "string", dest = "symbols_path", default = None, help = "absolute path to directory containing breakpad symbols, or the URL of a zip file containing symbols") - self.add_option("--skip-manifest", - action = "store", type = "string", dest = "manifest_file", + self.add_option("--manifest-path", + action = "store", type = "string", dest = "manifest_path", default = None, - help = "absolute path to a manifest file") + help = "path to test manifest, if different from the path to test binaries") -def extract_unittests_from_args(args, environ): +def extract_unittests_from_args(args, environ, manifest_path): """Extract unittests from args, expanding directories as needed""" mp = manifestparser.TestManifest(strict=True) tests = [] - for p in args: - if os.path.isdir(p): - try: - mp.read(os.path.join(p, 'cppunittest.ini')) - except IOError: - tests.extend([os.path.abspath(os.path.join(p, x)) for x in os.listdir(p)]) - else: - tests.append(os.path.abspath(p)) + binary_path = None + + if manifest_path: + mp.read(manifest_path) + binary_path = os.path.abspath(args[0]) + else: + for p in args: + if os.path.isdir(p): + try: + mp.read(os.path.join(p, 'cppunittest.ini')) + except IOError: + tests.extend([(os.path.abspath(os.path.join(p, x)), 1) for x in os.listdir(p)]) + else: + tests.append((os.path.abspath(p), 1)) # we skip the existence check here because not all tests are built # for all platforms (and it will fail on Windows anyway) - if mozinfo.isWin: - tests.extend([test['path'] + '.exe' for test in mp.active_tests(exists=False, disabled=False, **environ)]) + active_tests = mp.active_tests(exists=False, disabled=False, **environ) + suffix = '.exe' if mozinfo.isWin else '' + if binary_path: + tests.extend([(os.path.join(binary_path, test['relpath'] + suffix), int(test.get('requesttimeoutfactor', 1))) for test in active_tests]) else: - tests.extend([test['path'] for test in mp.active_tests(exists=False, disabled=False, **environ)]) + tests.extend([(test['path'] + suffix, int(test.get('requesttimeoutfactor', 1))) for test in active_tests]) # skip non-existing tests - tests = [test for test in tests if os.path.isfile(test)] + tests = [test for test in tests if os.path.isfile(test[0])] return tests @@ -213,6 +227,15 @@ def update_mozinfo(): path = os.path.split(path)[0] mozinfo.find_and_update_from_json(*dirs) +def run_test_harness(options, args): + update_mozinfo() + progs = extract_unittests_from_args(args, mozinfo.info, options.manifest_path) + options.xre_path = os.path.abspath(options.xre_path) + tester = CPPUnitTests() + result = tester.run_tests(progs, options.xre_path, options.symbols_path) + + return result + def main(): parser = CPPUnittestOptions() mozlog.commandline.add_logging_group(parser) @@ -223,19 +246,13 @@ def main(): if not options.xre_path: print >>sys.stderr, """Error: --xre-path is required""" sys.exit(1) - + if options.manifest_path and len(args) > 1: + print >>sys.stderr, "Error: multiple arguments not supported with --test-manifest" + sys.exit(1) log = mozlog.commandline.setup_logging("cppunittests", options, {"tbpl": sys.stdout}) - - update_mozinfo() - progs = extract_unittests_from_args(args, mozinfo.info) - options.xre_path = os.path.abspath(options.xre_path) - if mozinfo.isMac: - options.xre_path = os.path.join(os.path.dirname(options.xre_path), 'Resources') - tester = CPPUnitTests() - try: - result = tester.run_tests(progs, options.xre_path, options.symbols_path) + result = run_test_harness(options, args) except Exception as e: log.error(str(e)) result = False diff --git a/testing/testsuite-targets.mk b/testing/testsuite-targets.mk index bd0f05e695..2891db52df 100644 --- a/testing/testsuite-targets.mk +++ b/testing/testsuite-targets.mk @@ -60,9 +60,8 @@ RUN_MOCHITEST_REMOTE = \ RUN_MOCHITEST_ROBOCOP = \ rm -f ./$@.log && \ - $(PYTHON) _tests/testing/mochitest/runtestsremote.py \ - --robocop-apk=$(DEPTH)/build/mobile/robocop/robocop-debug.apk \ - --robocop-ids=$(DEPTH)/mobile/android/base/fennec_ids.txt \ + $(PYTHON) _tests/testing/mochitest/runrobocop.py \ + --robocop-apk=$(DEPTH)/mobile/android/tests/browser/robocop/robocop-debug.apk \ --robocop-ini=_tests/testing/mochitest/robocop.ini \ --log-tbpl=./$@.log $(DM_FLAGS) --dm_trans=$(DM_TRANS) \ --app=$(TEST_PACKAGE_NAME) --deviceIP=${TEST_DEVICE} --xre-path=${MOZ_HOST_BIN} \ diff --git a/toolkit/commonjs/sdk/content/context-menu.js b/toolkit/commonjs/sdk/content/context-menu.js index 4495638731..0e01230f62 100644 --- a/toolkit/commonjs/sdk/content/context-menu.js +++ b/toolkit/commonjs/sdk/content/context-menu.js @@ -183,7 +183,7 @@ CONTEXTS.SelectorContext = Class({ let selector = this.selector; while (!(popupNode instanceof Ci.nsIDOMDocument)) { - if (popupNode.mozMatchesSelector(selector)) + if (popupNode.matches(selector)) return popupNode; popupNode = popupNode.parentNode; diff --git a/toolkit/commonjs/sdk/system/Startup.js b/toolkit/commonjs/sdk/system/Startup.js index 7764090771..65582e9b92 100644 --- a/toolkit/commonjs/sdk/system/Startup.js +++ b/toolkit/commonjs/sdk/system/Startup.js @@ -5,7 +5,7 @@ var EXPORTED_SYMBOLS = ["Startup"]; -const { utils: Cu, interfaces: Ci, classes: Cc } = Components; +var { utils: Cu, interfaces: Ci, classes: Cc } = Components; const { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); const { defer } = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise; diff --git a/toolkit/commonjs/sdk/tabs/tab-firefox.js b/toolkit/commonjs/sdk/tabs/tab-firefox.js index ef2e17356c..2a318b12c2 100644 --- a/toolkit/commonjs/sdk/tabs/tab-firefox.js +++ b/toolkit/commonjs/sdk/tabs/tab-firefox.js @@ -215,7 +215,7 @@ const Tab = Class({ if (frame.frameElement != browser(this)) return; - listener.off("attach", listener); + frames.off("attach", listener); attach(frame); }; frames.on("attach", listener); diff --git a/toolkit/components/osfile/modules/osfile_async_front.jsm b/toolkit/components/osfile/modules/osfile_async_front.jsm index b91fab8cbb..3cbf786c52 100644 --- a/toolkit/components/osfile/modules/osfile_async_front.jsm +++ b/toolkit/components/osfile/modules/osfile_async_front.jsm @@ -24,18 +24,18 @@ this.EXPORTED_SYMBOLS = ["OS"]; const Cu = Components.utils; const Ci = Components.interfaces; -let SharedAll = {}; +var SharedAll = {}; Cu.import("resource://gre/modules/osfile/osfile_shared_allthreads.jsm", SharedAll); Cu.import("resource://gre/modules/XPCOMUtils.jsm", this); Cu.import("resource://gre/modules/Timer.jsm", this); // Boilerplate, to simplify the transition to require() -let LOG = SharedAll.LOG.bind(SharedAll, "Controller"); -let isTypedArray = SharedAll.isTypedArray; +var LOG = SharedAll.LOG.bind(SharedAll, "Controller"); +var isTypedArray = SharedAll.isTypedArray; // The constructor for file errors. -let SysAll = {}; +var SysAll = {}; if (SharedAll.Constants.Win) { Cu.import("resource://gre/modules/osfile/osfile_win_allthreads.jsm", SysAll); } else if (SharedAll.Constants.libc) { @@ -43,10 +43,10 @@ if (SharedAll.Constants.Win) { } else { throw new Error("I am neither under Windows nor under a Posix system"); } -let OSError = SysAll.Error; -let Type = SysAll.Type; +var OSError = SysAll.Error; +var Type = SysAll.Type; -let Path = {}; +var Path = {}; Cu.import("resource://gre/modules/osfile/ospath.jsm", Path); // The library of promises. @@ -58,7 +58,7 @@ Cu.import("resource://gre/modules/PromiseWorker.jsm", this); Cu.import("resource://gre/modules/Services.jsm", this); Cu.import("resource://gre/modules/TelemetryStopwatch.jsm", this); Cu.import("resource://gre/modules/AsyncShutdown.jsm", this); -let Native = Cu.import("resource://gre/modules/osfile/osfile_native.jsm", {}); +var Native = Cu.import("resource://gre/modules/osfile/osfile_native.jsm", {}); // It's possible for osfile.jsm to get imported before the profile is @@ -103,7 +103,7 @@ for (let [constProp, dirKey] of [ /** * Return a shallow clone of the enumerable properties of an object. */ -let clone = SharedAll.clone; +var clone = SharedAll.clone; /** * Extract a shortened version of an object, fit for logging. @@ -149,7 +149,7 @@ function summarizeObject(obj) { // In order to expose Scheduler to the unfiltered Cu.import return value variant // on B2G we need to save it to `this`. This does not make it public; // EXPORTED_SYMBOLS still controls that in all cases. -let Scheduler = this.Scheduler = { +var Scheduler = this.Scheduler = { /** * |true| once we have sent at least one message to the worker. @@ -512,7 +512,7 @@ SharedAll.Config.TEST = readDebugPref(PREF_OSFILE_LOG_REDIRECT, false); * If |true|, use the native implementaiton of OS.File methods * whenever possible. Otherwise, force the use of the JS version. */ -let nativeWheneverAvailable = true; +var nativeWheneverAvailable = true; const PREF_OSFILE_NATIVE = "toolkit.osfile.native"; Services.prefs.addObserver(PREF_OSFILE_NATIVE, function prefObserver(aSubject, aTopic, aData) { @@ -584,7 +584,7 @@ Services.prefs.addObserver(PREF_OSFILE_TEST_SHUTDOWN_OBSERVER, * * @constructor */ -let File = function File(fdmsg) { +var File = function File(fdmsg) { // FIXME: At the moment, |File| does not close on finalize // (see bug 777715) this._fdmsg = fdmsg; @@ -1462,7 +1462,7 @@ Object.defineProperty(OS.File, "queue", { /** * Shutdown barriers, to let clients register to be informed during shutdown. */ -let Barriers = { +var Barriers = { profileBeforeChange: new AsyncShutdown.Barrier("OS.File: Waiting for clients before profile-before-shutdown"), shutdown: new AsyncShutdown.Barrier("OS.File: Waiting for clients before full shutdown"), /** diff --git a/toolkit/components/osfile/modules/osfile_native.jsm b/toolkit/components/osfile/modules/osfile_native.jsm index 09e33feded..16cd3c92a1 100644 --- a/toolkit/components/osfile/modules/osfile_native.jsm +++ b/toolkit/components/osfile/modules/osfile_native.jsm @@ -10,11 +10,11 @@ this.EXPORTED_SYMBOLS = ["read"]; -let {results: Cr, utils: Cu, interfaces: Ci} = Components; +var {results: Cr, utils: Cu, interfaces: Ci} = Components; -let SharedAll = Cu.import("resource://gre/modules/osfile/osfile_shared_allthreads.jsm", {}); +var SharedAll = Cu.import("resource://gre/modules/osfile/osfile_shared_allthreads.jsm", {}); -let SysAll = {}; +var SysAll = {}; if (SharedAll.Constants.Win) { Cu.import("resource://gre/modules/osfile/osfile_win_allthreads.jsm", SysAll); } else if (SharedAll.Constants.libc) { @@ -22,8 +22,8 @@ if (SharedAll.Constants.Win) { } else { throw new Error("I am neither under Windows nor under a Posix system"); } -let {Promise} = Cu.import("resource://gre/modules/Promise.jsm", {}); -let {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {}); +var {Promise} = Cu.import("resource://gre/modules/Promise.jsm", {}); +var {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {}); /** * The native service holding the implementation of the functions. diff --git a/toolkit/components/osfile/modules/osfile_shared_allthreads.jsm b/toolkit/components/osfile/modules/osfile_shared_allthreads.jsm index 7e91686b7e..43bd1933e5 100644 --- a/toolkit/components/osfile/modules/osfile_shared_allthreads.jsm +++ b/toolkit/components/osfile/modules/osfile_shared_allthreads.jsm @@ -33,7 +33,7 @@ const Cc = typeof Components != "undefined" ? Components.classes : undefined; * * @constructor */ -let Meta; +var Meta; if (typeof Components != "undefined") { // Global definition of |exports|, to keep everybody happy. // In non-main thread, |exports| is provided by the module @@ -47,7 +47,7 @@ if (typeof Components != "undefined") { Meta = require("resource://gre/modules/workers/PromiseWorker.js").Meta; } -let EXPORTED_SYMBOLS = [ +var EXPORTED_SYMBOLS = [ "LOG", "clone", "Config", @@ -69,7 +69,7 @@ let EXPORTED_SYMBOLS = [ ////////////////////// Configuration of OS.File -let Config = { +var Config = { /** * If |true|, calls to |LOG| are shown. Otherwise, they are hidden. * @@ -99,7 +99,7 @@ exports.Constants = OS.Constants; ///////////////////// Utilities // Define a lazy getter for a property -let defineLazyGetter = function defineLazyGetter(object, name, getter) { +var defineLazyGetter = function defineLazyGetter(object, name, getter) { Object.defineProperty(object, name, { configurable: true, get: function lazy() { @@ -122,7 +122,7 @@ exports.defineLazyGetter = defineLazyGetter; * * The choice of logger can be overridden with Config.TEST. */ -let gLogger; +var gLogger; if (typeof window != "undefined" && window.console && console.log) { gLogger = console.log.bind(console, "OS"); } else { @@ -139,7 +139,7 @@ if (typeof window != "undefined" && window.console && console.log) { * @param {*} arg An argument to be stringified if possible. * @return {string} A stringified version of |arg|. */ -let stringifyArg = function stringifyArg(arg) { +var stringifyArg = function stringifyArg(arg) { if (typeof arg === "string") { return arg; } @@ -170,7 +170,7 @@ let stringifyArg = function stringifyArg(arg) { return arg; }; -let LOG = function (...args) { +var LOG = function (...args) { if (!Config.DEBUG) { // If logging is deactivated, don't log return; @@ -204,7 +204,7 @@ exports.LOG = LOG; * @param {Array} refs An optional array of field names to be passed by * reference instead of copying. */ -let clone = function (object, refs = []) { +var clone = function (object, refs = []) { let result = {}; // Make a reference between result[key] and object[key]. let refer = function refer(result, key, object) { @@ -407,7 +407,7 @@ Type.prototype = { /** * Utility function used to determine whether an object is a typed array */ -let isTypedArray = function isTypedArray(obj) { +var isTypedArray = function isTypedArray(obj) { return obj != null && typeof obj == "object" && "byteOffset" in obj; }; @@ -416,7 +416,7 @@ exports.isTypedArray = isTypedArray; /** * Utility function used to determine whether an object is an ArrayBuffer. */ -let isArrayBuffer = function(obj) { +var isArrayBuffer = function(obj) { return obj != null && typeof obj == "object" && obj.constructor.name == "ArrayBuffer"; }; @@ -511,7 +511,7 @@ exports.Type = Type; * therefore project them to regular numbers whenever possible. */ -let projectLargeInt = function projectLargeInt(x) { +var projectLargeInt = function projectLargeInt(x) { let str = x.toString(); let rv = parseInt(str, 10); if (rv.toString() !== str) { @@ -519,10 +519,10 @@ let projectLargeInt = function projectLargeInt(x) { } return rv; }; -let projectLargeUInt = function projectLargeUInt(x) { +var projectLargeUInt = function projectLargeUInt(x) { return projectLargeInt(x); }; -let projectValue = function projectValue(x) { +var projectValue = function projectValue(x) { if (!(x instanceof ctypes.CData)) { return x; } @@ -1070,7 +1070,7 @@ exports.Library = Library; * it does not exist), or a JavaScript wrapper performing the call to C * and any type conversion required. */ -let declareFFI = function declareFFI(lib, symbol, abi, +var declareFFI = function declareFFI(lib, symbol, abi, returnType /*, argTypes ...*/) { LOG("Attempting to declare FFI ", symbol); // We guard agressively, to avoid any late surprise diff --git a/toolkit/components/osfile/modules/osfile_shared_front.jsm b/toolkit/components/osfile/modules/osfile_shared_front.jsm index 76fbbe4a29..4a5f897b9d 100644 --- a/toolkit/components/osfile/modules/osfile_shared_front.jsm +++ b/toolkit/components/osfile/modules/osfile_shared_front.jsm @@ -14,13 +14,13 @@ if (typeof Components != "undefined") { } (function(exports) { -let SharedAll = +var SharedAll = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm"); -let Path = require("resource://gre/modules/osfile/ospath.jsm"); -let Lz4 = +var Path = require("resource://gre/modules/osfile/ospath.jsm"); +var Lz4 = require("resource://gre/modules/lz4.js"); -let LOG = SharedAll.LOG.bind(SharedAll, "Shared front-end"); -let clone = SharedAll.clone; +var LOG = SharedAll.LOG.bind(SharedAll, "Shared front-end"); +var clone = SharedAll.clone; /** * Code shared by implementations of File. @@ -29,7 +29,7 @@ let clone = SharedAll.clone; * @param {string} path File path of the file handle, used for error-reporting. * @constructor */ -let AbstractFile = function AbstractFile(fd, path) { +var AbstractFile = function AbstractFile(fd, path) { this._fd = fd; if (!path) { throw new TypeError("path is expected"); diff --git a/toolkit/components/osfile/modules/osfile_unix_allthreads.jsm b/toolkit/components/osfile/modules/osfile_unix_allthreads.jsm index 5a50760237..c4513300f0 100644 --- a/toolkit/components/osfile/modules/osfile_unix_allthreads.jsm +++ b/toolkit/components/osfile/modules/osfile_unix_allthreads.jsm @@ -19,7 +19,7 @@ "use strict"; -let SharedAll; +var SharedAll; if (typeof Components != "undefined") { let Cu = Components.utils; // Module is opened as a jsm module @@ -35,20 +35,20 @@ if (typeof Components != "undefined") { throw new Error("Please open this module with Component.utils.import or with require()"); } -let LOG = SharedAll.LOG.bind(SharedAll, "Unix", "allthreads"); -let Const = SharedAll.Constants.libc; +var LOG = SharedAll.LOG.bind(SharedAll, "Unix", "allthreads"); +var Const = SharedAll.Constants.libc; // Open libc -let libc = new SharedAll.Library("libc", +var libc = new SharedAll.Library("libc", "libc.so", "libSystem.B.dylib", "a.out"); exports.libc = libc; // Define declareFFI -let declareFFI = SharedAll.declareFFI.bind(null, libc); +var declareFFI = SharedAll.declareFFI.bind(null, libc); exports.declareFFI = declareFFI; // Define lazy binding -let LazyBindings = {}; +var LazyBindings = {}; libc.declareLazy(LazyBindings, "strerror", "strerror", ctypes.default_abi, /*return*/ ctypes.char.ptr, @@ -79,7 +79,7 @@ libc.declareLazy(LazyBindings, "strerror", * @constructor * @extends {OS.Shared.Error} */ -let OSError = function OSError(operation = "unknown operation", +var OSError = function OSError(operation = "unknown operation", errno = ctypes.errno, path = "") { SharedAll.OSError.call(this, operation, path); this.unixErrno = errno; @@ -184,7 +184,7 @@ exports.Error = OSError; * * @constructor */ -let AbstractInfo = function AbstractInfo(path, isDir, isSymLink, size, lastAccessDate, +var AbstractInfo = function AbstractInfo(path, isDir, isSymLink, size, lastAccessDate, lastModificationDate, unixLastStatusChangeDate, unixOwner, unixGroup, unixMode) { this._path = path; @@ -282,7 +282,7 @@ exports.AbstractInfo = AbstractInfo; * * @constructor */ -let AbstractEntry = function AbstractEntry(isDir, isSymLink, name, path) { +var AbstractEntry = function AbstractEntry(isDir, isSymLink, name, path) { this._isDir = isDir; this._isSymlLink = isSymLink; this._name = name; @@ -326,7 +326,7 @@ exports.POS_END = Const.SEEK_END; // Special types that need to be defined for communication // between threads -let Type = Object.create(SharedAll.Type); +var Type = Object.create(SharedAll.Type); exports.Type = Type; /** @@ -354,7 +354,7 @@ OSError.invalidArgument = function invalidArgument(operation) { return new OSError(operation, Const.EINVAL); }; -let EXPORTED_SYMBOLS = [ +var EXPORTED_SYMBOLS = [ "declareFFI", "libc", "Error", diff --git a/toolkit/components/osfile/modules/osfile_win_allthreads.jsm b/toolkit/components/osfile/modules/osfile_win_allthreads.jsm index 667d0a93bd..df0452d78c 100644 --- a/toolkit/components/osfile/modules/osfile_win_allthreads.jsm +++ b/toolkit/components/osfile/modules/osfile_win_allthreads.jsm @@ -19,7 +19,7 @@ "use strict"; -let SharedAll; +var SharedAll; if (typeof Components != "undefined") { let Cu = Components.utils; // Module is opened as a jsm module @@ -35,18 +35,18 @@ if (typeof Components != "undefined") { throw new Error("Please open this module with Component.utils.import or with require()"); } -let LOG = SharedAll.LOG.bind(SharedAll, "Win", "allthreads"); -let Const = SharedAll.Constants.Win; +var LOG = SharedAll.LOG.bind(SharedAll, "Win", "allthreads"); +var Const = SharedAll.Constants.Win; // Open libc -let libc = new SharedAll.Library("libc", "kernel32.dll"); +var libc = new SharedAll.Library("libc", "kernel32.dll"); exports.libc = libc; // Define declareFFI -let declareFFI = SharedAll.declareFFI.bind(null, libc); +var declareFFI = SharedAll.declareFFI.bind(null, libc); exports.declareFFI = declareFFI; -let Scope = {}; +var Scope = {}; // Define Error libc.declareLazy(Scope, "FormatMessage", @@ -85,7 +85,7 @@ libc.declareLazy(Scope, "FormatMessage", * @constructor * @extends {OS.Shared.Error} */ -let OSError = function OSError(operation = "unknown operation", +var OSError = function OSError(operation = "unknown operation", lastError = ctypes.winLastError, path = "") { operation = operation; SharedAll.OSError.call(this, operation, path); @@ -208,7 +208,7 @@ exports.Error = OSError; * * @constructor */ -let AbstractInfo = function AbstractInfo(path, isDir, isSymLink, size, +var AbstractInfo = function AbstractInfo(path, isDir, isSymLink, size, winBirthDate, lastAccessDate, lastWriteDate, winAttributes) { @@ -305,7 +305,7 @@ exports.AbstractInfo = AbstractInfo; * * @constructor */ -let AbstractEntry = function AbstractEntry(isDir, isSymLink, name, +var AbstractEntry = function AbstractEntry(isDir, isSymLink, name, winCreationDate, winLastWriteDate, winLastAccessDate, path) { this._isDir = isDir; @@ -376,7 +376,7 @@ exports.POS_END = Const.FILE_END; // Special types that need to be defined for communication // between threads -let Type = Object.create(SharedAll.Type); +var Type = Object.create(SharedAll.Type); exports.Type = Type; /** @@ -404,7 +404,7 @@ OSError.invalidArgument = function invalidArgument(operation) { return new OSError(operation, Const.ERROR_NOT_SUPPORTED); }; -let EXPORTED_SYMBOLS = [ +var EXPORTED_SYMBOLS = [ "declareFFI", "libc", "Error", diff --git a/toolkit/components/osfile/modules/ospath_unix.jsm b/toolkit/components/osfile/modules/ospath_unix.jsm index 6e0f00d562..4199ead628 100644 --- a/toolkit/components/osfile/modules/ospath_unix.jsm +++ b/toolkit/components/osfile/modules/ospath_unix.jsm @@ -29,7 +29,7 @@ if (typeof Components != "undefined") { throw new Error("Please load this module using require()"); } -let EXPORTED_SYMBOLS = [ +var EXPORTED_SYMBOLS = [ "basename", "dirname", "join", @@ -43,7 +43,7 @@ let EXPORTED_SYMBOLS = [ * Return the final part of the path. * The final part of the path is everything after the last "/". */ -let basename = function(path) { +var basename = function(path) { return path.slice(path.lastIndexOf("/") + 1); }; exports.basename = basename; @@ -56,7 +56,7 @@ exports.basename = basename; * * If the path contains no directory, return ".". */ -let dirname = function(path) { +var dirname = function(path) { let index = path.lastIndexOf("/"); if (index == -1) { return "."; @@ -82,7 +82,7 @@ exports.dirname = dirname; * Empty components are ignored, i.e. `OS.Path.join("foo", "", "bar)` is the * same as `OS.Path.join("foo", "bar")`. */ -let join = function(...path) { +var join = function(...path) { // If there is a path that starts with a "/", eliminate everything before let paths = []; for (let subpath of path) { @@ -104,7 +104,7 @@ exports.join = join; /** * Normalize a path by removing any unneeded ".", "..", "//". */ -let normalize = function(path) { +var normalize = function(path) { let stack = []; let absolute; if (path.length >= 0 && path[0] == "/") { @@ -151,7 +151,7 @@ exports.normalize = normalize; * * Other implementations may add additional OS-specific informations. */ -let split = function(path) { +var split = function(path) { return { absolute: path.length && path[0] == "/", components: path.split("/") @@ -163,8 +163,8 @@ exports.split = split; * Returns the file:// URI file path of the given local file path. */ // The case of %3b is designed to match Services.io, but fundamentally doesn't matter. -let toFileURIExtraEncodings = {';': '%3b', '?': '%3F', '#': '%23'}; -let toFileURI = function toFileURI(path) { +var toFileURIExtraEncodings = {';': '%3b', '?': '%3F', '#': '%23'}; +var toFileURI = function toFileURI(path) { let uri = encodeURI(this.normalize(path)); // add a prefix, and encodeURI doesn't escape a few characters that we do @@ -179,7 +179,7 @@ exports.toFileURI = toFileURI; /** * Returns the local file path from a given file URI. */ -let fromFileURI = function fromFileURI(uri) { +var fromFileURI = function fromFileURI(uri) { let url = new URL(uri); if (url.protocol != 'file:') { throw new Error("fromFileURI expects a file URI"); diff --git a/toolkit/components/osfile/modules/ospath_win.jsm b/toolkit/components/osfile/modules/ospath_win.jsm index 58a75fedff..6fdc8aee40 100644 --- a/toolkit/components/osfile/modules/ospath_win.jsm +++ b/toolkit/components/osfile/modules/ospath_win.jsm @@ -38,7 +38,7 @@ if (typeof Components != "undefined") { throw new Error("Please load this module using require()"); } -let EXPORTED_SYMBOLS = [ +var EXPORTED_SYMBOLS = [ "basename", "dirname", "join", @@ -54,7 +54,7 @@ let EXPORTED_SYMBOLS = [ * Return the final part of the path. * The final part of the path is everything after the last "\\". */ -let basename = function(path) { +var basename = function(path) { if (path.startsWith("\\\\")) { // UNC-style path let index = path.lastIndexOf("\\"); @@ -84,7 +84,7 @@ exports.basename = basename; * of this function. This implementation supports the following options: * - |winNoDrive| If |true|, also remove the letter from the path name. */ -let dirname = function(path, options) { +var dirname = function(path, options) { let noDrive = (options && options.winNoDrive); // Find the last occurrence of "\\" @@ -187,7 +187,7 @@ exports.join = join; * name includes the ":") or "\\\\DriveName..." (the returned drive name * includes "\\\\"). */ -let winGetDrive = function(path) { +var winGetDrive = function(path) { if (path == null) { throw new TypeError("path is invalid"); } @@ -216,7 +216,7 @@ exports.winGetDrive = winGetDrive; * We consider that a path is absolute if it starts with "\\" * or "driveletter:\\". */ -let winIsAbsolute = function(path) { +var winIsAbsolute = function(path) { let index = path.indexOf(":"); return path.length > index + 1 && path[index + 1] == "\\"; }; @@ -226,7 +226,7 @@ exports.winIsAbsolute = winIsAbsolute; * Normalize a path by removing any unneeded ".", "..", "\\". * Also convert any "/" to a "\\". */ -let normalize = function(path) { +var normalize = function(path) { let stack = []; if (!path.startsWith("\\\\")) { @@ -293,7 +293,7 @@ exports.normalize = normalize; * * Other implementations may add additional OS-specific informations. */ -let split = function(path) { +var split = function(path) { return { absolute: this.winIsAbsolute(path), winDrive: this.winGetDrive(path), @@ -306,8 +306,8 @@ exports.split = split; * Return the file:// URI file path of the given local file path. */ // The case of %3b is designed to match Services.io, but fundamentally doesn't matter. -let toFileURIExtraEncodings = {';': '%3b', '?': '%3F', '#': '%23'}; -let toFileURI = function toFileURI(path) { +var toFileURIExtraEncodings = {';': '%3b', '?': '%3F', '#': '%23'}; +var toFileURI = function toFileURI(path) { // URI-escape forward slashes and convert backward slashes to forward path = this.normalize(path).replace(/[\\\/]/g, m => (m=='\\')? '/' : '%2F'); let uri = encodeURI(path); @@ -329,7 +329,7 @@ exports.toFileURI = toFileURI; /** * Returns the local file path from a given file URI. */ -let fromFileURI = function fromFileURI(uri) { +var fromFileURI = function fromFileURI(uri) { let url = new URL(uri); if (url.protocol != 'file:') { throw new Error("fromFileURI expects a file URI"); @@ -357,7 +357,7 @@ exports.fromFileURI = fromFileURI; * Utility function: Remove any leading/trailing backslashes * from a string. */ -let trimBackslashes = function trimBackslashes(string) { +var trimBackslashes = function trimBackslashes(string) { return string.replace(/^\\+|\\+$/g,''); }; diff --git a/toolkit/components/osfile/tests/mochi/main_test_osfile_async.js b/toolkit/components/osfile/tests/mochi/main_test_osfile_async.js index 56f0bf923d..b940a032a2 100644 --- a/toolkit/components/osfile/tests/mochi/main_test_osfile_async.js +++ b/toolkit/components/osfile/tests/mochi/main_test_osfile_async.js @@ -11,16 +11,16 @@ Components.utils.import("resource://gre/modules/NetUtil.jsm"); Components.utils.import("resource://gre/modules/FileUtils.jsm"); Components.utils.import("resource://gre/modules/Services.jsm"); -let myok = ok; -let myis = is; -let myinfo = info; -let myisnot = isnot; +var myok = ok; +var myis = is; +var myinfo = info; +var myisnot = isnot; -let isPromise = function ispromise(value) { +var isPromise = function ispromise(value) { return value != null && typeof value == "object" && "then" in value; }; -let maketest = function(prefix, test) { +var maketest = function(prefix, test) { let utils = { ok: function ok(t, m) { myok(t, prefix + ": " + m); @@ -85,7 +85,7 @@ let maketest = function(prefix, test) { * @return {promise} * @resolves {string} The contents of the file. */ -let reference_fetch_file = function reference_fetch_file(path, test) { +var reference_fetch_file = function reference_fetch_file(path, test) { test.info("Fetching file " + path); let promise = Promise.defer(); let file = new FileUtils.File(path); @@ -124,14 +124,14 @@ let reference_fetch_file = function reference_fetch_file(path, test) { * * @resolves {null} */ -let reference_compare_files = function reference_compare_files(a, b, test) { +var reference_compare_files = function reference_compare_files(a, b, test) { test.info("Comparing files " + a + " and " + b); let a_contents = yield reference_fetch_file(a, test); let b_contents = yield reference_fetch_file(b, test); is(a_contents, b_contents, "Contents of files " + a + " and " + b + " match"); }; -let reference_dir_contents = function reference_dir_contents(path) { +var reference_dir_contents = function reference_dir_contents(path) { let result = []; let entries = new FileUtils.File(path).directoryEntries; while (entries.hasMoreElements()) { @@ -149,7 +149,7 @@ function toggleDebugTest (pref, consoleListener) { consoleListener); } -let test = maketest("Main", function main(test) { +var test = maketest("Main", function main(test) { return Task.spawn(function() { SimpleTest.waitForExplicitFinish(); yield test_stat(); @@ -167,13 +167,13 @@ let test = maketest("Main", function main(test) { /** * A file that we know exists and that can be used for reading. */ -let EXISTING_FILE = OS.Path.join("chrome", "toolkit", "components", +var EXISTING_FILE = OS.Path.join("chrome", "toolkit", "components", "osfile", "tests", "mochi", "main_test_osfile_async.js"); /** * Test OS.File.stat and OS.File.prototype.stat */ -let test_stat = maketest("stat", function stat(test) { +var test_stat = maketest("stat", function stat(test) { return Task.spawn(function() { // Open a file and stat it let file = yield OS.File.open(EXISTING_FILE); @@ -202,7 +202,7 @@ let test_stat = maketest("stat", function stat(test) { /** * Test feature detection using OS.File.Info.prototype on main thread */ -let test_info_features_detect = maketest("features_detect", function features_detect(test) { +var test_info_features_detect = maketest("features_detect", function features_detect(test) { return Task.spawn(function() { if (OS.Constants.Win) { // see if winBirthDate is defined @@ -225,7 +225,7 @@ let test_info_features_detect = maketest("features_detect", function features_de /** * Test file.{getPosition, setPosition} */ -let test_position = maketest("position", function position(test) { +var test_position = maketest("position", function position(test) { return Task.spawn(function() { let file = yield OS.File.open(EXISTING_FILE); @@ -256,7 +256,7 @@ let test_position = maketest("position", function position(test) { /** * Test OS.File.prototype.{DirectoryIterator} */ -let test_iter = maketest("iter", function iter(test) { +var test_iter = maketest("iter", function iter(test) { return Task.spawn(function() { let currentDir = yield OS.File.getCurrentDirectory(); @@ -381,7 +381,7 @@ let test_iter = maketest("iter", function iter(test) { /** * Test OS.File.prototype.{exists} */ -let test_exists = maketest("exists", function exists(test) { +var test_exists = maketest("exists", function exists(test) { return Task.spawn(function() { let fileExists = yield OS.File.exists(EXISTING_FILE); test.ok(fileExists, "file exists"); @@ -393,7 +393,7 @@ let test_exists = maketest("exists", function exists(test) { /** * Test changes to OS.Shared.DEBUG flag. */ -let test_debug = maketest("debug", function debug(test) { +var test_debug = maketest("debug", function debug(test) { return Task.spawn(function() { function testSetDebugPref (pref) { try { @@ -418,7 +418,7 @@ let test_debug = maketest("debug", function debug(test) { * Test logging in the main thread with set OS.Shared.DEBUG and * OS.Shared.TEST flags. */ -let test_debug_test = maketest("debug_test", function debug_test(test) { +var test_debug_test = maketest("debug_test", function debug_test(test) { return Task.spawn(function () { // Create a console listener. let consoleListener = { diff --git a/toolkit/components/osfile/tests/mochi/worker_test_osfile_comms.js b/toolkit/components/osfile/tests/mochi/worker_test_osfile_comms.js index fff2fb0d2e..5e8bdd9caa 100644 --- a/toolkit/components/osfile/tests/mochi/worker_test_osfile_comms.js +++ b/toolkit/components/osfile/tests/mochi/worker_test_osfile_comms.js @@ -7,7 +7,7 @@ importScripts('worker_test_osfile_shared.js'); // The set of samples for communications test. Declare as a global // variable to prevent this from being garbage-collected too early. -let samples; +var samples; self.onmessage = function(msg) { info("Initializing"); diff --git a/toolkit/components/osfile/tests/mochi/worker_test_osfile_front.js b/toolkit/components/osfile/tests/mochi/worker_test_osfile_front.js index 02b2ced35d..f6d840dcd7 100644 --- a/toolkit/components/osfile/tests/mochi/worker_test_osfile_front.js +++ b/toolkit/components/osfile/tests/mochi/worker_test_osfile_front.js @@ -4,7 +4,7 @@ importScripts('worker_test_osfile_shared.js'); importScripts("resource://gre/modules/workers/require.js"); -let SharedAll = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm"); +var SharedAll = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm"); SharedAll.Config.DEBUG = true; function should_throw(f) { diff --git a/toolkit/components/osfile/tests/xpcshell/head.js b/toolkit/components/osfile/tests/xpcshell/head.js index b24f9d415d..eef29962af 100644 --- a/toolkit/components/osfile/tests/xpcshell/head.js +++ b/toolkit/components/osfile/tests/xpcshell/head.js @@ -3,9 +3,9 @@ "use strict"; -let {utils: Cu, interfaces: Ci} = Components; +var {utils: Cu, interfaces: Ci} = Components; -let {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {}); +var {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {}); // Bug 1014484 can only be reproduced by loading OS.File first from the // CommonJS loader, so we do not want OS.File to be loaded eagerly for @@ -19,8 +19,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", XPCOMUtils.defineLazyModuleGetter(this, "Services", "resource://gre/modules/Services.jsm"); -let {Promise} = Cu.import("resource://gre/modules/Promise.jsm", {}); -let {Task} = Cu.import("resource://gre/modules/Task.jsm", {}); +var {Promise} = Cu.import("resource://gre/modules/Promise.jsm", {}); +var {Task} = Cu.import("resource://gre/modules/Task.jsm", {}); Services.prefs.setBoolPref("toolkit.osfile.log", true); diff --git a/toolkit/components/osfile/tests/xpcshell/test_duration.js b/toolkit/components/osfile/tests/xpcshell/test_duration.js index ad1cb31389..305c03da86 100644 --- a/toolkit/components/osfile/tests/xpcshell/test_duration.js +++ b/toolkit/components/osfile/tests/xpcshell/test_duration.js @@ -1,5 +1,5 @@ -let {OS} = Components.utils.import("resource://gre/modules/osfile.jsm", {}); -let {Services} = Components.utils.import("resource://gre/modules/Services.jsm", {}); +var {OS} = Components.utils.import("resource://gre/modules/osfile.jsm", {}); +var {Services} = Components.utils.import("resource://gre/modules/Services.jsm", {}); /** * Test optional duration reporting that can be used for telemetry. diff --git a/toolkit/components/osfile/tests/xpcshell/test_exception.js b/toolkit/components/osfile/tests/xpcshell/test_exception.js index 976d04b95b..1282adb3e1 100644 --- a/toolkit/components/osfile/tests/xpcshell/test_exception.js +++ b/toolkit/components/osfile/tests/xpcshell/test_exception.js @@ -7,7 +7,7 @@ "use strict"; -let EXISTING_FILE = do_get_file("xpcshell.ini").path; +var EXISTING_FILE = do_get_file("xpcshell.ini").path; // Tests on |open| diff --git a/toolkit/components/osfile/tests/xpcshell/test_loader.js b/toolkit/components/osfile/tests/xpcshell/test_loader.js index 9eb0edee9e..dcfa819be8 100644 --- a/toolkit/components/osfile/tests/xpcshell/test_loader.js +++ b/toolkit/components/osfile/tests/xpcshell/test_loader.js @@ -7,7 +7,7 @@ * Test that OS.File can be loaded using the CommonJS loader. */ -let { Loader } = Components.utils.import('resource://gre/modules/commonjs/toolkit/loader.js', {}); +var { Loader } = Components.utils.import('resource://gre/modules/commonjs/toolkit/loader.js', {}); function run_test() { run_next_test(); diff --git a/toolkit/components/osfile/tests/xpcshell/test_makeDir.js b/toolkit/components/osfile/tests/xpcshell/test_makeDir.js index 969050d9b3..5b9740a7ff 100644 --- a/toolkit/components/osfile/tests/xpcshell/test_makeDir.js +++ b/toolkit/components/osfile/tests/xpcshell/test_makeDir.js @@ -7,8 +7,8 @@ Components.utils.import("resource://gre/modules/osfile.jsm"); Components.utils.import("resource://gre/modules/Services.jsm"); -let Path = OS.Path; -let profileDir; +var Path = OS.Path; +var profileDir; do_register_cleanup(function() { Services.prefs.setBoolPref("toolkit.osfile.log", false); diff --git a/toolkit/components/osfile/tests/xpcshell/test_osfile_async_append.js b/toolkit/components/osfile/tests/xpcshell/test_osfile_async_append.js index 06660ecc51..0aef2c58af 100644 --- a/toolkit/components/osfile/tests/xpcshell/test_osfile_async_append.js +++ b/toolkit/components/osfile/tests/xpcshell/test_osfile_async_append.js @@ -104,7 +104,7 @@ function test_no_append(mode) { } } -let test_flags = [ +var test_flags = [ {}, {create:true}, {trunc:true} diff --git a/toolkit/components/osfile/tests/xpcshell/test_osfile_async_copy.js b/toolkit/components/osfile/tests/xpcshell/test_osfile_async_copy.js index 9b71f577dd..9c52c8a80d 100644 --- a/toolkit/components/osfile/tests/xpcshell/test_osfile_async_copy.js +++ b/toolkit/components/osfile/tests/xpcshell/test_osfile_async_copy.js @@ -15,7 +15,7 @@ function run_test() { /** * A file that we know exists and that can be used for reading. */ -let EXISTING_FILE = "test_osfile_async_copy.js"; +var EXISTING_FILE = "test_osfile_async_copy.js"; /** * Fetch asynchronously the contents of a file using xpcom. @@ -26,7 +26,7 @@ let EXISTING_FILE = "test_osfile_async_copy.js"; * @return {promise} * @resolves {string} The contents of the file. */ -let reference_fetch_file = function reference_fetch_file(path) { +var reference_fetch_file = function reference_fetch_file(path) { let promise = Promise.defer(); let file = new FileUtils.File(path); NetUtil.asyncFetch({ @@ -64,7 +64,7 @@ let reference_fetch_file = function reference_fetch_file(path) { * * @resolves {null} */ -let reference_compare_files = function reference_compare_files(a, b) { +var reference_compare_files = function reference_compare_files(a, b) { let a_contents = yield reference_fetch_file(a); let b_contents = yield reference_fetch_file(b); // Not using do_check_eq to avoid dumping the whole file to the log. diff --git a/toolkit/components/osfile/tests/xpcshell/test_osfile_async_setPermissions.js b/toolkit/components/osfile/tests/xpcshell/test_osfile_async_setPermissions.js index bcb835c296..2154816279 100644 --- a/toolkit/components/osfile/tests/xpcshell/test_osfile_async_setPermissions.js +++ b/toolkit/components/osfile/tests/xpcshell/test_osfile_async_setPermissions.js @@ -39,7 +39,7 @@ function apply_umask(mode) { // Sequence of setPermission parameters and expected file mode. The first test // checks the permissions when the file is first created. -let testSequence = [ +var testSequence = [ [null, apply_umask(0o600)], [{ unixMode: 0o4777 }, apply_umask(0o4777)], [{ unixMode: 0o4777, unixHonorUmask: false }, 0o4777], diff --git a/toolkit/components/osfile/tests/xpcshell/test_osfile_error.js b/toolkit/components/osfile/tests/xpcshell/test_osfile_error.js index 72643102aa..a1c319eca7 100644 --- a/toolkit/components/osfile/tests/xpcshell/test_osfile_error.js +++ b/toolkit/components/osfile/tests/xpcshell/test_osfile_error.js @@ -3,7 +3,7 @@ "use strict"; -let {OS: {File, Path, Constants}} = Components.utils.import("resource://gre/modules/osfile.jsm", {}); +var {OS: {File, Path, Constants}} = Components.utils.import("resource://gre/modules/osfile.jsm", {}); Components.utils.import("resource://gre/modules/Task.jsm"); function run_test() { diff --git a/toolkit/components/osfile/tests/xpcshell/test_osfile_win_async_setPermissions.js b/toolkit/components/osfile/tests/xpcshell/test_osfile_win_async_setPermissions.js index 20adf57277..990d722f5c 100644 --- a/toolkit/components/osfile/tests/xpcshell/test_osfile_win_async_setPermissions.js +++ b/toolkit/components/osfile/tests/xpcshell/test_osfile_win_async_setPermissions.js @@ -11,7 +11,7 @@ */ // Sequence of setPermission parameters. -let testSequence = [ +var testSequence = [ [ { winAttributes: { readOnly: true, system: true, hidden: true } }, { readOnly: true, system: true, hidden: true } ], [ { winAttributes: { readOnly: false } }, diff --git a/toolkit/components/osfile/tests/xpcshell/test_osfile_writeAtomic_backupTo_option.js b/toolkit/components/osfile/tests/xpcshell/test_osfile_writeAtomic_backupTo_option.js index 27867cc459..adf345b0c6 100644 --- a/toolkit/components/osfile/tests/xpcshell/test_osfile_writeAtomic_backupTo_option.js +++ b/toolkit/components/osfile/tests/xpcshell/test_osfile_writeAtomic_backupTo_option.js @@ -3,7 +3,7 @@ "use strict"; -let {OS: {File, Path, Constants}} = Components.utils.import("resource://gre/modules/osfile.jsm", {}); +var {OS: {File, Path, Constants}} = Components.utils.import("resource://gre/modules/osfile.jsm", {}); Components.utils.import("resource://gre/modules/Task.jsm"); /** diff --git a/toolkit/components/osfile/tests/xpcshell/test_osfile_writeAtomic_zerobytes.js b/toolkit/components/osfile/tests/xpcshell/test_osfile_writeAtomic_zerobytes.js index fbcfd7215c..beaefde727 100644 --- a/toolkit/components/osfile/tests/xpcshell/test_osfile_writeAtomic_zerobytes.js +++ b/toolkit/components/osfile/tests/xpcshell/test_osfile_writeAtomic_zerobytes.js @@ -2,7 +2,7 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; -let SHARED_PATH; +var SHARED_PATH; add_task(function* init() { do_get_profile(); @@ -24,4 +24,4 @@ add_test_pair(function* test_osfile_writeAtomic_zerobytes() { function run_test() { run_next_test(); -} \ No newline at end of file +} diff --git a/toolkit/components/osfile/tests/xpcshell/test_path.js b/toolkit/components/osfile/tests/xpcshell/test_path.js index 779709bcf8..2c76c86186 100644 --- a/toolkit/components/osfile/tests/xpcshell/test_path.js +++ b/toolkit/components/osfile/tests/xpcshell/test_path.js @@ -8,13 +8,13 @@ Components.utils.import("resource://gre/modules/Services.jsm", this); Services.prefs.setBoolPref("toolkit.osfile.test.syslib_necessary", false); // We don't need libc/kernel32.dll for this test -let ImportWin = {}; -let ImportUnix = {}; +var ImportWin = {}; +var ImportUnix = {}; Components.utils.import("resource://gre/modules/osfile/ospath_win.jsm", ImportWin); Components.utils.import("resource://gre/modules/osfile/ospath_unix.jsm", ImportUnix); -let Win = ImportWin; -let Unix = ImportUnix; +var Win = ImportWin; +var Unix = ImportUnix; function do_check_fail(f) { diff --git a/toolkit/components/osfile/tests/xpcshell/test_read_write.js b/toolkit/components/osfile/tests/xpcshell/test_read_write.js index 94856be83f..00235ed8c5 100644 --- a/toolkit/components/osfile/tests/xpcshell/test_read_write.js +++ b/toolkit/components/osfile/tests/xpcshell/test_read_write.js @@ -3,11 +3,11 @@ "use strict"; -let {utils: Cu} = Components; +var {utils: Cu} = Components; -let SHARED_PATH; +var SHARED_PATH; -let EXISTING_FILE = do_get_file("xpcshell.ini").path; +var EXISTING_FILE = do_get_file("xpcshell.ini").path; add_task(function* init() { do_get_profile(); diff --git a/toolkit/components/osfile/tests/xpcshell/test_reset.js b/toolkit/components/osfile/tests/xpcshell/test_reset.js index ce56bb63b5..f1e1b14d14 100644 --- a/toolkit/components/osfile/tests/xpcshell/test_reset.js +++ b/toolkit/components/osfile/tests/xpcshell/test_reset.js @@ -1,7 +1,7 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ -let Path = OS.Constants.Path; +var Path = OS.Constants.Path; add_task(function* init() { do_get_profile(); diff --git a/toolkit/components/osfile/tests/xpcshell/test_telemetry.js b/toolkit/components/osfile/tests/xpcshell/test_telemetry.js index 09fd8639fe..dc5104443d 100644 --- a/toolkit/components/osfile/tests/xpcshell/test_telemetry.js +++ b/toolkit/components/osfile/tests/xpcshell/test_telemetry.js @@ -1,7 +1,7 @@ "use strict"; -let {OS: {File, Path, Constants}} = Components.utils.import("resource://gre/modules/osfile.jsm", {}); -let {Services} = Components.utils.import("resource://gre/modules/Services.jsm", {}); +var {OS: {File, Path, Constants}} = Components.utils.import("resource://gre/modules/osfile.jsm", {}); +var {Services} = Components.utils.import("resource://gre/modules/Services.jsm", {}); // Ensure that we have a profile but that the OS.File worker is not launched add_task(function* init() { diff --git a/toolkit/components/passwordmgr/crypto-SDR.js b/toolkit/components/passwordmgr/crypto-SDR.js index d916e5ff74..b64dab0775 100644 --- a/toolkit/components/passwordmgr/crypto-SDR.js +++ b/toolkit/components/passwordmgr/crypto-SDR.js @@ -217,5 +217,5 @@ LoginManagerCrypto_SDR.prototype = { }, }; // end of nsLoginManagerCrypto_SDR implementation -let component = [LoginManagerCrypto_SDR]; +var component = [LoginManagerCrypto_SDR]; this.NSGetFactory = XPCOMUtils.generateNSGetFactory(component); diff --git a/toolkit/components/perfmonitoring/PerformanceStats-content.js b/toolkit/components/perfmonitoring/PerformanceStats-content.js index 79ca340efb..46ef5ad210 100644 --- a/toolkit/components/perfmonitoring/PerformanceStats-content.js +++ b/toolkit/components/perfmonitoring/PerformanceStats-content.js @@ -12,7 +12,7 @@ "use strict"; -const { utils: Cu, classes: Cc, interfaces: Ci } = Components; +var { utils: Cu, classes: Cc, interfaces: Ci } = Components; const { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); const { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {}); @@ -32,12 +32,12 @@ XPCOMUtils.defineLazyModuleGetter(this, "Task", * * In the parent, this is always an empty monitor. */ -let gMonitor = PerformanceStats.getMonitor([]); +var gMonitor = PerformanceStats.getMonitor([]); /** * `true` if this is a content process, `false` otherwise. */ -let isContent = Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT; +var isContent = Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT; /** * Handle message `performance-stats-service-acquire`: ensure that the global diff --git a/toolkit/devtools/animationinspector/animation-controller.js b/toolkit/devtools/animationinspector/animation-controller.js index e23912f29e..d7cb90cbfe 100644 --- a/toolkit/devtools/animationinspector/animation-controller.js +++ b/toolkit/devtools/animationinspector/animation-controller.js @@ -6,7 +6,7 @@ "use strict"; -const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; +var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; Cu.import("resource://gre/modules/Task.jsm"); Cu.import("resource://gre/modules/devtools/Loader.jsm"); diff --git a/toolkit/devtools/animationinspector/test/head.js b/toolkit/devtools/animationinspector/test/head.js index c9960c464a..2630c998e2 100644 --- a/toolkit/devtools/animationinspector/test/head.js +++ b/toolkit/devtools/animationinspector/test/head.js @@ -4,7 +4,7 @@ "use strict"; -const Cu = Components.utils; +var Cu = Components.utils; const {gDevTools} = Cu.import("resource://gre/modules/devtools/gDevTools.jsm", {}); const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}); const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {}); diff --git a/toolkit/devtools/app-manager/content/connection-footer.js b/toolkit/devtools/app-manager/content/connection-footer.js index 4ff809a4d7..8e6c40d71c 100644 --- a/toolkit/devtools/app-manager/content/connection-footer.js +++ b/toolkit/devtools/app-manager/content/connection-footer.js @@ -2,8 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -const Cu = Components.utils; -const Ci = Components.interfaces; +var Cu = Components.utils; +var Ci = Components.interfaces; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/devtools/gDevTools.jsm"); diff --git a/toolkit/mozapps/installer/upload-files.mk b/toolkit/mozapps/installer/upload-files.mk index 54353a94c4..7e9cccd3f4 100644 --- a/toolkit/mozapps/installer/upload-files.mk +++ b/toolkit/mozapps/installer/upload-files.mk @@ -335,7 +335,7 @@ UPLOAD_EXTRA_FILES += ../embedding/android/geckoview_example/geckoview_example.a # Robocop/Robotium tests, Android Background tests, and Fennec need to # be signed with the same key, which means release signing them all. -ROBOCOP_PATH = $(abspath $(_ABS_DIST)/../build/mobile/robocop) +ROBOCOP_PATH = $(abspath $(DEPTH)/mobile/android/tests/browser/robocop) # Normally, $(NSINSTALL) would be used instead of cp, but INNER_ROBOCOP_PACKAGE # is used in a series of commands that run under a "cd something", while # $(NSINSTALL) is relative.