Beispiel #1
0
    def __init__(self,
                 xmlfile,
                 istest=True,
                 parentDirDefaults=None,
                 project=None):
        assert project
        self.file = xmlfile
        self.dirname = os.path.dirname(xmlfile)
        self.istest = istest
        self.defaults = self.DEFAULT_DESCRIPTOR if parentDirDefaults is None else parentDirDefaults
        roottag = 'pysystest' if istest else 'pysysdirconfig'
        if not os.path.exists(xmlfile):
            raise UserError("Unable to find supplied descriptor \"%s\"" %
                            xmlfile)
        self.project = project

        try:
            self.doc = xml.dom.minidom.parse(xmlfile)
        except Exception as ex:
            raise UserError("Invalid XML in descriptor '%s': %s" %
                            (xmlfile, ex))
        else:
            if self.doc.getElementsByTagName(roottag) == []:
                raise UserError(
                    "No <%s> element supplied in XML descriptor '%s'" %
                    (roottag, xmlfile))
            else:
                self.root = self.doc.getElementsByTagName(roottag)[0]
Beispiel #2
0
		def findMatchingIndex(specId): # change this to return the match, rather than whether it matches
			# optimize the case where we specify the full id; no need to iterate
			index = testids.get(specId, None)
			if index is not None: return index
			
			if specId.isdigit():
				regex = re.compile('.+_0*'+(specId.lstrip('0') if (len(specId)>0) else specId)+'$')
				matches = [index for index, d in enumerate(descriptors) if regex.match(d.id)]
			else:
				# permit specifying suffix at end of testcase, which is 
				# important to allow shell directory completion to be used if an id-prefix is 
				# being added onto the directory id; but only do this if spec is non-numeric 
				# since we don't want to match test_104 against spec 04
			
				matches = [index for index, d in enumerate(descriptors) if d.id.endswith(specId)]
			
			if len(matches) == 1: return matches[0]			
			if len(matches) == 0: raise UserError('No tests found matching id: "%s"'%specId)
			
			# as a special-case, see if there's an exact match with the dirname
			dirnameMatches = [index for index, d in enumerate(descriptors) if os.path.basename(d.testDir)==specId]
			if len(dirnameMatches)==1: return dirnameMatches[0]
			
			# nb: use space not comma as the delimiter so it's easy to copy paste it
			raise UserError('Multiple tests found matching "%s"; please specify which one you want: %s'%(specId, 
				' '.join([descriptors[index].id for index in matches[:20] ])))
Beispiel #3
0
    def _parseClassAndConfigDict(self,
                                 node,
                                 defaultClass,
                                 returnClassAsName=False):
        """Parses a dictionary of arbitrary options and a python class out of the specified XML node.

		The node may optionally contain classname and module (if not specified as a separate attribute,
		module will be extracted from the first part of classname); any other attributes will be returned in
		the optionsDict, as will <property name=""></property> child elements.

		:param node: The node, may be None
		:param defaultClass: a string specifying the name of the default fully-qualified class, if any
		:return: a tuple of (pythonclassconstructor, propertiesdict), or if returnClassAsName (classname, propertiesDict)
		"""
        optionsDict = {}
        if node:
            for att in range(node.attributes.length):
                name = node.attributes.item(att).name.strip()
                if name in optionsDict:
                    raise UserError(
                        'Duplicate property "%s" in <%s> configuration' %
                        (name, node.tagName))
                optionsDict[name] = self.expandProperties(
                    node.attributes.item(att).value, default=None, name=name)
            for tag in node.getElementsByTagName('property'):
                name = tag.getAttribute('name')
                assert name
                if name in optionsDict:
                    raise UserError(
                        'Duplicate property "%s" in <%s> configuration' %
                        (name, node.tagName))
                optionsDict[name] = self.expandProperties(
                    tag.getAttribute("value") or '\n'.join(
                        n.data for n in tag.childNodes
                        if (n.nodeType in {n.TEXT_NODE, n.CDATA_SECTION_NODE})
                        and n.data),
                    default=tag,
                    name=name)

        classname = optionsDict.pop('classname', defaultClass)
        if not classname:
            raise UserError('Missing require attribute "classname=" for <%s>' %
                            node.tagName)
        mod = optionsDict.pop('module', '.'.join(classname.split('.')[:-1]))
        classname = classname.split('.')[-1]

        if returnClassAsName:
            return (mod + '.' + classname).strip('.'), optionsDict

        # defer importing the module until we actually need to instantiate the
        # class, to avoid introducing tricky module import order problems, given
        # that the project itself needs loading very early
        def classConstructor(*args, **kwargs):
            module = import_module(mod)
            cls = getattr(module, classname)
            return cls(*args,
                       **kwargs)  # invoke the constructor for this class

        return classConstructor, optionsDict
