Exemplo n.º 1
0
    def clean(self):
        descriptors = createDescriptors(self.arguments, None, [], [], None,
                                        self.workingDir)
        for descriptor in descriptors:
            if self.all:
                if sys.version_info >= (3, ):
                    cache = os.path.join(os.path.dirname(descriptor.module),
                                         "__pycache__")
                    if os.path.exists(cache):
                        log.info("Deleting pycache: " + cache)
                        self.purgeDirectory(cache, True)
                else:
                    path = descriptor.module + ".pyc"
                    try:
                        mode = os.stat(path)[stat.ST_MODE]
                        if stat.S_ISLNK(mode):
                            os.unlink(path)
                        if stat.S_ISREG(mode):
                            os.remove(path)
                        log.info("Deleting compiled module: " + path)
                    except Exception:
                        log.debug("Error deleting compiled module: " + path)

            pathToDelete = os.path.join(descriptor.output, self.outsubdir)
            if os.path.exists(pathToDelete):
                log.info("Deleting output directory: " + pathToDelete)
                self.purgeDirectory(pathToDelete, True)
            else:
                log.debug("Output directory does not exist: " + pathToDelete)
Exemplo n.º 2
0
    def printTests(self):
        descriptors = createDescriptors(self.arguments, self.type,
                                        self.includes, self.excludes,
                                        self.trace, self.workingDir)
        exit = 0
        if self.groups == True:
            groups = []
            for descriptor in descriptors:
                for group in descriptor.groups:
                    if group not in groups:
                        groups.append(group)
            print("\nGroups defined: ")
            for group in groups:
                print("                 %s" % (group))
            exit = 1

        if self.modes == True:
            modes = []
            for descriptor in descriptors:
                for mode in descriptor.modes:
                    if mode not in modes:
                        modes.append(mode)
            print("\nModes defined: ")
            for mode in modes:
                print("                 %s" % (mode))
            exit = 1

        if self.requirements == True:
            requirements = []
            for descriptor in descriptors:
                for requirement in descriptor.traceability:
                    if requirement not in requirements:
                        requirements.append(requirement)
            print("\nRequirements covered: ")
            for requirement in requirements:
                print("                 %s" % (requirement))
            exit = 1

        if exit: return

        maxsize = 0
        for descriptor in descriptors:
            if len(descriptor.id) > maxsize: maxsize = len(descriptor.id)
        maxsize = maxsize + 2

        for descriptor in descriptors:
            if self.mode and not self.mode in descriptor.modes: continue
            padding = " " * (maxsize - len(descriptor.id))
            if not self.full:
                print("%s:%s%s" % (descriptor.id, padding, descriptor.title))
            else:
                print("==========================================")
                print("		" + descriptor.id)
                print("==========================================")
                print(descriptor)
Exemplo n.º 3
0
    def clean(self):
        Project.findAndLoadProject(outdir=self.outsubdir)

        descriptors = createDescriptors(self.arguments,
                                        None, [], [],
                                        None,
                                        self.workingDir,
                                        expandmodes=False)
        supportMultipleModesPerRun = Project.getInstance().getProperty(
            'supportMultipleModesPerRun', True)

        for descriptor in descriptors:
            if self.all:
                modulepath = os.path.join(descriptor.testDir,
                                          descriptor.module)
                cache = os.path.join(os.path.dirname(modulepath),
                                     "__pycache__")
                if os.path.isdir(cache):
                    log.info("Deleting pycache: " + cache)
                    deletedir(cache)
                else:
                    log.debug('__pycache__ does not exist: %s', cache)
                path = modulepath + ".pyc"
                if os.path.exists(path):
                    log.info("Deleting compiled Python module: " + path)
                    os.remove(path)
                else:
                    log.debug('.pyc does not exist: %s', path)

            for mode in (descriptor.modes or [None]):
                pathToDelete = os.path.join(descriptor.testDir,
                                            descriptor.output, self.outsubdir)

                if os.path.isabs(self.outsubdir
                                 ):  # must delete only the selected testcase
                    pathToDelete += "/" + descriptor.id

                if supportMultipleModesPerRun and mode:
                    pathToDelete += '~' + mode

                if os.path.exists(pathToDelete):
                    log.info("Deleting output directory: " + pathToDelete)
                    deletedir(pathToDelete)
                else:
                    log.debug("Output directory does not exist: " +
                              pathToDelete)
Exemplo n.º 4
0
    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
Exemplo n.º 5
0
    def printTests(self):
        Project.findAndLoadProject()

        # nb: mode filtering happens later
        descriptors = createDescriptors(
            self.arguments,
            self.type,
            self.includes,
            self.excludes,
            self.trace,
            self.workingDir,
            expandmodes=True if self.modefilter else False,
            modeincludes=self.modefilter)

        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))
            ]

        # nb: do this case insensitively since if someone uses inconsistent capitaization they still probably
        # want related items to show up next to each other
        if not self.sort:
            descriptors.sort(key=lambda d: d._defaultSortKey.lower())
        elif (self.sort.lower() == 'id'):
            descriptors.sort(key=lambda d: d.id.lower())
        elif self.sort.lower().replace(
                '-', '') in ['executionorderhint', 'orderhint', 'order']:
            descriptors.sort(key=lambda d:
                             [d.executionOrderHint,
                              d._defaultSortKey.lower()])
        elif self.sort.lower() == 'title':
            descriptors.sort(
                key=lambda d:
                [d.title.lower(), d.title,
                 d._defaultSortKey.lower()])
        else:
            raise UserError('Unknown sort key: %s' % self.sort)

        if self.json:
            print(
                json.dumps([d.toDict() for d in descriptors],
                           indent=3,
                           sort_keys=False))
            return

        exit = 0
        if self.groups == True:
            groups = []
            for descriptor in descriptors:
                for group in descriptor.groups:
                    if group not in groups:
                        groups.append(group)
            print("\nGroups defined: ")
            for group in groups:
                print("  %s" % (group))
            exit = 1

        if self.modes == True:
            modes = []
            for descriptor in descriptors:
                for mode in descriptor.modes:
                    if mode not in modes:
                        modes.append(mode)
            print("\nModes defined: ")
            for mode in modes:
                print("  %s" % (mode))
            exit = 1

        if self.requirements == True:
            requirements = []
            for descriptor in descriptors:
                for requirement in descriptor.traceability:
                    if requirement not in requirements:
                        requirements.append(requirement)
            print("\nTraceability requirement ids covered: ")
            for requirement in requirements:
                print("  %s" % (requirement))
            exit = 1

        if exit: return

        maxsize = 0
        for descriptor in descriptors:
            if len(descriptor.id) > maxsize: maxsize = len(descriptor.id)
        maxsize = maxsize + 2

        for descriptor in descriptors:
            padding = " " * (maxsize - len(descriptor.id))
            if not self.full:
                print("%s%s| %s" % (descriptor.id, padding, descriptor.title))
            else:
                print("=" * 80)
                print(descriptor)
Exemplo n.º 6
0
    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