Пример #1
0
    def go(self):
        """ Execute the test step """
        super(Execute, self).go()

        try:
            self.executor.go(self.plan.workdir)
        except tmt.utils.GeneralError as error:
            self.info('Error occured during test execution.', color='red')
            self.plan.provision.execute('cat nohup.out')

        self.plan.provision.sync_workdir_from_guest()

        output = {}
        for logname in ['stdout.log', 'stderr.log']:
            logpath = os.path.join(self.workdir, logname)
            output[logname] = open(logpath).read()
            self.debug(logname, output[logname], 'yellow')

        # Process the stdout.log
        overview = output['stdout.log'].rstrip('\nD')
        self.verbose('overview', overview, color='green', shift=1)
        passed = 0
        failed = 0
        for character in output['stdout.log']:
            if character == '.':
                passed += 1
            if character == 'F':
                failed += 1
        passed = listed(passed, 'test')
        failed = listed(failed, 'test')
        message = f"{passed} passed, {failed} failed"
        self.info('result', message, color='green', shift=1)
Пример #2
0
 def overview(tree):
     """ Show overview of available tests """
     tests = [style(str(test), fg='red') for test in tree.tests()]
     echo(
         style('Found {}{}{}.'.format(listed(tests, 'test'),
                                      ': ' if tests else '',
                                      listed(tests, max=12)),
               fg='blue'))
Пример #3
0
 def overview(tree):
     """ Show overview of available plans """
     plans = [style(str(plan), fg='red') for plan in tree.plans()]
     echo(
         style('Found {}{}{}.'.format(listed(plans, 'plan'),
                                      ': ' if plans else '',
                                      listed(plans, max=12)),
               fg='blue'))
Пример #4
0
 def overview(tree):
     """ Show overview of available stories """
     stories = [style(str(story), fg='red') for story in tree.stories()]
     echo(
         style('Found {}{}{}.'.format(listed(stories, 'story'),
                                      ': ' if stories else '',
                                      listed(stories, max=12)),
               fg='blue'))
Пример #5
0
def finito(commands, *args, **kwargs):
    """ Process the main callback """
    # Show all commands that have been provided
    log.info('Detected {0}{1}.'.format(listed(
        commands, 'command'), (': ' + listed(commands)) if commands else ''))

    # Run test steps if any explicitly requested or no command given at all
    if not commands or any([step in commands for step in tmt.steps.STEPS]):
        run.go()
Пример #6
0
    def show(self, brief=False, formatting=None, values=[]):
        """ Show metadata """
        # Show nothing if there's nothing
        if not self.data:
            return None

        # Custom formatting
        if formatting is not None:
            formatting = re.sub("\\\\n", "\n", formatting)
            name = self.name
            data = self.data
            root = self.root
            evaluated = []
            for value in values:
                evaluated.append(eval(value))
            return formatting.format(*evaluated)

        # Show the name
        output = utils.color(self.name, 'red')
        if brief:
            return output
        # List available attributes
        for key, value in sorted(self.data.items()):
            output += "\n{0}: ".format(utils.color(key, 'yellow'))
            if isinstance(value, type("")):
                output += value
            elif isinstance(value, list) and all(
                [isinstance(item, type("")) for item in value]):
                output += utils.listed(value)
            else:
                output += pretty(value)
            output
        return output + "\n"
Пример #7
0
Файл: cli.py Проект: thrix/fmf
    def show(self, brief=False):
        """ Show metadata for each path given """
        output = []
        for path in self.options.paths or ["."]:
            if self.options.verbose:
                utils.info("Checking {0} for metadata.".format(path))
            tree = fmf.Tree(path)
            for node in tree.prune(self.options.whole, self.options.keys,
                                   self.options.names, self.options.filters,
                                   self.options.conditions):
                if brief:
                    show = node.show(brief=True)
                else:
                    show = node.show(brief=False,
                                     formatting=self.options.formatting,
                                     values=self.options.values)
                # List source files when in debug mode
                if self.options.debug:
                    for source in node.sources:
                        show += utils.color("{0}\n".format(source), "blue")
                if show is not None:
                    output.append(show)

        # Print output and summary
        if brief or self.options.formatting:
            joined = "".join(output)
        else:
            joined = "\n".join(output)
        print(joined, end="")
        if self.options.verbose:
            utils.info("Found {0}.".format(utils.listed(len(output),
                                                        "object")))
        self.output = joined