Beispiel #4
0
		def makeregex(s):
			if not s: return None
			if s.startswith('!'): raise UserError('Exclusions such as !xxx are not permitted in execution-order configuration')
			
			# make a regex that will match either the entire expression as a literal 
			# or the entire expression as a regex
			s = s.rstrip('$')
			try:
				#return re.compile('(%s|%s)$'%(re.escape(s), s))
				return re.compile('%s$'%(s))
			except Exception as ex:
				raise UserError('Invalid regular expression in execution-order "%s": %s'%(s, ex))
Beispiel #5
0
    def setup(self,
              numTests=0,
              cycles=1,
              xargs=None,
              threads=0,
              testoutdir=u'',
              runner=None,
              **kwargs):
        for k in self.pluginProperties:
            if not hasattr(type(self), k):
                raise UserError('Unknown property "%s" for %s' % (k, self))

        self.runner = runner
        if not self.destDir: raise Exception('Cannot set destDir to ""')

        # avoid double-expanding (which could mess up ${$} escapes), but if using default value we need to expand it
        if self.destDir == TestOutputArchiveWriter.destDir:
            self.destDir = runner.project.expandProperties(self.destDir)
        self.destDir = toLongPathSafe(
            os.path.normpath(os.path.join(runner.output + '/..',
                                          self.destDir)))
        if os.path.exists(self.destDir) and all(
                f.endswith(('.txt', '.zip'))
                for f in os.listdir(self.destDir)):
            deletedir(
                self.destDir
            )  # remove any existing archives (but not if this dir seems to have other stuff in it!)

        self.fileExcludesRegex = re.compile(
            self.fileExcludesRegex) if self.fileExcludesRegex else None
        self.fileIncludesRegex = re.compile(
            self.fileIncludesRegex) if self.fileIncludesRegex else None

        self.__totalBytesRemaining = int(
            float(self.maxTotalSizeMB) * 1024 * 1024)

        if self.archiveAtEndOfRun:
            self.queuedInstructions = []

        self.skippedTests = []
        self.archivesCreated = 0

        self.includeNonFailureOutcomes = [
            str(o) for o in OUTCOMES
        ] if self.includeNonFailureOutcomes == '*' else [
            o.strip().upper()
            for o in self.includeNonFailureOutcomes.split(',') if o.strip()
        ]
        for o in self.includeNonFailureOutcomes:
            if not any(o == str(outcome) for outcome in OUTCOMES):
                raise UserError(
                    'Unknown outcome display name "%s" in includeNonFailureOutcomes'
                    % o)
Beispiel #6
0
		def expandProperty(m):
			m = m.group(1)
			if m == '$': return '$'
			try:
				if m.startswith(envprefix): 
					return os.environ[m[len(envprefix):]]
			except KeyError as ex:
				raise UserError(errorprefix+'cannot find environment variable "%s"'%m[len(envprefix):])
			
			if m in self.properties:
				return self.properties[m]
			else:
				raise UserError(errorprefix+'PySys project property ${%s} is not defined, please check your pysysproject.xml file"'%m)
