Bug 500142 Create mozmill and mozmill-one make targets for build automation to use - add the initial targets. r=asuth,gozer
--- a/mail/Makefile.in
+++ b/mail/Makefile.in
@@ -47,16 +47,20 @@ DIRS = base locales components extensio
ifeq ($(OS_ARCH),WINNT)
ifdef MOZ_INSTALLER
# though some lasts are more last than others
DIRS += installer/windows
endif
endif
+ifdef ENABLE_TESTS
+DIRS += test/mozmill
+endif
+
include $(topsrcdir)/config/rules.mk
ifeq ($(OS_ARCH),WINNT)
ifdef MOZ_INSTALLER
# For Windows build the uninstaller during the application build since the
# uninstaller is included with the application for mar file generation.
libs::
--- a/mail/build.mk
+++ b/mail/build.mk
@@ -93,8 +93,39 @@ package-compare:
install::
@$(MAKE) -C mail/installer install
source-package::
@$(MAKE) -C mail/installer source-package
upload::
@$(MAKE) -C mail/installer upload
+
+# Instructions below this line are for mail/ specific tests.
+
+MOZMILLDIR=$(DEPTH)/mozilla/_tests/mozmill
+
+PROGRAM = $(DIST)
+
+ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT)))
+# Mac options
+APP_NAME = $(MOZ_APP_DISPLAYNAME)
+ifdef MOZ_DEBUG
+APP_NAME := $(APP_NAME)Debug
+endif
+PROGRAM = ../../../$(DIST)/$(APP_NAME).app/Contents/MacOS/
+PROGRAM := $(PROGRAM)thunderbird-bin$(BIN_SUFFIX)
+else
+# Non-mac options
+PROGRAM = ../../../$(DIST)/bin/
+PROGRAM := $(PROGRAM)thunderbird$(BIN_SUFFIX)
+endif
+
+ifdef ENABLE_TESTS
+mozmill::
+ cd $(MOZMILLDIR) && MACOSX_DEPLOYMENT_TARGET= $(PYTHON) \
+ runtestlist.py --list=mozmilltests.list --binary=$(PROGRAM) \
+ --dir=$(topsrcdir)/mail/test/mozmill
+
+mozmill-one::
+ cd $(MOZMILLDIR) && MACOSX_DEPLOYMENT_TARGET= $(PYTHON) runtest.py \
+ --test=$(topsrcdir)/mail/test/mozmill/$(SOLO_TEST) --binary=$(PROGRAM)
+endif
--- a/mail/makefiles.sh
+++ b/mail/makefiles.sh
@@ -56,16 +56,17 @@ mail/extensions/Makefile
mail/extensions/mailviews/Makefile
mail/extensions/smime/Makefile
mail/installer/Makefile
mail/installer/windows/Makefile
mail/themes/Makefile
mail/themes/pinstripe/Makefile
mail/themes/qute/Makefile
mail/themes/gnomestripe/Makefile
+mail/test/mozmill/Makefile
"
if test -n "$MOZ_BRANDING_DIRECTORY"; then
add_makefiles "
$MOZ_BRANDING_DIRECTORY/Makefile
$MOZ_BRANDING_DIRECTORY/locales/Makefile
"
fi
new file mode 100644
--- /dev/null
+++ b/mail/test/mozmill/Makefile.in
@@ -0,0 +1,73 @@
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 1998
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = mozmill
+
+include $(topsrcdir)/config/rules.mk
+
+# We're installing to _tests/mozmill
+TARGET_DEPTH = ../..
+include $(MOZILLA_DIR)/build/automation-build.mk
+
+_DEST_DIR = $(MOZDEPTH)/_tests/mozmill
+
+_HARNESS_FILES = \
+ $(srcdir)/runtest.py \
+ $(srcdir)/runtestlist.py \
+ $(srcdir)/mozmilltests.list \
+ automation.py \
+ $(NULL)
+
+GARBAGE += automation.py
+
+$(_DEST_DIR):
+ echo $(_HARNESS_FILES)
+ $(NSINSTALL) -D $@
+
+$(_HARNESS_FILES): $(_DEST_DIR)
+
+# Copy the mozmill bits to $(_DEST_DIR)
+libs:: $(_HARNESS_FILES)
+ echo $(_HARNESS_FILES)
+ $(INSTALL) $(_HARNESS_FILES) $(_DEST_DIR)
new file mode 100644
--- /dev/null
+++ b/mail/test/mozmill/mozmilltests.list
@@ -0,0 +1,4 @@
+bloat
+folder-display
+junk-commands
+search-window
--- a/mail/test/mozmill/runtest.py
+++ b/mail/test/mozmill/runtest.py
@@ -46,16 +46,19 @@ Runs the Bloat test harness
import sys
import os
import shutil
import mozrunner
import jsbridge
import mozmill
import socket
import copy
+SCRIPT_DIRECTORY = os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0])))
+sys.path.append(SCRIPT_DIRECTORY)
+import automation
from time import sleep
# We need this because rmtree-ing read-only files fails on Windows
def rmtree_onerror(func, path, exc_info):
"""
Error handler for ``shutil.rmtree``.
If the error is due to an access error (read only file)
@@ -128,91 +131,33 @@ class ThunderTestProfile(mozrunner.Thund
'mail.smtpservers' : "smtp1",
'mail.startup.enabledMailCheckOnce' : True,
'mailnews.start_page_override.mstone' : "ignore",
}
def __init__(self, default_profile=None, profile=None, create_new=True,
plugins=[], preferences={}):
self.init_env()
- self.init_paths()
+ self.profile_dir = os.path.join(SCRIPT_DIRECTORY, 'mozmillprofile')
+
mozrunner.Profile.__init__(self, default_profile, profile, create_new, plugins, preferences)
- def init_paths(self):
- global automation
- self.src_dir = self.find_src_dir()
- self.obj_dir = self.find_obj_dir()
-
- self.automation_dir = os.path.join(self.obj_dir, 'mozilla', 'build')
- sys.path.append(self.automation_dir)
- import automation
-
- self.profile_dir = os.path.join(self.obj_dir, 'mozilla',
- '_tests', 'leakprofile')
- # XXX tidy up
- if automation.IS_MAC:
- if automation.IS_DEBUG_BUILD:
- appName = 'ShredderDebug.app'
- else:
- appName = 'Shredder.app'
- self.bin_dir = os.path.join(self.obj_dir, 'mozilla', 'dist', appName, 'Contents', 'MacOS')
- appname = 'thunderbird-bin'
- else:
- self.bin_dir = os.path.join(self.obj_dir, 'mozilla', 'dist', 'bin')
- appname = 'thunderbird'
- if automation.IS_WIN32:
- appname += '.exe'
-
- self.app_path = os.path.join(self.bin_dir, appname)
-
- self.base_test_dir = os.getcwd()
-
-
- def find_src_dir(self):
- curdir = os.getcwd()
- while not os.path.isdir(os.path.join(curdir, '.hg')):
- curdir, olddir = os.path.split(curdir)
- if curdir == '':
- raise Exception("unable to figure out src_dir")
- return os.path.expanduser(os.path.expandvars(curdir))
-
- def find_obj_dir(self):
- if 'MOZCONFIG' in os.environ:
- mozconfig_path = os.environ['MOZCONFIG']
- else:
- mozconfig_path = os.path.join(self.src_dir, '.mozconfig.mk')
-
- guess_path = os.path.join(self.src_dir, 'mozilla/build/autoconf/config.guess')
- config_guess = os.popen("sh " + guess_path).read()
- config_guess = config_guess.strip()
- f = open(mozconfig_path, 'rt')
- for line in f:
- if 'MOZ_OBJDIR' in line:
- varpath = line.split('=')[1].strip()
- varpath = varpath.replace('@TOPSRCDIR@', self.src_dir)
- varpath = varpath.replace('$(TOPSRCDIR)', self.src_dir)
- varpath = varpath.replace('@CONFIG_GUESS@',config_guess)
- return os.path.expanduser(os.path.expandvars(varpath))
- f.close()
-
- raise Exception("unable to figure out obj_dir")
-
def init_env(self):
self.base_env = dict(os.environ)
# note, we do NOT want to set NO_EM_RESTART or jsbridge wouldn't work
# avoid dialogs on windows
self.base_env['XPCOM_DEBUG_BREAK'] = 'stack'
# do not reuse an existing instance
self.base_env['MOZ_NO_REMOTE'] = '1'
def _run(self, *args, **extraenv):
env = self.base_env.copy()
env.update(extraenv)
- allArgs = [self.app_path]
+ allArgs = [BINARY]
allArgs.extend(args)
proc = automation.Process(allArgs, env=env)
status = proc.wait()
def create_new_profile(self, default_profile):
# create a clean directory
if os.path.exists(self.profile_dir):
shutil.rmtree(self.profile_dir, onerror=rmtree_onerror)
@@ -243,17 +188,16 @@ class ThunderTestRunner(mozrunner.Thunde
class ThunderTestCLI(mozmill.CLI):
profile_class = ThunderTestProfile
runner_class = ThunderTestRunner
parser_options = copy.copy(mozmill.CLI.parser_options)
parser_options[('-m', '--bloat-tests')] = {"default":None, "dest":"created_profile", "help":"Log file name."}
-
def parse_and_get_runner(self):
"""Parses the command line arguments and returns a runner instance."""
(options, args) = self.parser.parse_args()
self.options = options
self.args = args
if self.options.plugins is None:
plugins = []
else:
@@ -272,16 +216,23 @@ class ThunderTestCLI(mozmill.CLI):
shutil.copytree(profilename, workingprofile, False)
crea_new = False
def_profile = False
else:
def_profile = options.default_profile
workingprofile = options.profile
crea_new = options.create_new
+ # We use a global as there appears to be no easy way of getting the
+ # binary details into the profile without re-implementing what mozmill
+ # gives us.
+ global BINARY
+ BINARY = self.options.binary
+ print BINARY
+
profile = self.get_profile(def_profile,
workingprofile, crea_new,
plugins=plugins)
runner = self.get_runner(binary=self.options.binary,
profile=profile)
return runner
@@ -329,17 +280,20 @@ def prettyPrintException(e):
else:
print ' ', prettifyFilename(path), line
import pprint
def prettyPrintResults():
for result in TEST_RESULTS:
#pprint.pprint(result)
- print 'TEST', result['name'], len(result['fails']) and "FAILED" or "PASSED"
+ if len(result['fails']) == 0:
+ print 'TEST-PASS | ', result['name']
+ else:
+ print 'TEST-UNEXPECTED-FAIL | ', result['name']
for failure in result['fails']:
if 'exception' in failure:
prettyPrintException(failure['exception'])
import atexit
atexit.register(prettyPrintResults)
if __name__ == '__main__':
new file mode 100644
--- /dev/null
+++ b/mail/test/mozmill/runtestlist.py
@@ -0,0 +1,140 @@
+#!/usr/bin/env python
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Mail Bloat Test.
+#
+# The Initial Developer of the Original Code is
+# Mozilla Messaging.
+# Portions created by the Initial Developer are Copyright (C) 2008
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Mark Banner <bugzilla@standard8.plus.com>
+# Andrew Sutherland <bugzilla@asutherland.org>
+# Ludovic Hirlimann <ludovic@hirlimann.net>
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+import optparse
+import sys
+import os
+import shutil
+import subprocess
+import logging
+
+SCRIPT_DIRECTORY = os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0])))
+
+class RunTestListOptions(optparse.OptionParser):
+ """Parsed run test list command line options."""
+ def __init__(self, **kwargs):
+ optparse.OptionParser.__init__(self, **kwargs)
+ defaults = {}
+
+ self.add_option("--binary",
+ action = "store", type = "string", dest = "binary",
+ help = "Binary to be run")
+ defaults["binary"] = ""
+
+ self.add_option("--list",
+ action = "store", type = "string", dest = "list",
+ help = "List of tests to be run")
+ defaults["list"] = ""
+
+ self.add_option("--dir",
+ action = "store", type = "string", dest = "dir",
+ help = "Directory of the tests, leave blank for current directory")
+ defaults["dir"] = ""
+
+ self.set_defaults(**defaults);
+
+ usage = """\
+Usage instructions for runtestlist.py
+All arguments must be specified.
+"""
+ self.set_usage(usage)
+
+log = logging.getLogger()
+handler = logging.StreamHandler(sys.stdout)
+log.setLevel(logging.INFO)
+log.addHandler(handler)
+
+parser = RunTestListOptions()
+options, args = parser.parse_args()
+
+if options.binary == "" or options.list == "":
+ parser.print_help()
+ sys.exit(1)
+
+totalTestErrors = 0
+totalTestPasses = 0
+totalDirectories = 0
+
+f = open(options.list, 'rt')
+for directory in f:
+ log.info("INFO | (runtestlist.py) | Running directory: %s",
+ directory.rstrip())
+ if options.dir != "":
+ testDirectory = os.path.join(options.dir, directory.rstrip())
+ else:
+ testDirectory = directory.rstrip()
+ args = ["python", "runtest.py", "-t", testDirectory, "--binary",
+ options.binary]
+ print args
+ outputPipe = subprocess.PIPE
+
+ proc = subprocess.Popen(args, cwd=SCRIPT_DIRECTORY, stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
+
+ testErrors = 0
+ testPasses = 0
+
+ line = proc.stdout.readline()
+ while line != "":
+ log.info(line.rstrip())
+ if line.find("TEST-UNEXPECTED-") != -1:
+ testErrors += 1
+ if line.find("TEST-PASS") != -1:
+ testPasses += 1
+ line = proc.stdout.readline()
+
+ result = proc.wait()
+
+ if result != 0:
+ log.info("TEST-UNEXPECTED-FAIL | (runtestlist.py) | Exited with code %d during directory run", result)
+ totalTestErrors += 1
+ else:
+ totalTestPasses += 1
+
+ log.info("INFO | (runtestlist.py) | %s: %d passed, %d failed",
+ directory.rstrip(), testPasses, testErrors)
+ totalTestErrors += testErrors
+ totalTestPasses += testPasses
+ totalDirectories += 1
+
+
+log.info("INFO | (runtestlist.py) | Directories Run: %d, Passed: %d, Failed: %d",
+ totalDirectories, totalTestPasses, totalTestErrors)
+
+if totalTestErrors:
+ sys.exit(1)