Пример #8
0
def main(cmdline=None):
    """ Parse options, gather metadata, print requested data """

    # Parse command line arguments
    options, arguments = Options().parse(cmdline)
    if not arguments:
        arguments = ["."]
    output = ""

    # Enable debugging output
    if options.debug:
        utils.log.setLevel(utils.LOG_DEBUG)

    # Show metadata for each path given
    counter = 0
    for path in arguments:
        if options.verbose:
            utils.info("Checking {0} for metadata.".format(path))
        tree = fmf.Tree(path)
        for node in tree.prune(options.whole, options.keys, options.names,
                               options.filters):
            show = node.show(options.brief, options.formatting, options.values)
            if show is not None:
                print(show, end="")
                output += show
                counter += 1
    # Print summary
    if options.verbose:
        utils.info("Found {0}.".format(utils.listed(counter, "object")))
    return output
Пример #9
0
 def summary(self):
     """ Give a concise summary of the discovery """
     # Summary of selected tests
     text = listed(len(self.tests()), 'test') + ' selected'
     self.info('summary', text, 'green', shift=1)
     # Test list in verbose mode
     for test in self.tests():
         self.verbose(test.name, color='red', shift=2)
Пример #10
0
def go():
    """ Go and do test steps for selected plans """
    echo(
        style('Found {0}.\n'.format(listed(tree.plans(), 'plan')),
              fg='magenta'))
    for plan in tree.plans():
        plan.ls(summary=True)
        plan.go()
        echo()
Пример #11
0
    def go(self):
        """ Go and do test steps for selected plans """
        # Show run id / workdir path
        self.info(self.workdir, color='magenta')
        # Attempt to load run data
        self.load()

        if self.opt('follow'):
            self.follow()

        # Enable selected steps
        enabled_steps = self._context.obj.steps
        all_steps = self.opt('all') or not enabled_steps
        since = self.opt('since')
        until = self.opt('until')
        after = self.opt('after')
        before = self.opt('before')
        skip = self.opt('skip')

        if all_steps or since or until:
            # Detect index of the first and last enabled step
            if since:
                first = tmt.steps.STEPS.index(since)
            elif after:
                first = tmt.steps.STEPS.index(after) + 1
            else:
                first = tmt.steps.STEPS.index('discover')
            if until:
                last = tmt.steps.STEPS.index(until)
            elif before:
                last = tmt.steps.STEPS.index(before) - 1
            else:
                last = tmt.steps.STEPS.index('finish')
            # Enable all steps between the first and last
            for index in range(first, last + 1):
                step = tmt.steps.STEPS[index]
                if step not in skip:
                    enabled_steps.add(step)
        self.debug(f"Enabled steps: {fmf.utils.listed(enabled_steps)}")

        # Show summary, store run data
        if not self.plans:
            raise tmt.utils.GeneralError("No plans found.")
        self.verbose('Found {0}.'.format(listed(self.plans, 'plan')))
        self.save()

        # Iterate over plans
        for plan in self.plans:
            plan.go()

        # Update the last run id at the very end
        # (override possible runs created during execution)
        self.config.last_run(self.workdir)

        # Give the final summary, remove workdir, handle exit codes
        self.finish()