Beispiel #7
0
	def getProperties(self):
		propertyNodeList = [element for element in self.root.getElementsByTagName('property') if element.parentNode == self.root]

		for propertyNode in propertyNodeList:
			permittedAttributes = None
			# use of these options for customizing the property names of env/root/osfamily is no longer encouraged; just kept for compat
			if propertyNode.hasAttribute("environment"):
				self.environment = propertyNode.getAttribute("environment")
			elif propertyNode.hasAttribute("root"): 
				propname = propertyNode.getAttribute("root")
				self.properties[propname] = self.dirname
				log.debug('Setting project property %s="%s"', propname, self.dirname)
			elif propertyNode.hasAttribute("osfamily"): # just for older configs, better to use ${os} now
				propname = propertyNode.getAttribute("osfamily")
				self.properties[propname] = OSFAMILY
				log.debug('Setting project property %s="%s"', propname, OSFAMILY)
					
			elif propertyNode.hasAttribute("file"): 
				file = self.expandProperties(propertyNode.getAttribute("file"), default=propertyNode, name='properties file reading')
				self.getPropertiesFromFile(os.path.normpath(os.path.join(self.dirname, file)) if file else '', 
					pathMustExist=(propertyNode.getAttribute("pathMustExist") or '').lower()=='true',
					includes=propertyNode.getAttribute("includes"),
					excludes=propertyNode.getAttribute("excludes"),
					prefix=propertyNode.getAttribute("prefix") or '',
					)
				permittedAttributes = {'name', 'file', 'default', 'pathMustExist', 'includes', 'excludes', 'prefix'}

			elif propertyNode.hasAttribute("name"):
				name = propertyNode.getAttribute("name") 
				value = self.expandProperties(propertyNode.getAttribute("value"), default=propertyNode, name=name)
				if name in self.properties:
					raise UserError('Cannot set project property "%s" as it is already set'%name)
				self.properties[name] = value
				log.debug('Setting project property %s="%s"', name, value)

				if (propertyNode.getAttribute("pathMustExist") or '').lower()=='true':
					if not (value and os.path.exists(os.path.join(self.dirname, value))):
						raise UserError('Cannot find path referenced in project property "%s": "%s"'%(
							name, '' if not value else os.path.normpath(os.path.join(self.dirname, value))))
				permittedAttributes = {'name', 'value', 'default', 'pathMustExist'}
			else:
				raise UserError('Found <property> with no name= or file=')
			
			if permittedAttributes is not None:
				for att in range(propertyNode.attributes.length):
					attName = propertyNode.attributes.item(att).name
					if attName not in permittedAttributes: 
						# not an error, to allow for adding new ones in future pysys versions, but worth warning about
						log.warn('Unknown <property> attribute "%s" in project configuration'%attName)

		return self.properties
Beispiel #8
0
        def expandAndValidateTemplate(t, defaults):
            source = t.get('source', '<unknown source>')
            if defaults is None: defaults = DEFAULT_DESCRIPTOR

            if t['name'].lower().replace('_', '').replace(' ',
                                                          '') != t['name']:
                raise UserError(  # enforce this to make them easy to type on cmd line, and consistent
                    "Invalid template name \"%s\" - must be lowercase and use hyphens not underscores/spaces for separating words, in \"%s\""
                    % (t['name'], source))

            source = t.get('source', None)
            if t['mkdir'] is None:
                t['mkdir'] = [defaults.output, defaults.reference]
                if defaults.input not in [
                        '!Input_dir_if_present_else_testDir!',
                        '!INPUT_DIR_IF_PRESENT_ELSE_TEST_DIR!'
                ]:
                    t['mkdir'].append(defaults.input)

            t['testOutputDir'] = defaults.output

            t['copy'] = [
                os.path.normpath(
                    os.path.join(
                        os.path.dirname(source) if source else '',
                        project.expandProperties(x).strip()))
                for x in t['copy']
            ]
            copy = []
            for c in t['copy']:
                globbed = glob.glob(c)
                if not globbed:
                    raise UserError(
                        'Cannot find any file or directory "%s" in maker template "%s" of "%s"'
                        % (c, t['name'], source))
                copy.extend(globbed)
            t['copy'] = copy

            t['replace'] = [(r1, project.expandProperties(r2))
                            for (r1, r2) in t['replace']]
            for r1, r2 in t['replace']:
                try:
                    re.compile(r1)
                except Exception as ex:
                    raise UserError(
                        'Invalid replacement regular expression "%s" in maker template "%s" of "%s": %s'
                        % (r1, t['name'], source, ex))

            return t
