Updated Branches: refs/heads/4.3 0533001fe -> 11d8c4618
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/11d8c461/tools/marvin/marvin/misc/build/xen.cfg ---------------------------------------------------------------------- diff --git a/tools/marvin/marvin/misc/build/xen.cfg b/tools/marvin/marvin/misc/build/xen.cfg new file mode 100644 index 0000000..bdeacda --- /dev/null +++ b/tools/marvin/marvin/misc/build/xen.cfg @@ -0,0 +1,225 @@ +{ + "zones": [ + { + "name": "z0", + "guestcidraddress": "10.1.1.0/24", + "dns2": "8.8.8.8", + "dns1": "8.8.8.8", + "physical_networks": [ + { + "name": "z0-pnet", + "providers": [ + { + "broadcastdomainrange": "ZONE", + "name": "VirtualRouter" + }, + { + "broadcastdomainrange": "ZONE", + "name": "VpcVirtualRouter" + }, + { + "broadcastdomainrange": "ZONE", + "name": "InternalLbVm" + } + ], + "broadcastdomainrange": "Zone", + "vlan": "2001-2050", + "traffictypes": [ + { + "typ": "Guest" + }, + { + "typ": "Management" + }, + { + "typ": "Public" + } + ], + "isolationmethods": [ + "VLAN" + ] + } + ], + "securitygroupenabled": "false", + "ipranges": [ + { + "startip": "10.208.10.10", + "endip": "10.208.10.62", + "netmask": "255.255.255.192", + "vlan": "100", + "gateway": "10.208.10.1" + }, + { + "startip": "10.208.10.66", + "endip": "10.208.10.126", + "netmask": "255.255.255.192", + "vlan": "101", + "gateway": "10.208.10.65" + } + ], + "networktype": "Advanced", + "pods": [ + { + "endip": "10.208.8.75", + "name": "z0p0", + "startip": "10.208.8.70", + "netmask": "255.255.255.192", + "clusters": [ + { + "clustername": "z0p0c0", + "hypervisor": "XenServer", + "hosts": [ + { + "username": "root", + "url": "http://apache-81-3", + "password": "password" + }, + { + "username": "root", + "url": "http://apache-81-2", + "password": "password" + } + ], + "clustertype": "CloudManaged", + "primaryStorages": [ + { + "url": "nfs://nfs.fmt.vmops.com:/export/automation/acs/primary", + "name": "z0p0c0ps0" + }, + { + "url": "nfs://nfs.fmt.vmops.com:/export/automation/acs/primary1", + "name": "z0p0c0ps1" + } + ] + } + ], + "gateway": "10.208.8.65" + }, + { + "endip": "10.208.8.205", + "name": "z0p1", + "startip": "10.208.8.200", + "netmask": "255.255.255.192", + "clusters": [ + { + "clustername": "z0p1c0", + "hypervisor": "XenServer", + "hosts": [ + { + "username": "root", + "url": "http://apache-83-1", + "password": "password" + } + ], + "clustertype": "CloudManaged", + "primaryStorages": [ + { + "url": "nfs://nfs.fmt.vmops.com:/export/automation/acs/primary2", + "name": "z0p1c0ps0" + } + ] + } + ], + "gateway": "10.208.8.193" + } + ], + "internaldns1": "10.208.8.5", + "internaldns2": "10.208.8.5", + "secondaryStorages": [ + { + "url": "nfs://nfs.fmt.vmops.com:/export/automation/acs/secondary", + "provider": "NFS" + } + ] + } + ], + "dbSvr": { + "dbSvr": "cloudstack-centos63", + "passwd": "cloud", + "db": "cloud", + "port": 3306, + "user": "cloud" + }, + "logger": [ + { + "name": "TestClient", + "file": "/var/log/testclient.log" + }, + { + "name": "TestCase", + "file": "/var/log/testcase.log" + } + ], + "globalConfig": [ + { + "name": "storage.cleanup.interval", + "value": "120" + }, + { + "name": "direct.agent.load.size", + "value": "1000" + }, + { + "name": "default.page.size", + "value": "10000" + }, + { + "name": "account.cleanup.interval", + "value": "120" + }, + { + "name": "workers", + "value": "10" + }, + { + "name": "vm.op.wait.interval", + "value": "5" + }, + { + "name": "network.gc.interval", + "value": "120" + }, + { + "name": "guest.domain.suffix", + "value": "sandbox.xen" + }, + { + "name": "expunge.delay", + "value": "60" + }, + { + "name": "vm.allocation.algorithm", + "value": "random" + }, + { + "name": "expunge.interval", + "value": "60" + }, + { + "name": "enable.dynamic.scale.vm", + "value": "true" + }, + { + "name": "instance.name", + "value": "QA" + }, + { + "name": "expunge.workers", + "value": "3" + }, + { + "name": "secstorage.allowed.internal.sites", + "value": "10.208.8.0/26,10.208.8.65/26,10.208.8.128/26,10.208.8.192/26,10.208.13.194/32" + }, + { + "name": "check.pod.cidrs", + "value": "true" + } + ], + "mgtSvr": [ + { + "mgtSvrIp": "cloudstack-centos63", + "port": 8096 + } + ] +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cloudstack/blob/11d8c461/tools/marvin/marvin/misc/build/xen.properties ---------------------------------------------------------------------- diff --git a/tools/marvin/marvin/misc/build/xen.properties b/tools/marvin/marvin/misc/build/xen.properties new file mode 100644 index 0000000..cffa28c --- /dev/null +++ b/tools/marvin/marvin/misc/build/xen.properties @@ -0,0 +1,86 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + + +[globals] +#global settings in cloudstack +expunge.delay=60 +expunge.interval=60 +storage.cleanup.interval=120 +account.cleanup.interval=120 +network.gc.interval=120 +expunge.workers=3 +workers=10 +vm.allocation.algorithm=random +vm.op.wait.interval=5 +guest.domain.suffix=sandbox.xen +instance.name=QA +direct.agent.load.size=1000 +default.page.size=10000 +check.pod.cidrs=true +secstorage.allowed.internal.sites=10.208.8.0/26,10.208.8.65/26,10.208.8.128/26,10.208.8.192/26,10.208.13.194/32 +enable.dynamic.scale.vm=true +[environment] +dns1=8.8.8.8 +dns2=8.8.8.8 +internal_dns1=10.208.8.5 +internal_dns2=10.208.8.5 +mshost=cloudstack-centos63 +mysql.host=cloudstack-centos63 +mysql.cloud.user=cloud +mysql.cloud.passwd=cloud +[cloudstack] +hypervisor=XenServer +host.password=password + +#Zone 1 +z0.guest.vlan=2001-2050 + +z0p0.private.gateway=10.208.8.65 +z0p0.private.pod.startip=10.208.8.70 +z0p0.private.pod.endip=10.208.8.75 +z0p0.private.netmask=255.255.255.192 + +z0p0.public.gateway=10.208.10.1 +z0p0.public.vlan.startip=10.208.10.10 +z0p0.public.vlan.endip=10.208.10.62 +z0p0.public.netmask=255.255.255.192 +z0p0.public.vlan=100 + +z0p0c0h0.host=apache-81-3 +z0p0c0h1.host=apache-81-2 + +z0p0c0ps0.primary.pool=nfs://nfs.fmt.vmops.com:/export/automation/acs/primary +z0p0c0ps1.primary.pool=nfs://nfs.fmt.vmops.com:/export/automation/acs/primary1 + +z0p1.private.gateway=10.208.8.193 +z0p1.private.pod.startip=10.208.8.200 +z0p1.private.pod.endip=10.208.8.205 +z0p1.private.netmask=255.255.255.192 + +z0p1.public.gateway=10.208.10.65 +z0p1.public.vlan.startip=10.208.10.66 +z0p1.public.vlan.endip=10.208.10.126 +z0p1.public.netmask=255.255.255.192 +z0p1.public.vlan=101 + +z0p1c0h0.host=apache-83-1 + +z0p1c0ps0.primary.pool=nfs://nfs.fmt.vmops.com:/export/automation/acs/primary2 + + +z0.secondary.pool=nfs://nfs.fmt.vmops.com:/export/automation/acs/secondary http://git-wip-us.apache.org/repos/asf/cloudstack/blob/11d8c461/tools/marvin/marvin/misc/build/xunitmp/setup.py ---------------------------------------------------------------------- diff --git a/tools/marvin/marvin/misc/build/xunitmp/setup.py b/tools/marvin/marvin/misc/build/xunitmp/setup.py new file mode 100644 index 0000000..b5ad6d8 --- /dev/null +++ b/tools/marvin/marvin/misc/build/xunitmp/setup.py @@ -0,0 +1,46 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version .0 (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.apache.org/licenses/LICENSE-.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +import os +from setuptools import setup + +def read(fname): + return open(os.path.join(os.path.dirname(__file__), fname)).read().strip() + +VERSION = '0.1.0' + +setup( + name = "xunitmultiprocess", + version = VERSION, + author = "Prasanna Santhanam", + author_email = "[email protected]", + description = "Run tests written using CloudStack's Marvin testclient", + license = 'ASL .0', + classifiers = [ + "Intended Audience :: Developers", + "Topic :: Software Development :: Testing", + "Programming Language :: Python", + ], + + py_modules = ['xunitmultiprocess'], + zip_safe = False, + + entry_points = { + 'nose.plugins': ['xunitmultiprocess = xunitmultiprocess:Xunitmp'] + }, + install_requires = ['nose'], +) http://git-wip-us.apache.org/repos/asf/cloudstack/blob/11d8c461/tools/marvin/marvin/misc/build/xunitmp/xunitmultiprocess.py ---------------------------------------------------------------------- diff --git a/tools/marvin/marvin/misc/build/xunitmp/xunitmultiprocess.py b/tools/marvin/marvin/misc/build/xunitmp/xunitmultiprocess.py new file mode 100644 index 0000000..950a2e3 --- /dev/null +++ b/tools/marvin/marvin/misc/build/xunitmp/xunitmultiprocess.py @@ -0,0 +1,274 @@ + +"""This plugin provides test results in the standard XUnit XML format. + +It was designed for the `Hudson`_ continuous build system but will +probably work for anything else that understands an XUnit-formatted XML +representation of test results. + +Add this shell command to your builder :: + + nosetests --with-xunitmp + +And by default a file named nosetests.xml will be written to the +working directory. + +In a Hudson builder, tick the box named "Publish JUnit test result report" +under the Post-build Actions and enter this value for Test report XMLs:: + + **/nosetests.xml + +If you need to change the name or location of the file, you can set the +``--xunit-file`` option. + +Here is an abbreviated version of what an XML test report might look like:: + + <?xml version="1.0" encoding="UTF-8"?> + <testsuite name="nosetests" tests="1" errors="1" failures="0" skip="0"> + <testcase classname="path_to_test_suite.TestSomething" + name="test_it" time="0"> + <error type="exceptions.TypeError" message="oops, wrong type"> + Traceback (most recent call last): + ... + TypeError: oops, wrong type + </error> + </testcase> + </testsuite> + +.. _Hudson: https://hudson.dev.java.net/ + +""" +__author__ = "original xunit author, Rosen Diankov ([email protected])" + +import doctest +import os +import traceback +import re +import inspect +from nose.plugins.base import Plugin +from nose.exc import SkipTest +from time import time +from xml.sax import saxutils +from nose.pyversion import UNICODE_STRINGS +import sys +import multiprocessing +globalxunitmanager = multiprocessing.Manager() +globalxunitstream = globalxunitmanager.list() # used for gathering statistics +globalxunitstats = multiprocessing.Array('i',[0]*4) + +# Invalid XML characters, control characters 0-31 sans \t, \n and \r +CONTROL_CHARACTERS = re.compile(r"[\000-\010\013\014\016-\037]") + +def xml_safe(value): + """Replaces invalid XML characters with '?'.""" + return CONTROL_CHARACTERS.sub('?', value) + +def escape_cdata(cdata): + """Escape a string for an XML CDATA section.""" + return xml_safe(cdata).replace(']]>', ']]>]]><![CDATA[') + +def nice_classname(obj): + """Returns a nice name for class object or class instance. + + >>> nice_classname(Exception()) # doctest: +ELLIPSIS + '...Exception' + >>> nice_classname(Exception) # doctest: +ELLIPSIS + '...Exception' + + """ + if inspect.isclass(obj): + cls_name = obj.__name__ + else: + cls_name = obj.__class__.__name__ + mod = inspect.getmodule(obj) + if mod: + name = mod.__name__ + # jython + if name.startswith('org.python.core.'): + name = name[len('org.python.core.'):] + return "%s.%s" % (name, cls_name) + else: + return cls_name + +def exc_message(exc_info): + """Return the exception's message.""" + exc = exc_info[1] + if exc is None: + # str exception + result = exc_info[0] + else: + try: + result = str(exc) + except UnicodeEncodeError: + try: + result = unicode(exc) + except UnicodeError: + # Fallback to args as neither str nor + # unicode(Exception(u'\xe6')) work in Python < 2.6 + result = exc.args[0] + return xml_safe(result) + +class Xunitmp(Plugin): + """This plugin provides test results in the standard XUnit XML format.""" + name = 'xunitmp' + score = 499 # necessary for it to go after capture + encoding = 'UTF-8' + xunitstream = None + xunitstats = None + xunit_file = None + + def _timeTaken(self): + if hasattr(self, '_timer'): + taken = time() - self._timer + else: + # test died before it ran (probably error in setup()) + # or success/failure added before test started probably + # due to custom TestResult munging + taken = 0.0 + return taken + + def _quoteattr(self, attr): + """Escape an XML attribute. Value can be unicode.""" + attr = xml_safe(attr) + if isinstance(attr, unicode) and not UNICODE_STRINGS: + attr = attr.encode(self.encoding) + return saxutils.quoteattr(attr) + + def options(self, parser, env): + """Sets additional command line options.""" + Plugin.options(self, parser, env) + parser.add_option( + '--xml-file', action='store', + dest='xunit_file', metavar="FILE", + default=env.get('NOSE_XUNI_FILE', 'nosetests.xml'), + help=("Path to xml file to store the xunit report in. " + "Default is nosetests.xml in the working directory " + "[NOSE_XUNIT_FILE]")) + parser.add_option( + '--xunit-header', action='store', + dest='xunit_header', metavar="HEADER", + default=env.get('NOSE_XUNIT_HEADER', ''), + help=("The attributes of the <testsuite> report that will be created, in particular 'package' and 'name' should be filled." + "[NOSE_XUNIT_HEADER]")) + + def configure(self, options, config): + """Configures the xunit plugin.""" + Plugin.configure(self, options, config) + self.config = config + if self.enabled: + self.xunitstream = globalxunitstream + self.xunitstats = globalxunitstats + for i in range(4): + self.xunitstats[i] = 0 + self.xunit_file = options.xunit_file + self.xunit_header = options.xunit_header + + def report(self, stream): + """Writes an Xunit-formatted XML file + + The file includes a report of test errors and failures. + + """ + stats = {'errors': self.xunitstats[0], 'failures': self.xunitstats[1], 'passes': self.xunitstats[2], 'skipped': self.xunitstats[3] } + stats['encoding'] = self.encoding + stats['total'] = (stats['errors'] + stats['failures'] + stats['passes'] + stats['skipped']) + stats['header'] = self.xunit_header + if UNICODE_STRINGS: + error_report_file = open(self.xunit_file, 'w', encoding=self.encoding) + else: + error_report_file = open(self.xunit_file, 'w') + error_report_file.write( + '<?xml version="1.0" encoding="%(encoding)s"?>' + '<testsuite %(header)s tests="%(total)d" ' + 'errors="%(errors)d" failures="%(failures)d" ' + 'skip="%(skipped)d">' % stats) + while len(self.xunitstream) > 0: + error_report_file.write(self.xunitstream.pop(0)) + #error_report_file.write('<properties><property name="myproperty" value="1.5"/></properties>') + error_report_file.write('</testsuite>') + error_report_file.close() + if self.config.verbosity > 1: + stream.writeln("-" * 70) + stream.writeln("XML: %s" % error_report_file.name) + + def startTest(self, test): + """Initializes a timer before starting a test.""" + self._timer = time() + + def addstream(self,xml): + try: + self.xunitstream.append(xml) + except Exception, e: + print 'xunitmultiprocess add stream len=%d,%s'%(len(xml),str(e)) + + def addError(self, test, err, capt=None): + """Add error output to Xunit report. + """ + taken = self._timeTaken() + if issubclass(err[0], SkipTest): + type = 'skipped' + self.xunitstats[3] += 1 + else: + type = 'error' + self.xunitstats[0] += 1 + tb = ''.join(traceback.format_exception(*err)) + try: + id=test.shortDescription() + if id is None: + id = test.id() + except AttributeError: + id='' + id = id.split('.') + name = self._quoteattr(id[-1]) + systemout = '' +# if test.capturedOutput is not None: +# systemout = '<system-out><![CDATA['+escape_cdata(str(test.capturedOutput))+']]></system-out>' + xml = """<testcase classname=%(cls)s name=%(name)s time="%(taken)f"> +%(systemout)s +<%(type)s type=%(errtype)s message=%(message)s><![CDATA[%(tb)s]]> +</%(type)s></testcase> +""" %{'cls': self._quoteattr('.'.join(id[:-1])), 'name': self._quoteattr(name), 'taken': taken, 'type': type, 'errtype': self._quoteattr(nice_classname(err[0])), 'message': self._quoteattr(exc_message(err)), 'tb': escape_cdata(tb), 'systemout':systemout} + self.addstream(xml) + + def addFailure(self, test, err, capt=None, tb_info=None): + """Add failure output to Xunit report. + """ + taken = self._timeTaken() + tb = ''.join(traceback.format_exception(*err)) + self.xunitstats[1] += 1 + try: + id=test.shortDescription() + if id is None: + id = test.id() + except AttributeError: + id='' + id = id.split('.') + name = self._quoteattr(id[-1]) + systemout = '' +# if test.capturedOutput is not None: +# systemout = '<system-out><![CDATA['+escape_cdata(str(test.capturedOutput))+']]></system-out>' + xml = """<testcase classname=%(cls)s name=%(name)s time="%(taken)f"> +%(systemout)s +<failure type=%(errtype)s message=%(message)s><![CDATA[%(tb)s]]> +</failure></testcase> +""" %{'cls': self._quoteattr('.'.join(id[:-1])), 'name': self._quoteattr(name), 'taken': taken, 'errtype': self._quoteattr(nice_classname(err[0])), 'message': self._quoteattr(exc_message(err)), 'tb': escape_cdata(tb), 'systemout':systemout} + self.addstream(xml) + + def addSuccess(self, test, capt=None): + """Add success output to Xunit report. + """ + taken = self._timeTaken() + self.xunitstats[2] += 1 + try: + id=test.shortDescription() + if id is None: + id = test.id() + except AttributeError: + id='' + id = id.split('.') + name = self._quoteattr(id[-1]) + systemout='' +# if test.capturedOutput is not None: +# systemout = '<system-out><![CDATA['+escape_cdata(str(test.capturedOutput))+']]></system-out>' + xml = """<testcase classname=%(cls)s name=%(name)s time="%(taken)f" >%(systemout)s</testcase> +""" % {'cls': self._quoteattr('.'.join(id[:-1])), 'name': self._quoteattr(name), 'taken': taken, 'systemout':systemout } + self.addstream(xml)