Пример #12
0
 def go(self):
     """ Go and do test steps for selected plans """
     # Show run id / workdir path
     self.info(self.workdir, color='magenta')
     # Enable all steps if none selected or --all provided
     if self.opt('all_') or not self._context.obj.steps:
         self._context.obj.steps = set(tmt.steps.STEPS)
     # Show summary and iterate over plans
     self.verbose('Found {0}.'.format(listed(self.plans, 'plan')))
     for plan in self.plans:
         plan.go()
Пример #13
0
def coverage(
        context, code, test, docs,
        implemented, verified, documented, covered,
        unimplemented, unverified, undocumented, uncovered, **kwargs):
    """
    Show code, test and docs coverage for given stories.

    Regular expression can be used to filter stories by name.
    Use '.' to select stories under the current working directory.
    """
    tmt.Story._save_context(context)

    def headfoot(text):
        """ Format simple header/footer """
        echo(style(text.rjust(4) + ' ', fg='blue'), nl=False)

    header = False
    total = code_coverage = test_coverage = docs_coverage = 0
    if not any([code, test, docs]):
        code = test = docs = True
    for story in context.obj.tree.stories():
        # Check conditions
        if not story._match(
                implemented, verified, documented, covered, unimplemented,
                unverified, undocumented, uncovered):
            continue
        # Show header once
        if not header:
            if code:
                headfoot('code')
            if test:
                headfoot('test')
            if docs:
                headfoot('docs')
            headfoot('story')
            echo()
            header = True
        # Show individual stats
        status = story.coverage(code, test, docs)
        total += 1
        code_coverage += status[0]
        test_coverage += status[1]
        docs_coverage += status[2]
    # Summary
    if not total:
        return
    if code:
        headfoot('{}%'.format(round(100 * code_coverage / total)))
    if test:
        headfoot('{}%'.format(round(100 * test_coverage / total)))
    if docs:
        headfoot('{}%'.format(round(100 * docs_coverage / total)))
    headfoot('from {}'.format(listed(total, 'story')))
    echo()
Пример #14
0
    def go(self):
        """ Execute the test step """
        super(Execute, self).go()

        lognames = ('stdout.log', 'stderr.log', 'nohup.out')

        # Remove logs prior to write
        for name in lognames:
            logpath = os.path.join(self.workdir, name)
            if os.path.exists(logpath):
                os.remove(logpath)

        try:
            self.executor.go(self.plan.workdir)
        except tmt.utils.GeneralError as error:
            self.get_logs(lognames)
            raise tmt.utils.GeneralError(f'Test execution failed: {error}')

        output = self.get_logs(lognames)

        # Process the stdout.log
        overview = output['stdout.log'].rstrip('\nD')
        self.verbose('overview', overview, color='green', shift=1)
        passed = 0
        failed = 0
        errors = 0
        for character in output['stdout.log']:
            if character == '.':
                passed += 1
            if character == 'F':
                failed += 1
            if character == 'E':
                errors += 1
        passed = listed(passed, 'test')
        failed = listed(failed, 'test')
        message = f"{passed} passed, {failed} failed"
        self.info('result', message, color='green', shift=1)
        if errors > 0:
            raise tmt.utils.GeneralError(
                f"{errors} errors occured during tests.")