Beispiel #9
0
	def checkVersions(self):
		requirespython = self.root.getElementsByTagName('requires-python')
		if requirespython and requirespython[0].firstChild: 
			requirespython = requirespython[0].firstChild.nodeValue
			if requirespython:
				if list(sys.version_info) < list(map(int, requirespython.split('.'))):
					raise UserError('This test project requires Python version %s or greater, but this is version %s (from %s)'%(requirespython, '.'.join([str(x) for x in sys.version_info[:3]]), sys.executable))

		requirespysys = self.root.getElementsByTagName('requires-pysys')
		if requirespysys and requirespysys[0].firstChild: 
			requirespysys = requirespysys[0].firstChild.nodeValue
			if requirespysys:
				thisversion = __version__
				if pysys.utils.misc.compareVersions(requirespysys, thisversion) > 0:
					raise UserError('This test project requires PySys version %s or greater, but this is version %s'%(requirespysys, thisversion))
Beispiel #10
0
	def expandProperties(self, value, default, name=None):
		"""
		Expand any ${...} project properties or env vars, with ${$} for escaping.
		The "default" is expanded and used if value contains some undefined variables. 
		If default=None then an error is raised instead. If default is a node, its "default" attribute is used
		
		The "name" is used to generate more informative error messages
		"""
		envprefix = self.environment+'.'
		errorprefix = ('Error setting project property "%s": '%name) if name else ''
		
		if hasattr(default, 'getAttribute'):
			default = default.getAttribute("default") if default.hasAttribute("default") else None

		def expandProperty(m):
			m = m.group(1)
			if m == '$': return '$'
			try:
				if m.startswith(envprefix): 
					return os.environ[m[len(envprefix):]]
			except KeyError as ex:
				raise UserError(errorprefix+'cannot find environment variable "%s"'%m[len(envprefix):])
			
			if m in self.properties:
				return self.properties[m]
			else:
				raise UserError(errorprefix+'PySys project property ${%s} is not defined, please check your pysysproject.xml file"'%m)
		try:
			return re.sub(r'[$][{]([^}]+)[}]', expandProperty, value)
		except UserError as ex:
			if default is None: raise UserError('%s; if this is intended to be an optional property please add a default="..." value'%ex)
			log.debug('Failed to resolve value "%s" of property "%s", so falling back to default value', value, name or '<unknown>')
			return re.sub(r'[$][{]([^}]+)[}]', expandProperty, default)
Beispiel #11
0
	def getPropertiesFromFile(self, file, pathMustExist=False, includes=None, excludes=None, prefix=''):
		if not os.path.isfile(file):
			if pathMustExist:
				raise UserError('Cannot find properties file referenced in %s: "%s"'%(
					self.xmlfile, file))

			log.debug('Skipping project properties file which not exist: "%s"', file)
			return

		try:
			rawProps = loadProperties(file) # since PySys 1.6.0 this is UTF-8 by default
		except UnicodeDecodeError:
			# fall back to ISO8859-1 if not valid UTF-8 (matching Java 9+ behaviour)
			rawProps = loadProperties(file, encoding='iso8859-1')
		
		props = collections.OrderedDict()
		for name, value in rawProps.items():
			if includes and not re.match(includes, name): continue
			if excludes and re.match(excludes, name): continue
			props[prefix+name] = value
				
		for name, value in props.items():
			# when loading properties files it's not so helpful to give errors (and there's nowhere else to put an empty value) so default to empty string
			value = self.expandProperties(value, default='', name=name)	
			
			if name in self.properties and value != self.properties[name]:
				# Whereas we want a hard error for duplicate <property name=".../> entries, for properties files 
				# there's a good case to allow overwriting of properties, but it log it at INFO
				log.info('Overwriting previous value of project property "%s" with new value "%s" from "%s"'%(name, value, os.path.basename(file)))

			self.properties[name] = value
			log.debug('Setting project property %s="%s" (from %s)', name, self.properties[name], file)
