def parseArgs(self, args, printXOptions=None): try: optlist, self.arguments = getopt.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(printXOptions) elif option in ("-a", "--all"): self.all = True elif option in ("-v", "--verbosity"): if value.upper() == "DEBUG": stdoutHandler.setLevel(logging.DEBUG) elif value.upper() == "INFO": stdoutHandler.setLevel(logging.INFO) elif value.upper() == "WARN": stdoutHandler.setLevel(logging.WARN) elif value.upper() == "CRIT": stdoutHandler.setLevel(logging.CRITICAL) elif option in ("-o", "--outdir"): self.outsubdir = value
def parseArgs(self, args): try: optlist, arguments = getopt.getopt(args, 'ha:d:', ["help", "type=", "dir="]) except Exception: print("Error parsing command line arguments: %s" % (sys.exc_info()[1])) self.printUsage() for option, value in optlist: if option in ("-h", "--help"): self.printUsage() 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 ("-d", "--dir"): self.testdir = value if arguments == []: print("A valid string test id must be supplied") self.printUsage() else: self.testId = arguments[0] return self.testId
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)
def assertLineCount(self, file, filedir=None, expr='', condition=">=1", ignores=None, encoding=None, **xargs): """Perform a validation assert on the number of lines in a text file matching a specific regular expression. This method will add a C{PASSED} outcome to the outcome list if the number of lines in the input file matching the specified regular expression evaluate to true when evaluated against the supplied condition. @param file: The basename of the file used in the line count @param filedir: The dirname of the file (defaults to the testcase output subdirectory) @param expr: The regular expression string used to match a line of the input file @param condition: The condition to be met for the number of lines matching the regular expression @param ignores: A list of regular expressions that will cause lines to be excluded from the count @param encoding: The encoding to use to open the file. The default value is None which indicates that the decision will be delegated to the L{getDefaultFileEncoding()} method. @param xargs: Variable argument list (see class description for supported parameters) """ if filedir is None: filedir = self.output f = os.path.join(filedir, file) try: numberLines = linecount(f, expr, ignores=ignores, encoding=encoding or self.getDefaultFileEncoding(f)) log.debug("Number of matching lines is %d"%numberLines) except Exception: log.warn("caught %s: %s", sys.exc_info()[0], sys.exc_info()[1], exc_info=1) msg = self.__assertMsg(xargs, 'Line count on %s for %s%s '%(file, quotestring(expr), condition)) self.addOutcome(BLOCKED, '%s failed due to %s: %s'%(msg, sys.exc_info()[0], sys.exc_info()[1]), abortOnError=self.__abortOnError(xargs)) else: if (eval("%d %s" % (numberLines, condition))): msg = self.__assertMsg(xargs, 'Line count on input file %s' % file) self.addOutcome(PASSED, msg, abortOnError=self.__abortOnError(xargs)) else: msg = self.__assertMsg(xargs, 'Line count on %s for %s%s (actual =%d) '%(file, quotestring(expr), condition, numberLines)) self.addOutcome(FAILED, msg, abortOnError=self.__abortOnError(xargs))
def assertDiff(self, file1, file2, filedir1=None, filedir2=None, ignores=[], sort=False, replace=[], includes=[], encoding=None, **xargs): """Perform a validation assert on the comparison of two input text files. This method performs a file comparison on two input files. The files are pre-processed prior to the comparison to either ignore particular lines, sort their constituent lines, replace matches to regular expressions in a line with an alternate value, or to only include particular lines. Should the files after pre-processing be equivalent a C{PASSED} outcome is added to the test outcome list, otherwise a C{FAILED} outcome is added. @param file1: The basename of the first file used in the file comparison @param file2: The basename of the second file used in the file comparison (often a reference file) @param filedir1: The dirname of the first file (defaults to the testcase output subdirectory) @param filedir2: The dirname of the second file (defaults to the testcase reference directory) @param ignores: A list of regular expressions used to denote lines in the files which should be ignored @param sort: Boolean flag to indicate if the lines in the files should be sorted prior to the comparison @param replace: List of tuples of the form ('regexpr', 'replacement'). For each regular expression in the list, any occurences in the files is replaced with the replacement value prior to the comparison being carried out. This is often useful to replace timestamps in logfiles etc. @param includes: A list of regular expressions used to denote lines in the files which should be used in the comparison. Only lines which match an expression in the list are used for the comparison @param encoding: The encoding to use to open the file. The default value is None which indicates that the decision will be delegated to the L{getDefaultFileEncoding()} method. @param xargs: Variable argument list (see class description for supported parameters) """ if filedir1 is None: filedir1 = self.output if filedir2 is None: filedir2 = self.reference f1 = os.path.join(filedir1, file1) f2 = os.path.join(filedir2, file2) log.debug("Performing file comparison:") log.debug(" file1: %s" % file1) log.debug(" filedir1: %s" % filedir1) log.debug(" file2: %s" % file2) log.debug(" filedir2: %s" % filedir2) msg = self.__assertMsg(xargs, 'File comparison between %s and %s'%(file1, file2)) unifiedDiffOutput=os.path.join(self.output, os.path.basename(f1)+'.diff') result = False try: result = filediff(f1, f2, ignores, sort, replace, includes, unifiedDiffOutput=unifiedDiffOutput, encoding=encoding or self.getDefaultFileEncoding(f1)) except Exception: log.warn("caught %s: %s", sys.exc_info()[0], sys.exc_info()[1], exc_info=1) self.addOutcome(BLOCKED, '%s failed due to %s: %s'%(msg, sys.exc_info()[0], sys.exc_info()[1]), abortOnError=self.__abortOnError(xargs)) else: try: self.addOutcome(PASSED if result else FAILED, msg, abortOnError=self.__abortOnError(xargs)) finally: if not result: self.logFileContents(unifiedDiffOutput, encoding=encoding or self.getDefaultFileEncoding(f1))
def assertOrderedGrep(self, file, filedir=None, exprList=[], contains=True, encoding=None, **xargs): """Perform a validation assert on a list of regular expressions occurring in specified order in a text file. When the C{contains} input argument is set to true, this method will append a C{PASSED} outcome to the test outcome list if the supplied regular expressions in the C{exprList} are seen in the file in the order they appear in the list; otherwise a C{FAILED} outcome is added. Should C{contains} be set to false, a C{PASSED} outcome will only be added should the regular expressions not be seen in the file in the order they appear in the list. @param file: The basename of the file used in the ordered grep @param filedir: The dirname of the file (defaults to the testcase output subdirectory) @param exprList: A list of regular expressions which should occur in the file in the order they appear in the list @param contains: Boolean flag to denote if the expressions should or should not be seen in the file in the order specified @param encoding: The encoding to use to open the file. The default value is None which indicates that the decision will be delegated to the L{getDefaultFileEncoding()} method. @param xargs: Variable argument list (see class description for supported parameters) """ if filedir is None: filedir = self.output f = os.path.join(filedir, file) log.debug("Performing ordered grep on file:") log.debug(" file: %s" % file) log.debug(" filedir: %s" % filedir) for expr in exprList: log.debug(" exprList: %s" % expr) log.debug(" contains: %s" % LOOKUP[contains]) msg = self.__assertMsg(xargs, 'Ordered grep on input file %s' % file) expr = None try: expr = orderedgrep(f, exprList, encoding=encoding or self.getDefaultFileEncoding(f)) except Exception: log.warn("caught %s: %s", sys.exc_info()[0], sys.exc_info()[1], exc_info=1) self.addOutcome(BLOCKED, '%s failed due to %s: %s'%(msg, sys.exc_info()[0], sys.exc_info()[1]), abortOnError=self.__abortOnError(xargs)) else: if expr is None and contains: result = PASSED elif expr is None and not contains: result = FAILED elif expr is not None and not contains: result = PASSED else: result = FAILED if result == FAILED and expr: msg += ' failed on expression \"%s\"'% expr self.addOutcome(result, msg, abortOnError=self.__abortOnError(xargs))
def parseArgs(self, args): try: optlist, self.arguments = getopt.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 if option in ("-g", "--groups"): self.groups = True if option in ("-d", "--modes"): self.modes = True if option in ("-r", "--requirements"): self.requirements = True elif option in ("-m", "--mode"): self.mode = value 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)
def parseArgs(self, args, printXOptions=None): 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) from pysys.internal.initlogging import pysysLogHandler, stdoutHandler for option, value in optlist: if option in ("-h", "--help"): self.printUsage(printXOptions) elif option in ("-a", "--all"): self.all = True elif option in ("-v", "--verbosity"): if value.upper() == "DEBUG": verbosity = logging.DEBUG elif value.upper() == "INFO": verbosity = logging.INFO elif value.upper() == "WARN": verbosity = logging.WARN elif value.upper() == "CRIT": verbosity = logging.CRITICAL else: log.warn('Invalid log level "%s"' % value) sys.exit(1) log.setLevel(verbosity) if verbosity == logging.DEBUG: stdoutHandler.setLevel(verbosity) # refresh handler levels pysysLogHandler.setLogHandlersForCurrentThread([stdoutHandler]) elif option in ("-o", "--outdir"): self.outsubdir = value else: print("Unknown option: %s" % option) sys.exit(1)
def assertLastGrep(self, file, filedir=None, expr='', contains=True, ignores=[], includes=[], encoding=None, **xargs): """Perform a validation assert on a regular expression occurring in the last line of a text file. When the C{contains} input argument is set to true, this method will add a C{PASSED} outcome to the test outcome list if the supplied regular expression is seen in the file; otherwise a C{FAILED} outcome is added. Should C{contains} be set to false, a C{PASSED} outcome will only be added should the regular expression not be seen in the file. @param file: The basename of the file used in the grep @param filedir: The dirname of the file (defaults to the testcase output subdirectory) @param expr: The regular expression to check for in the last line of the file @param contains: Boolean flag to denote if the expression should or should not be seen in the file @param ignores: A list of regular expressions used to denote lines in the file which should be ignored @param includes: A list of regular expressions used to denote lines in the file which should be used in the assertion.# @param encoding: The encoding to use to open the file. The default value is None which indicates that the decision will be delegated to the L{getDefaultFileEncoding()} method. @param xargs: Variable argument list (see class description for supported parameters) """ if filedir is None: filedir = self.output f = os.path.join(filedir, file) log.debug("Performing grep on file:") log.debug(" file: %s" % file) log.debug(" filedir: %s" % filedir) log.debug(" expr: %s" % expr) log.debug(" contains: %s" % LOOKUP[contains]) msg = self.__assertMsg(xargs, 'Grep on last line of %s %s %s'%(file, 'contains' if contains else 'not contains', quotestring(expr))) try: result = lastgrep(f, expr, ignores, includes, encoding=encoding or self.getDefaultFileEncoding(f)) == contains except Exception: log.warn("caught %s: %s", sys.exc_info()[0], sys.exc_info()[1], exc_info=1) self.addOutcome(BLOCKED, '%s failed due to %s: %s'%(msg, sys.exc_info()[0], sys.exc_info()[1]), abortOnError=self.__abortOnError(xargs)) else: if result: msg = self.__assertMsg(xargs, 'Grep on input file %s' % file) self.addOutcome(PASSED if result else FAILED, msg, abortOnError=self.__abortOnError(xargs))
def parseArgs(self, args, printXOptions=None): try: optlist, self.arguments = getopt.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(printXOptions) elif option in ("-r", "--record"): self.record = True elif option in ("-p", "--purge"): self.purge = True elif option in ("-v", "--verbosity"): self.verbosity = value if self.verbosity.upper() == "DEBUG": stdoutHandler.setLevel(logging.DEBUG) elif self.verbosity.upper() == "INFO": stdoutHandler.setLevel(logging.INFO) elif self.verbosity.upper() == "WARN": stdoutHandler.setLevel(logging.WARN) elif self.verbosity.upper() == "CRIT": stdoutHandler.setLevel(logging.CRITICAL) 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 ("-c", "--cycle"): try: self.cycle = int(value) except Exception: print( "Error parsing command line arguments: A valid integer for the number of cycles must be supplied" ) self.printUsage(printXOptions) elif option in ("-o", "--outdir"): self.outsubdir = value elif option in ("-m", "--mode"): self.mode = value elif option in ("-n", "--threads"): try: self.threads = int(value) except Exception: print( "Error parsing command line arguments: A valid integer for the number of threads must be supplied" ) self.printUsage(printXOptions) elif option in ("-b", "--abort"): setattr(PROJECT, 'defaultAbortOnError', str(value.lower() == 'true')) elif option in ["-g", "--progress"]: self.progress = True elif option in ["-X"]: if EXPR1.search(value) is not None: self.userOptions[value.split('=')[0]] = value.split('=')[1] if EXPR2.search(value) is not None: self.userOptions[value] = True elif option in ("-y", "--validateOnly"): self.userOptions['validateOnly'] = True if os.getenv('PYSYS_PROGRESS', '').lower() == 'true': self.progress = True self.userOptions['__progressWritersEnabled'] = self.progress descriptors = createDescriptors(self.arguments, self.type, self.includes, self.excludes, self.trace, self.workingDir) # No exception handler above, as any createDescriptors failure is really a fatal problem that should cause us to # terminate with a non-zero exit code; we don't want to run no tests without realizing it and return success return self.record, self.purge, self.cycle, self.mode, self.threads, self.outsubdir, descriptors, self.userOptions
def filediff(file1, file2, ignore=[], sort=True, replacementList=[], include=[], unifiedDiffOutput=None, encoding=None): """Perform a file comparison between two (preprocessed) input files, returning true if the files are equivalent. The method reads in the files and loads the contents of each as a list of strings. The two files are said to be equal if the two lists are equal. The method allows for preprocessing of the string lists to trim down their contents prior to the comparison being performed. Preprocessing is either to remove entries from the lists which match any entry in a set of regular expressions, include only lines which match any entry in a set of regular expressions, replace certain keywords in the string values of each list with a set value (e.g. to replace time stamps etc), or to sort the lists before the comparison (e.g. where determinism may not exist). Verbose logging of the method occurs at DEBUG level showing the contents of the processed lists prior to the comparison being performed. @param file1: The full path to the first file to use in the comparison @param file2: The full path to the second file to use in the comparison, typically a reference file @param ignore: A list of regular expressions which remove entries in the input file contents before making the comparison @param sort: Boolean to sort the input file contents before making the comparison @param replacementList: A list of tuples (key, value) where matches to key are replaced with value in the input file contents before making the comparison @param include: A list of regular expressions used to select lines from the input file contents to use in the comparison @param unifiedDiffOutput: If specified, indicates the full path of a file to which unified diff output will be written, if the diff fails. @param encoding: Specifies the encoding to be used for opening the file, or None for default. @return: success (True / False) @rtype: boolean @raises FileNotFoundException: Raised if either of the files do not exist """ for file in file1, file2: if not os.path.exists(file): raise FileNotFoundException("unable to find file %s" % (os.path.basename(file))) else: list1 = [] list2 = [] with openfile(file1, 'r', encoding=encoding) as f: for i in f: list1.append(i.strip()) with openfile(file2, 'r', encoding=encoding) as f: for i in f: list2.append(i.strip()) list1 = trimContents(list1, ignore, exclude=True) list2 = trimContents(list2, ignore, exclude=True) list1 = trimContents(list1, include, exclude=False) list2 = trimContents(list2, include, exclude=False) list1 = replace(list1, replacementList) list2 = replace(list2, replacementList) if sort: list1.sort() list2.sort() logContents( "Contents of %s after pre-processing;" % os.path.basename(file1), list1) logContents( "Contents of %s after pre-processing;" % os.path.basename(file2), list2) if not list1 and not list2: # maybe this should be an exception... it's probably not what was intended log.warn( 'File comparison pre-processing has filtered out all lines from the files to be diffed, please check if this is intended: %s, %s', os.path.basename(file1), os.path.basename(file2)) if list1 != list2: log.debug("Unified diff between pre-processed input files;") l1 = [] l2 = [] for i in list1: l1.append("%s\n" % i) for i in list2: l2.append("%s\n" % i) # nb: have to switch 1 and 2 around to get the right diff for a typical output,ref file pair diff = ''.join( difflib.unified_diff( l2, l1, fromfile='%s (%d lines)' % (os.path.basename(file2), len(l2)), tofile='%s (%d lines)' % (os.path.basename(file1), len(l1)), )) if unifiedDiffOutput: with openfile(unifiedDiffOutput, 'w', encoding=encoding) as f: f.write(diff) for line in diff.split('\n'): log.debug(" %s", line) if list1 == list2: return True return False
def parseArgs(self, args, printXOptions=None): # add any default args first; shlex.split does a great job of providing consistent parsing from str->list, # but need to avoid mangling \'s on windows; since this env var will be different for each OS no need for consistent win+unix behaviour if os.getenv('PYSYS_DEFAULT_ARGS', ''): log.info('Using PYSYS_DEFAULT_ARGS = %s' % os.environ['PYSYS_DEFAULT_ARGS']) args = shlex.split(os.environ['PYSYS_DEFAULT_ARGS'].replace( os.sep, os.sep * 2 if os.sep == '\\' else os.sep)) + args printLogsDefault = PrintLogs.ALL if '--ci' in args: # to ensure identical behaviour, set these as if on the command line # (printLogs we don't set here since we use the printLogsDefault mechanism to allow it to be overridden # by CI writers and/or the command line; note that setting --mode=ALL would be incorrect if # supportMultipleModesPerRun=false but that's a legacy options so we raise an exception later if this happened) args = [ '--purge', '--record', '-j0', '--type=auto', '--mode=ALL', '-XcodeCoverage' ] + args printLogsDefault = PrintLogs.FAILURES 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) log.debug('PySys arguments: tests=%s options=%s', self.arguments, optlist) EXPR1 = re.compile("^[\w\.]*=.*$") EXPR2 = re.compile("^[\w\.]*$") printLogs = None ci = False defaultAbortOnError = None logging.getLogger('pysys').setLevel(logging.INFO) # as a special case, set a non-DEBUG log level for the implementation of assertions # so that it doesn't get enabled with -vDEBUG only -vassertions=DEBUG # as it is incredibly verbose and slow and not often useful logging.getLogger('pysys.assertions').setLevel(logging.INFO) for option, value in optlist: if option in ("-h", "--help"): self.printUsage(printXOptions) elif option in ['--ci']: continue # handled above elif option in ("-r", "--record"): self.record = True elif option in ("-p", "--purge"): self.purge = True elif option in ("-v", "--verbosity"): verbosity = value if '=' in verbosity: loggername, verbosity = value.split('=') assert not loggername.startswith( 'pysys.' ), 'The "pysys." prefix is assumed and should not be explicitly specified' if loggername.startswith('python:'): loggername = loggername[len('python:'):] assert not loggername.startswith( 'pysys' ), 'Cannot use python: with pysys.*' # would produce a duplicate log handler # in the interests of performance and simplicity we normally only add the pysys.* category logging.getLogger(loggername).addHandler( pysys.internal.initlogging.pysysLogHandler) else: loggername = 'pysys.' + loggername else: loggername = None if verbosity.upper() == "DEBUG": verbosity = logging.DEBUG elif verbosity.upper() == "INFO": verbosity = logging.INFO elif verbosity.upper() == "WARN": verbosity = logging.WARN elif verbosity.upper() == "CRIT": verbosity = logging.CRITICAL else: log.warn('Invalid log level "%s"' % verbosity) sys.exit(1) if loggername is None: # when setting global log level to a higher level like WARN etc we want to affect stdout but # not necessarily downgrade the root level (would make run.log less useful and break # some PrintLogs behaviour) stdoutHandler.setLevel(verbosity) if verbosity == logging.DEBUG: logging.getLogger('pysys').setLevel(logging.DEBUG) else: # for specific level setting we need the opposite - only change stdoutHandler if we're # turning up the logging (since otherwise it wouldn't be seen) but also change the specified level logging.getLogger(loggername).setLevel(verbosity) 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 ("-c", "--cycle"): try: self.cycle = int(value) except Exception: print( "Error parsing command line arguments: A valid integer for the number of cycles must be supplied" ) sys.exit(1) elif option in ("-o", "--outdir"): value = os.path.normpath(value) if os.path.isabs(value) and not value.startswith('\\\\?\\'): value = fromLongPathSafe(toLongPathSafe(value)) self.outsubdir = value elif option in ("-m", "--mode", "--modeinclude"): self.modeinclude = self.modeinclude + [ x.strip() for x in value.split(',') ] elif option in ["--modeexclude"]: self.modeexclude = self.modeexclude + [ x.strip() for x in value.split(',') ] elif option in ["-n", "-j", "--threads"]: N_CPUS = multiprocessing.cpu_count() if value.lower() == 'auto': value = '0' if value.lower().startswith('x'): self.threads = max(1, int(float(value[1:]) * N_CPUS)) else: self.threads = int(value) if self.threads <= 0: self.threads = int( os.getenv('PYSYS_DEFAULT_THREADS', N_CPUS)) elif option in ("-b", "--abort"): defaultAbortOnError = str(value.lower() == 'true') elif option in ["-g", "--progress"]: self.progress = True elif option in ["--printLogs"]: printLogs = getattr(PrintLogs, value.upper(), None) if printLogs is None: print( "Error parsing command line arguments: Unsupported --printLogs value '%s'" % value) sys.exit(1) elif option in ["-X"]: if '=' in value: key, value = value.split('=', 1) else: key, value = value, 'true' # best not to risk unintended consequences with matching of other types, but for boolean # it's worth it to resolve the inconsistent behaviour of -Xkey=true and -Xkey that existed until 1.6.0, # and because getting a bool where you expected a string is a bit more likely to give an exception # and be noticed that getting a string where you expected a boolean (e.g. the danger of if "false":) if value.lower() == 'true': value = True elif value.lower() == 'false': value = False self.userOptions[key] = value elif option in ("-y", "--validateOnly"): self.userOptions['validateOnly'] = True elif option in ("-G", "--grep"): self.grep = value else: print("Unknown option: %s" % option) sys.exit(1) # log this once we've got the log levels setup log.debug('PySys is installed at: %s; python from %s', os.path.dirname(pysys.__file__), sys.executable) # retained for compatibility, but PYSYS_DEFAULT_ARGS is a better way to achieve the same thing if os.getenv('PYSYS_PROGRESS', '').lower() == 'true': self.progress = True # special hidden dict of extra values to pass to the runner, since we can't change # the public API now self.userOptions['__extraRunnerOptions'] = { 'progressWritersEnabled': self.progress, 'printLogs': printLogs, 'printLogsDefault': printLogsDefault, # to use if not provided by a CI writer or cmdline } # load project AFTER we've parsed the arguments, which opens the possibility of using cmd line config in # project properties if needed Project.findAndLoadProject(outdir=self.outsubdir) if defaultAbortOnError is not None: setattr(Project.getInstance(), 'defaultAbortOnError', defaultAbortOnError) if '--ci' in args and not Project.getInstance().getProperty( 'supportMultipleModesPerRun', True): raise UserError( 'Cannot use --ci option with a legacy supportMultipleModesPerRun=false project' ) descriptors = createDescriptors(self.arguments, self.type, self.includes, self.excludes, self.trace, self.workingDir, modeincludes=self.modeinclude, modeexcludes=self.modeexclude, expandmodes=True) descriptors.sort( key=lambda d: [d.executionOrderHint, d._defaultSortKey]) # No exception handler above, as any createDescriptors failure is really a fatal problem that should cause us to # terminate with a non-zero exit code; we don't want to run no tests without realizing it and return success if self.grep: regex = re.compile(self.grep, flags=re.IGNORECASE) descriptors = [ d for d in descriptors if (regex.search(d.id) or regex.search(d.title)) ] runnermode = self.modeinclude[0] if len( self.modeinclude ) == 1 else None # used when supportMultipleModesPerRun=False return self.record, self.purge, self.cycle, runnermode, self.threads, self.outsubdir, descriptors, self.userOptions
def makeProject(args): _PYSYS_SCRIPT_NAME = os.path.basename( sys.argv[0]) if '__main__' not in sys.argv[0] else 'pysys.py' templatelist = ', '.join(sorted(getProjectConfigTemplates().keys())) def printUsage(): print( "\nPySys System Test Framework (version %s): Project configuration file maker" % __version__) print("") print("Usage: %s makeproject [option]* [--template=TEMPLATE]" % (_PYSYS_SCRIPT_NAME)) print("") print(" where TEMPLATE can be: %s" % templatelist) print("") print(" and [option] includes:") print(" -h | --help print this message") print( " -d | --dir STRING root directory in which to create project configuration file" ) print( " (default is current working dir)" ) print("") print("Project configuration templates are stored in: %s" % os.path.normpath( os.path.dirname(getProjectConfigTemplates()['default']))) sys.exit() optionString = 'hd:' optionList = ['dir=', 'help', 'template='] try: optlist, arguments = getopt.gnu_getopt(args, optionString, optionList) except Exception: log.warn("Error parsing command line arguments: %s" % (sys.exc_info()[1])) sys.exit(1) dir = '.' tmpl = 'default' for option, value in optlist: if option in ["-h", "--help"]: printUsage() if option in ["--template"]: tmpl = value elif option in ["-d", "--dir"]: dir = value else: print("Unknown option: %s" % option) sys.exit(1) if arguments: print("Unexpected argument '%s'; maybe you meant to use --template" % arguments[0]) sys.exit(1) templates = getProjectConfigTemplates() if tmpl not in templates: print( "Unknown template '%s', please specify one of the following: %s" % (tmpl, templatelist)) sys.exit(1) if os.path.exists(dir): for f in os.listdir(dir): if f in DEFAULT_PROJECTFILE: print("Cannot create as project file already exists: %s" % os.path.normpath(dir + '/' + f)) sys.exit(1) createProjectConfig(dir, templates[tmpl]) print( "Successfully created project configuration in root directory '%s'." % os.path.normpath(dir)) print( "Now change to that directory and use 'pysys make' to create your first testcase." )
def assertGrep(self, file, filedir=None, expr='', contains=True, ignores=None, literal=False, encoding=None, **xargs): """Perform a validation assert on a regular expression occurring in a text file. When the C{contains} input argument is set to true, this method will add a C{PASSED} outcome to the test outcome list if the supplied regular expression is seen in the file; otherwise a C{FAILED} outcome is added. Should C{contains} be set to false, a C{PASSED} outcome will only be added should the regular expression not be seen in the file. @param file: The basename of the file used in the grep @param filedir: The dirname of the file (defaults to the testcase output subdirectory) @param expr: The regular expression to check for in the file (or a string literal if literal=True). If the match fails, the matching regex will be reported as the test outcome @param contains: Boolean flag to denote if the expression should or should not be seen in the file @param ignores: Optional list of regular expressions that will be ignored when reading the file. @param literal: By default expr is treated as a regex, but set this to True to pass in a string literal instead @param encoding: The encoding to use to open the file. The default value is None which indicates that the decision will be delegated to the L{getDefaultFileEncoding()} method. @param xargs: Variable argument list (see class description for supported parameters) """ if filedir is None: filedir = self.output f = os.path.join(filedir, file) if literal: def escapeRegex(expr): # use our own escaping as re.escape makes the string unreadable regex = expr expr = '' for c in regex: if c in '\\{}[]+?^$': expr += '\\'+c elif c in '().*/': expr += '['+c+']' # more readable else: expr += c return expr expr = escapeRegex(expr) log.debug("Performing grep on file:") log.debug(" file: %s" % file) log.debug(" filedir: %s" % filedir) log.debug(" expr: %s" % expr) log.debug(" contains: %s" % LOOKUP[contains]) try: result = filegrep(f, expr, ignores=ignores, returnMatch=True, encoding=encoding or self.getDefaultFileEncoding(f)) except Exception: log.warn("caught %s: %s", sys.exc_info()[0], sys.exc_info()[1], exc_info=1) msg = self.__assertMsg(xargs, 'Grep on %s %s %s'%(file, 'contains' if contains else 'does not contain', quotestring(expr) )) self.addOutcome(BLOCKED, '%s failed due to %s: %s'%(msg, sys.exc_info()[0], sys.exc_info()[1]), abortOnError=self.__abortOnError(xargs)) else: # short message if it succeeded, more verbose one if it failed to help you understand why, # including the expression it found that should not have been there outcome = PASSED if (result!=None) == contains else FAILED if outcome == PASSED: msg = self.__assertMsg(xargs, 'Grep on input file %s' % file) else: msg = self.__assertMsg(xargs, 'Grep on %s %s %s'%(file, 'contains' if contains else 'does not contain', quotestring(result.group(0) if result else expr) )) self.addOutcome(outcome, msg, abortOnError=self.__abortOnError(xargs))