Пример #15
0
def init(context, path, template, force, **kwargs):
    """
    Initialize a new tmt tree.

    By default tree is created in the current directory.
    Provide a PATH to create it in a different location.

    \b
    A tree can be optionally populated with example metadata:
    * 'mini' template contains a minimal plan and no tests,
    * 'base' template contains a plan and a beakerlib test,
    * 'full' template contains a 'full' story, an 'full' plan and a shell test.
    """

    # Check for existing tree
    path = os.path.realpath(path)
    try:
        tree = tmt.Tree(path)
        # Are we creating a new tree under the existing one?
        if path == tree.root:
            echo("Tree '{}' already exists.".format(tree.root))
        else:
            tree = None
    except tmt.utils.GeneralError:
        tree = None
    # Create a new tree
    if tree is None:
        try:
            fmf.Tree.init(path)
            tree = tmt.Tree(path)
        except fmf.utils.GeneralError as error:
            raise tmt.utils.GeneralError(
                "Failed to initialize tree in '{}': {}".format(
                    path, error))
        echo("Tree '{}' initialized.".format(tree.root))

    # Populate the tree with example objects if requested
    if template == 'empty':
        non_empty_choices = [c for c in _init_template_choices if c != 'empty']
        echo("To populate it with example content, use --template with "
             "{}.".format(listed(non_empty_choices, join='or')))
    else:
        echo("Applying template '{}'.".format(template, _init_templates))
    if template == 'mini':
        tmt.Plan.create('/plans/example', 'mini', tree, force)
    elif template == 'base':
        tmt.Test.create('/tests/example', 'beakerlib', tree, force)
        tmt.Plan.create('/plans/example', 'base', tree, force)
    elif template == 'full':
        tmt.Test.create('/tests/example', 'shell', tree, force)
        tmt.Plan.create('/plans/example', 'full', tree, force)
        tmt.Story.create('/stories/example', 'full', tree, force)
Пример #16
0
 def get_command(self, context, cmd_name):
     """ Allow command shortening """
     # Support both story & stories
     cmd_name = cmd_name.replace('story', 'stories')
     found = click.Group.get_command(self, context, cmd_name)
     if found is not None:
         return found
     matches = [command for command in self.list_commands(context)
                if command.startswith(cmd_name)]
     if not matches:
         return None
     elif len(matches) == 1:
         return click.Group.get_command(self, context, matches[0])
     context.fail('Did you mean {}?'.format(
         listed(sorted(matches), join='or')))
Пример #17
0
 def tests(self):
     """ Return all discovered tests """
     # Show filters if provided
     if self.filters:
         for filter_ in self.filters:
             self.info('filter', filter_, 'green')
     # Nothing to do in dry mode
     if self.opt('dry'):
         return []
     # Prepare test name filter if provided
     tests = self.tests_tree.tests(filters=self.filters)
     # Summary of selected tests, test list in verbose mode
     self.info('tests', listed(len(tests), 'test') + ' selected', 'green')
     for test in tests:
         self.verbose(test.name, color='red', shift=1)
     return tests
Пример #18
0
 def show(self, brief=False):
     """ Show metadata """
     # Show the name
     output = utils.color(self.name, 'red')
     if brief:
         return output
     # List available attributes
     for key, value in sorted(self.data.iteritems()):
         output += "\n{0}: ".format(utils.color(key, 'yellow'))
         if isinstance(value, basestring):
             output += value
         elif isinstance(value, list) and all(
                 [isinstance(item, basestring) for item in value]):
             output += utils.listed(value)
         else:
             output += pretty(value)
         output
     return output
Пример #19
0
def coverage(
    context, code, test, docs,
    implemented, tested, documented, covered,
    unimplemented, untested, undocumented, uncovered, **kwargs):
    """ Show code, test and docs coverage for given stories. """
    tmt.Story._context = context

    def headfoot(text):
        """ Format simple header/footer """
        echo(style(text.rjust(4) + ' ', fg='blue'), nl=False)

    header = False
    total = code_coverage = test_coverage = docs_coverage = 0
    if not any([code, test, docs]):
        code = test = docs = True
    for story in context.obj.tree.stories():
        # Header
        if not header:
            if code:
                headfoot('code')
            if test:
                headfoot('test')
            if docs:
                headfoot('docs')
            headfoot('story')
            echo()
            header = True
        # Coverage
        if story._match(implemented, tested, documented, covered,
                unimplemented, untested, undocumented, uncovered):
            status = story.coverage(code, test, docs)
            total += 1
            code_coverage += status[0]
            test_coverage += status[1]
            docs_coverage += status[2]
    # Summary
    if code:
        headfoot('{}%'.format(round(100 * code_coverage / total)))
    if test:
        headfoot('{}%'.format(round(100 * test_coverage / total)))
    if docs:
        headfoot('{}%'.format(round(100 * docs_coverage / total)))
    headfoot('from {}'.format(listed(total, 'story')))
    echo()