Beispiel #12
0
    def setup(self, **kwargs):
        self.runner = kwargs['runner']
        # NB: this method is also called by ConsoleFailureAnnotationsWriter
        self.includeNonFailureOutcomes = [
            str(o) for o in OUTCOMES
        ] if self.includeNonFailureOutcomes == '*' else [
            o.strip().upper()
            for o in self.includeNonFailureOutcomes.split(',') if o.strip()
        ]
        for o in self.includeNonFailureOutcomes:
            if not any(o == str(outcome) for outcome in OUTCOMES):
                raise UserError(
                    'Unknown outcome display name "%s" in includeNonFailureOutcomes'
                    % o)

        self.logfile = os.path.normpath(
            os.path.join(self.outputDir or kwargs['runner'].output + '/..',
                         self.logfile))
        mkdir(os.path.dirname(self.logfile))

        self.resultsWritten = 0
        self.cycles = self.runner.cycles

        if self.fp is None:  # this condition allows a subclass to write to something other than a .json file
            self.fp = io.open(self.logfile, "w", encoding='utf-8')
        self.fp.write('{"runDetails": ')
        json.dump(self.runner.runDetails, self.fp)
        self.fp.write(', "results":[\n')
        self.fp.flush()
Beispiel #13
0
	def getDescriptorLoaderClass(self):
		nodeList = self.root.getElementsByTagName('descriptor-loader')
		cls, optionsDict = self._parseClassAndConfigDict(nodeList[0] if nodeList else None, 'pysys.xml.descriptor.DescriptorLoader')
		
		if optionsDict: raise UserError('Unexpected descriptor-loader attribute(s): '+', '.join(list(optionsDict.keys())))
		
		return cls
Beispiel #14
0
    def parseArgs(self, args):
        try:
            optlist, self.arguments = getopt.gnu_getopt(
                args, self.optionString, self.optionList)
        except Exception:
            log.warn("Error parsing command line arguments: %s" %
                     (sys.exc_info()[1]))
            sys.exit(1)

        for option, value in optlist:
            if option in ("-h", "--help"):
                self.printUsage()

            elif option in ("-f", "--full"):
                self.full = True

            elif option in ("-g", "--groups"):
                self.groups = True

            elif option in ("-d", "--modes"):
                self.modes = True

            elif option in ("-r", "--requirements"):
                self.requirements = True

            elif option in ("-m", "--mode"):
                self.modefilter = value
                if ',' in value or '!' in value:
                    raise UserError(
                        'Only one mode can be specified when printing tests')

            elif option in ("-a", "--type"):
                self.type = value
                if self.type not in ["auto", "manual"]:
                    log.warn(
                        "Unsupported test type - valid types are auto and manual"
                    )
                    sys.exit(1)

            elif option in ("-t", "--trace"):
                self.trace = value

            elif option in ("-i", "--include"):
                self.includes.append(value)

            elif option in ("-e", "--exclude"):
                self.excludes.append(value)

            elif option in ("-s", "--sort"):
                self.sort = value

            elif option in ("-G", "--grep"):
                self.grep = value

            elif option == '--json':
                self.json = True

            else:
                print("Unknown option: %s" % option)
                sys.exit(1)
Beispiel #15
0
    def getContainer(self):
        '''Create and return an instance of TestDescriptor for the contents of the descriptor.'''

        for attrName, attrValue in self.root.attributes.items():
            if attrName not in ['state', 'type']:
                raise UserError(
                    'Unknown attribute "%s" in XML descriptor "%s"' %
                    (attrName, self.file))

        # some elements that are mandatory for an individual test and not used for dir config
        return TestDescriptor(
            self.getFile(),
            self.getID(),
            self.getType(),
            self.getState(),
            self.getTitle() if self.istest else '',
            self.getPurpose() if self.istest else '',
            self.getGroups(),
            self.getModes(),
            self.project.expandProperties(self.getClassDetails()[0]),
            self.project.expandProperties(self.getClassDetails()[1]),
            self.getTestInput(),
            self.getTestOutput(),
            self.getTestReference(),
            self.getRequirements(),
            self.getExecutionOrderHint(),
            skippedReason=self.getSkippedReason(),
            testDir=self.dirname,
            userData=self.getUserData(),
            isDirConfig=not self.istest)
