summaryrefslogtreecommitdiff
path: root/python/helpers/pycharm/lettuce_runner.py
blob: 6aaa566df719f6c8cd1e731ab0f4f8b673e0eecc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# coding=utf-8
"""
BDD lettuce framework runner
"""
__author__ = 'Ilya.Kazakevich'
import os
from lettuce.exceptions import ReasonToFail
import time
import sys
import tcmessages
import lettuce
from lettuce import core


# Error message about unsupported outlines
_NO_OUTLINE_ERROR = "Outline scenarios are not supported due to https://github.com/gabrielfalcao/lettuce/issues/451"


class LettuceRunner(object):
    """
    TODO: Runs lettuce
    """

    def __init__(self, base_dir):
        """
        :param base_dir base directory to run tests in
        :type base_dir: str

        """
        self.base_dir = base_dir
        self.runner = lettuce.Runner(base_dir)
        self.messages = tcmessages.TeamcityServiceMessages()
        self.test_start_time = None

    def report_tests(self):
        """
        :returns : number of tests
        :rtype : int
        """
        result = 0
        for feature_file in self.runner.loader.find_feature_files():
            feature = core.Feature.from_file(feature_file)
            for scenario in feature.scenarios:
                assert isinstance(scenario, core.Scenario), scenario
                if not scenario.outlines:
                    result += len(scenario.steps)
        self.messages.testCount(result)

    def report_scenario_started(self, scenario):
        """
        Reports scenario launched
        :type scenario core.Scenario
        :param scenario: scenario
        """
        if scenario.outlines:
            self.messages.testIgnored(scenario.name,
                                      _NO_OUTLINE_ERROR)
            scenario.steps = []  # Clear to prevent running. TODO: Fix when this issue fixed
            scenario.background = None  # TODO: undocumented
            return
        self.report_suite(True, scenario.name, scenario.described_at)

    def report_suite(self, is_start, name, described_at):
        """
        Reports some suite (scenario, feature, background etc) is started or stopped
        :param is_start: started or not
        :param name: suite name
        :param described_at: where it is described (file, line)
        :return:
        """
        if is_start:
            self.messages.testSuiteStarted(name, self._gen_location(described_at))
        else:
            self.messages.testSuiteFinished(name)

    def report_step(self, is_start, step):
        """
        Reports step start / stop
        :param is_start: true if step started
        :type step core.Step
        :param step: step
        """
        test_name = step.sentence
        if is_start:
            self.test_start_time = time.time()
            self.messages.testStarted(test_name, self._gen_location(step.described_at))
        elif step.passed:
            duration = 0
            if self.test_start_time:
                duration = long(time.time() - self.test_start_time)
            self.messages.testFinished(test_name, duration=duration)
            self.test_start_time = None
        elif step.failed:
            reason = step.why
            assert isinstance(reason, ReasonToFail), reason
            self.messages.testFailed(test_name, message=reason.exception, details=reason.traceback)

    def _gen_location(self, description):
        """
        :param description: "described_at" (file, line)
        :return: location in format file:line by "described_at"
        """
        return "file:///{}/{}:{}".format(self.base_dir, description.file, description.line)

    def run(self):
        """
        Launches runner
        """
        self.report_tests()
        self.messages.testMatrixEntered()

        lettuce.before.each_feature(lambda f: self.report_suite(True, f.name, f.described_at))
        lettuce.after.each_feature(lambda f: self.report_suite(False, f.name, f.described_at))

        lettuce.before.each_scenario(lambda s: self.report_scenario_started(s))
        lettuce.after.each_scenario(lambda s: self.report_suite(False, s.name, s.described_at))

        lettuce.before.each_background(
            lambda b, *args: self.report_suite(True, "Scenario background", b.feature.described_at))
        lettuce.after.each_background(
            lambda b, *args: self.report_suite(False, "Scenario background", b.feature.described_at))

        lettuce.before.each_step(lambda s: self.report_step(True, s))
        lettuce.after.each_step(lambda s: self.report_step(False, s))

        self.runner.run()


if __name__ == "__main__":
    path = sys.argv[1] if len(sys.argv) > 1 else "."
    assert os.path.exists(path), "{} does not exist".format(path)
    LettuceRunner(path).run()