Пример #20
0
Файл: cli.py Проект: jscotka/fmf
def main(cmdline=None):
    """ Parse options, gather metadata, print requested data """

    # Parse command line arguments
    options, arguments = Options().parse(cmdline)
    if not arguments:
        arguments = ["."]
    output = ""

    # Enable debugging output
    if options.debug:
        utils.log.setLevel(utils.LOG_DEBUG)

    # Show metadata for each path given
    counter = 0
    for path in arguments:
        if options.verbose:
            utils.info("Checking {0} for metadata.".format(path))
        tree = fmf.Tree(path)
        for node in tree.climb(options.whole):
            # Select only nodes with key content
            if not all([key in node.data for key in options.keys]):
                continue
            # Select nodes with name matching regular expression
            if options.names and not any(
                    [re.search(name, node.name) for name in options.names]):
                continue
            # Apply advanced filters if given
            try:
                if not all([utils.filter(filter, node.data)
                        for filter in options.filters]):
                    continue
            # Handle missing attribute as if filter failed
            except utils.FilterError:
                continue
            show = node.show(brief=options.brief)
            print(show)
            output += show + "\n"
            counter += 1
    # Print summary
    if options.verbose:
        utils.info("Found {0}.".format(utils.listed(counter, "object")))
    return output
Пример #21
0
    def export(self, format_='rst', title=True):
        """ Export story data into requested format """

        output = ''

        # Title and its anchor
        if title:
            depth = len(re.findall('/', self.name)) - 1
            title = self.title or re.sub('.*/', '', self.name)
            output += f'\n.. _{self.name}:\n'
            output += '\n{}\n{}\n'.format(title, '=~^:-><'[depth] * len(title))

        # Summary, story and description
        if self.summary and self.summary != self.node.parent.get('summary'):
            output += '\n{}\n'.format(self.summary)
        if self.story != self.node.parent.get('story'):
            output += '\n*{}*\n'.format(self.story.strip())
        if self.description:
            output += '\n{}\n'.format(self.description)

        # Examples
        if self.example:
            output += '\nExamples::\n\n'
            output += tmt.utils.format('',
                                       self.example,
                                       wrap=False,
                                       indent=4,
                                       key_color=None,
                                       value_color=None) + '\n'

        # Status
        if not self.node.children:
            status = []
            for coverage in ['implemented', 'tested', 'documented']:
                if getattr(self, coverage):
                    status.append(coverage)
            output += "\nStatus: {}\n".format(
                listed(status) if status else 'idea')

        return output
Пример #22
0
 def go(self):
     """ Discover available tests """
     super(DiscoverFmf, self).go()
     testdir = os.path.join(self.workdir, 'tests')
     # Clone provided git repository
     if self.repository:
         self.info('repository', self.repository, 'green')
         self.debug(f"Clone '{self.repository}' to '{testdir}'.")
         self.run(f'git clone {self.repository} {testdir}')
     # Copy current directory to workdir
     else:
         directory = self.step.plan.run.tree.root
         self.info('directory', directory, 'green')
         self.debug("Copy '{}' to '{}'.".format(directory, testdir))
         shutil.copytree(directory, testdir)
     # Checkout revision if requested
     if self.revision:
         self.info('revision', self.revision, 'green')
         self.debug(f"Checkout revision '{self.revision}'.")
         self.run(f"git checkout -f {self.revision}", cwd=testdir)
     # Show filters if provided
     if self.filters:
         for filter_ in self.filters:
             self.info('filter', filter_, 'green')
     # Initialize the metadata tree
     self.debug(f"Check metadata tree in '{testdir}'.")
     # Nothing more to do here when in dry mode
     if self.opt('dry'):
         return []
     tests = tmt.Tree(testdir).tests(filters=self.filters)
     # Modify test names and paths to make them unique
     for test in tests:
         test.name = f"/{self.name}{test.name}"
         test.path = f"/{self.name}/tests{test.path}"
     # Summary of selected tests, test list in verbose mode
     self.info('tests', listed(len(tests), 'test') + ' selected', 'green')
     for test in tests:
         self.verbose(test.name, color='red', shift=1)
     self._tests = tests