Beispiel #16
0
    def createFormatters(self):
        stdout = runlog = None

        formattersNodeList = self.root.getElementsByTagName('formatters')
        if formattersNodeList:
            formattersNodeList = formattersNodeList[0].getElementsByTagName(
                'formatter')
        if formattersNodeList:
            for formatterNode in formattersNodeList:
                fname = formatterNode.getAttribute('name')
                if fname not in ['stdout', 'runlog']:
                    raise UserError(
                        'Formatter "%s" is invalid - must be stdout or runlog'
                        % fname)

                if fname == 'stdout':
                    cls, options = self._parseClassAndConfigDict(
                        formatterNode,
                        'pysys.utils.logutils.ColorLogFormatter')
                    options['__formatterName'] = 'stdout'
                    stdout = cls(options)
                else:
                    cls, options = self._parseClassAndConfigDict(
                        formatterNode, 'pysys.utils.logutils.BaseLogFormatter')
                    options['__formatterName'] = 'runlog'
                    runlog = cls(options)
        return stdout, runlog
Beispiel #17
0
 def getState(self):
     '''Return the state attribute of the test element.'''
     state = self.root.getAttribute("state") or self.defaults.state
     if state not in ["runnable", "deprecated", "skipped"]:
         raise UserError(
             "The state attribute of the test element should be \"runnable\", \"deprecated\" or \"skipped\" in \"%s\""
             % self.file)
     return state
Beispiel #18
0
 def getType(self):
     '''Return the type attribute of the test element.'''
     type = self.root.getAttribute("type") or self.defaults.type
     if type not in ["auto", "manual"]:
         raise UserError(
             "The type attribute of the test element should be \"auto\" or \"manual\" in \"%s\""
             % self.file)
     return type
Beispiel #19
0
	def addToPath(self):		
		for elementname in ['path', 'pythonpath']:
			pathNodeList = self.root.getElementsByTagName(elementname)

			for pathNode in pathNodeList:
					value = self.expandProperties(pathNode.getAttribute("value"), default=None, name='pythonpath')
					if not value: 
						raise UserError('Cannot add directory to the pythonpath: "%s"'%value)

					# we ignore the "relative" option and always make it relative to the testrootdir if not already absolute
					value = os.path.join(self.dirname, value)
					value = os.path.normpath(value)
					if not os.path.isdir(value): 
						raise UserError('Cannot add non-existent directory to the python <path>: "%s"'%value)
					else:
						log.debug('Adding value to path: %s', value)
						sys.path.append(value)
Beispiel #20
0
    def getTitle(self):
        '''Return the test titlecharacter data of the description element.'''
        descriptionNodeList = self.root.getElementsByTagName('description')
        if descriptionNodeList == []:
            raise UserError(
                "No <description> element supplied in XML descriptor \"%s\"" %
                self.file)

        if descriptionNodeList[0].getElementsByTagName('title') == []:
            raise UserError(
                "No <title> child element of <description> supplied in XML descriptor \"%s\""
                % self.file)
        else:
            try:
                title = descriptionNodeList[0].getElementsByTagName('title')[0]
                return title.childNodes[0].data.strip()
            except Exception:
                return self.defaults.title
Beispiel #21
0
	def getPerformanceReporterDetails(self):
		nodeList = self.root.getElementsByTagName('performance-reporter')
		cls, optionsDict = self._parseClassAndConfigDict(nodeList[0] if nodeList else None, 'pysys.utils.perfreporter.CSVPerformanceReporter')
			
		summaryfile = optionsDict.pop('summaryfile', '')
		summaryfile = self.expandProperties(summaryfile, default=None, name='performance-reporter summaryfile')
		if optionsDict: raise UserError('Unexpected performancereporter attribute(s): '+', '.join(list(optionsDict.keys())))
		
		return cls, summaryfile
Beispiel #22
0
 def getSkippedReason(self):
     for e in self.root.getElementsByTagName('skipped'):
         r = (e.getAttribute('reason') or '').strip()
         # make this mandatory, to encourage good practice
         if not r:
             raise UserError(
                 'Missing reason= attribute in <skipped> element of "%s"' %
                 self.file)
         return r
     return self.defaults.skippedReason
Beispiel #23
0
    def setup(self, cycles=-1, **kwargs):
        for k in self.pluginProperties:
            if not hasattr(type(self), k):
                raise UserError('Unknown property "%s" for %s' % (k, self))

        super(ConsoleFailureAnnotationsWriter, self).setup(cycles=cycles,
                                                           **kwargs)
        self.cycles = cycles
        self.format = self.format or os.getenv(
            'PYSYS_CONSOLE_FAILURE_ANNOTATIONS', '') or self.DEFAULT_FORMAT
        if self.format.lower() == 'true': self.format = self.DEFAULT_FORMAT

        self.includeNonFailureOutcomes = [
            o.strip().upper()
            for o in self.includeNonFailureOutcomes.split(',') if o.strip()
        ]
        for o in self.includeNonFailureOutcomes:
            if not any(o == str(outcome) for outcome in OUTCOMES):
                raise UserError(
                    'Unknown outcome display name "%s" in includeNonFailureOutcomes'
                    % o)
Beispiel #24
0
	def getDefaultFileEncodings(self):
		result = []
		for n in self.root.getElementsByTagName('default-file-encoding'):
			pattern = (n.getAttribute('pattern') or '').strip().replace('\\','/')
			encoding = (n.getAttribute('encoding') or '').strip()
			if not pattern: raise UserError('<default-file-encoding> element must include both a pattern= attribute')
			if encoding: 
				codecs.lookup(encoding) # give an exception if an invalid encoding is specified
			else:
				encoding=None
			result.append({'pattern':pattern, 'encoding':encoding})
		return result
Beispiel #25
0
    def setup(self, cycles=-1, **kwargs):
        from pysys.writer.outcomes import JSONResultsWriter
        self.__jsonWriter = JSONResultsWriter(
            logfile=
            '__pysys_ConsoleFailureAnnotationsWriter_dummy.shouldnotexist')
        self.__jsonWriter.fp = io.StringIO(
        )  # to stop it creating an actual file
        self.__jsonWriter.setup(cycles=cycles, **kwargs)

        for k in self.pluginProperties:
            if not hasattr(type(self), k):
                raise UserError('Unknown property "%s" for %s' % (k, self))

        super(ConsoleFailureAnnotationsWriter, self).setup(cycles=cycles,
                                                           **kwargs)
        self.cycles = cycles
        if os.getenv('PYSYS_CONSOLE_FAILURE_ANNOTATIONS',
                     '').lower() not in ['', 'true']:
            self.format = os.environ['PYSYS_CONSOLE_FAILURE_ANNOTATIONS']
        else:
            self.format = self.format or self.DEFAULT_FORMAT

        includeNonFailureOutcomes = os.getenv(
            'PYSYS_CONSOLE_FAILURE_ANNOTATIONS_INCLUDE_OUTCOMES',
            '') or self.includeNonFailureOutcomes
        self.includeNonFailureOutcomes = [
            str(o) for o in OUTCOMES
        ] if includeNonFailureOutcomes == '*' else [
            o.strip().upper() for o in includeNonFailureOutcomes.split(',')
            if o.strip()
        ]
        for o in self.includeNonFailureOutcomes:
            if not any(o == str(outcome) for outcome in OUTCOMES):
                raise UserError(
                    'Unknown outcome display name "%s" in includeNonFailureOutcomes'
                    % o)
Beispiel #26
0
 def getExecutionOrderHint(self):
     r = None
     for e in self.root.getElementsByTagName('execution-order'):
         r = e.getAttribute('hint')
         if r:
             try:
                 r = float(r)
             except Exception:
                 raise UserError(
                     'Invalid float value specified for execution-order hint in "%s"'
                     % self.file)
     if r is None or r == '':
         return self.defaults.executionOrderHint
     else:
         return r
Beispiel #27
0
    def getID(self):
        '''Return the id of the test, or for a pysysdirconfig, the id prefix.'''
        id = self.defaults.id
        for e in self.root.getElementsByTagName('id-prefix'):
            id = id + self.getText(e)

        for c in u'\\/:~#<>':
            # reserve a few characters that we might need for other purposes; _ and . can be used however
            if c in id:
                raise UserError(
                    'The <id-prefix> is not permitted to contain "%s"; error in "%s"'
                    % (c, self.file))

        if self.istest: id = id + os.path.basename(self.dirname)

        return id