Пример #23
0
 def test_text(self):
     assert (listed(range(6), 'category') == '6 categories')
     assert (listed(7, "leaf", "leaves") == '7 leaves')
     assert (listed(0, "item") == "0 items")
Пример #24
0
    Regular expression can be used to filter tests for linting.
    Use '.' to select tests under the current working directory.
    """
    # FIXME: Workaround https://github.com/pallets/click/pull/1840 for click 7
    context.params.update(kwargs)
    tmt.Test._save_context(context)
    exit_code = 0
    for test in context.obj.tree.tests():
        if not test.lint():
            exit_code = 1
        echo()
    raise SystemExit(exit_code)


_test_templates = listed(tmt.templates.TEST, join='or')


@tests.command()
@click.pass_context
@click.argument('name')
@click.option('-t',
              '--template',
              metavar='TEMPLATE',
              help='Test template ({}).'.format(_test_templates),
              prompt='Template ({})'.format(_test_templates))
@verbose_debug_quiet
@force_dry
def create(context, name, template, force, **kwargs):
    """
    Create a new test based on given template.
Пример #25
0
 def test_basic(self):
     assert (listed(range(1)) == '0')
     assert (listed(range(2)) == '0 and 1')
Пример #26
0
 def test_quoting(self):
     assert (listed(range(3), quote='"') == '"0", "1" and "2"')
Пример #27
0
Файл: cli.py Проект: happz/tmt
@name_filter_condition
@verbose_debug_quiet
def lint(context, **kwargs):
    """
    Check tests against the L1 metadata specification

    Regular expression can be used to filter tests for linting.
    Use '.' to select tests under the current working directory.
    """
    tmt.Test._save_context(context)
    for test in context.obj.tree.tests():
        test.lint()
        echo()


_test_templates = listed(tmt.templates.TEST, join='or')


@tests.command()
@click.pass_context
@click.argument('name')
@click.option('-t',
              '--template',
              metavar='TEMPLATE',
              help='Test template ({}).'.format(_test_templates),
              prompt='Template ({})'.format(_test_templates))
@verbose_debug_quiet
@force_dry
def create(context, name, template, force, **kwargs):
    """ Create a new test based on given template. """
    tmt.Test._save_context(context)
Пример #28
0
 def test_max(self):
     assert (listed(range(4), max=3) == '0, 1, 2 and 1 more')
     assert (listed(range(5), 'number', max=2) == '0, 1 and 3 more numbers')
Пример #29
0
        echo()


@tests.command()
@click.pass_context
@name_filter_condition
@verbose_debug_quiet
def lint(context, **kwargs):
    """ Check tests against the L1 metadata specification. """
    tmt.Test._context = context
    for test in context.obj.tree.tests():
        test.lint()
        echo()


_test_templates = listed(tmt.templates.TEST, join='or')
@tests.command()
@click.pass_context
@click.argument('name')
@click.option(
    '-t', '--template', metavar='TEMPLATE',
    help='Test template ({}).'.format(_test_templates),
    prompt='Template ({})'.format(_test_templates))
@verbose_debug_quiet
@force_dry
def create(context, name, template, **kwargs):
    """ Create a new test based on given template. """
    tmt.Test._context = context
    tmt.Test.create(name, template, context.obj.tree, force)