Beispiel #28
0
    def setup(self,
              numTests=0,
              cycles=1,
              xargs=None,
              threads=0,
              testoutdir=u'',
              runner=None,
              **kwargs):
        for k in self.pluginProperties:
            if not hasattr(type(self), k):
                raise UserError('Unknown property "%s" for %s' % (k, self))

        self.runner = runner
        if not self.destDir: raise Exception('Cannot set destDir to ""')
        if not self.fileIncludesRegex:
            raise Exception('fileIncludesRegex must be specified for %s' %
                            type(self).__name__)

        self.destDir = os.path.normpath(
            os.path.join(runner.output + '/..', self.destDir))
        if pathexists(self.destDir + os.sep + 'pysysproject.xml'):
            raise Exception('Cannot set destDir to testRootDir')

        # the code below assumes (for long path safe logic) this includes correct slashes (if any)
        self.outputPattern = self.outputPattern.replace('/', os.sep).replace(
            '\\', os.sep)

        if self.destArchive:
            self.destArchive = os.path.join(self.destDir, self.destArchive)

        if os.path.exists(self.destDir):
            deletedir(
                self.destDir
            )  # remove any existing archives (but not if this dir seems to have other stuff in it!)

        def prepRegex(exp):
            if not exp: return None
            if not exp.endswith('$'):
                exp = exp + '$'  # by default require regex to match up to the end to avoid common mistakes
            return re.compile(exp)

        self.fileExcludesRegex = prepRegex(self.fileExcludesRegex)
        self.fileIncludesRegex = prepRegex(self.fileIncludesRegex)

        self.collectedFileCount = 0
Beispiel #29
0
    def getExecutionOrderHints(self):
        result = []
        secondaryModesHintDelta = None

        def makeregex(s):
            if not s: return None
            if s.startswith('!'):
                raise UserError(
                    'Exclusions such as !xxx are not permitted in execution-order configuration'
                )

            # make a regex that will match either the entire expression as a literal
            # or the entire expression as a regex
            s = s.rstrip('$')
            try:
                #return re.compile('(%s|%s)$'%(re.escape(s), s))
                return re.compile('%s$' % (s))
            except Exception as ex:
                raise UserError(
                    'Invalid regular expression in execution-order "%s": %s' %
                    (s, ex))

        for parent in self.root.getElementsByTagName('execution-order'):
            if parent.getAttribute('secondaryModesHintDelta'):
                secondaryModesHintDelta = float(
                    parent.getAttribute('secondaryModesHintDelta'))
            for n in parent.getElementsByTagName('execution-order'):
                moderegex = makeregex(n.getAttribute('forMode'))
                groupregex = makeregex(n.getAttribute('forGroup'))
                if not (moderegex or groupregex):
                    raise UserError(
                        'Must specify either forMode, forGroup or both')

                hintmatcher = lambda groups, mode, moderegex=moderegex, groupregex=groupregex: (
                    (moderegex is None or moderegex.match(mode or '')) and
                    (groupregex is None or any(
                        groupregex.match(group) for group in groups)))

                result.append((float(n.getAttribute('hint')), hintmatcher))
        if secondaryModesHintDelta is None:
            secondaryModesHintDelta = +100.0  # default value
        return result, secondaryModesHintDelta
Beispiel #30
0
        def expandProperty(m):
            m = m.group(1)
            if m == '$': return '$'
            try:
                if m.startswith(envprefix):
                    return os.environ[m[len(envprefix):]]
                if m.startswith(
                        'env:'
                ):  # for consistency with eval: also support this syntax
                    return os.environ[m[4:]]
            except KeyError as ex:
                raise KeyError(errorprefix +
                               'cannot find environment variable "%s"' %
                               m[len(envprefix):])

            if m.startswith('eval:'):
                props = dict(self.properties)
                props.pop(
                    'os',
                    None)  # remove this to avoid hiding the os.path module
                props['properties'] = self.properties
                try:
                    v = pysys.utils.safeeval.safeEval(
                        m[5:],
                        extraNamespace=props,
                        errorMessage=
                        'Failed to evaluate Python eval() string "{expr}" during property expansion due to {error}'
                    )
                    return str(v)
                except Exception as ex:
                    raise UserError(str(ex))

            if m in self.properties:
                return self.properties[m]
            else:
                raise KeyError(
                    errorprefix +
                    'PySys project property ${%s} is not defined, please check your pysysproject.xml file'
                    % m)