blob: 6aaa566df719f6c8cd1e731ab0f4f8b673e0eecc [file] [log] [blame]
Tor Norbye2e5965e2014-07-25 12:24:15 -07001# coding=utf-8
2"""
3BDD lettuce framework runner
4"""
5__author__ = 'Ilya.Kazakevich'
6import os
7from lettuce.exceptions import ReasonToFail
8import time
9import sys
10import tcmessages
11import lettuce
12from lettuce import core
13
14
15# Error message about unsupported outlines
16_NO_OUTLINE_ERROR = "Outline scenarios are not supported due to https://github.com/gabrielfalcao/lettuce/issues/451"
17
18
19class LettuceRunner(object):
20 """
21 TODO: Runs lettuce
22 """
23
24 def __init__(self, base_dir):
25 """
26 :param base_dir base directory to run tests in
27 :type base_dir: str
28
29 """
30 self.base_dir = base_dir
31 self.runner = lettuce.Runner(base_dir)
32 self.messages = tcmessages.TeamcityServiceMessages()
33 self.test_start_time = None
34
35 def report_tests(self):
36 """
37 :returns : number of tests
38 :rtype : int
39 """
40 result = 0
41 for feature_file in self.runner.loader.find_feature_files():
42 feature = core.Feature.from_file(feature_file)
43 for scenario in feature.scenarios:
44 assert isinstance(scenario, core.Scenario), scenario
45 if not scenario.outlines:
46 result += len(scenario.steps)
47 self.messages.testCount(result)
48
49 def report_scenario_started(self, scenario):
50 """
51 Reports scenario launched
52 :type scenario core.Scenario
53 :param scenario: scenario
54 """
55 if scenario.outlines:
56 self.messages.testIgnored(scenario.name,
57 _NO_OUTLINE_ERROR)
58 scenario.steps = [] # Clear to prevent running. TODO: Fix when this issue fixed
59 scenario.background = None # TODO: undocumented
60 return
61 self.report_suite(True, scenario.name, scenario.described_at)
62
63 def report_suite(self, is_start, name, described_at):
64 """
65 Reports some suite (scenario, feature, background etc) is started or stopped
66 :param is_start: started or not
67 :param name: suite name
68 :param described_at: where it is described (file, line)
69 :return:
70 """
71 if is_start:
72 self.messages.testSuiteStarted(name, self._gen_location(described_at))
73 else:
74 self.messages.testSuiteFinished(name)
75
76 def report_step(self, is_start, step):
77 """
78 Reports step start / stop
79 :param is_start: true if step started
80 :type step core.Step
81 :param step: step
82 """
83 test_name = step.sentence
84 if is_start:
85 self.test_start_time = time.time()
86 self.messages.testStarted(test_name, self._gen_location(step.described_at))
87 elif step.passed:
88 duration = 0
89 if self.test_start_time:
90 duration = long(time.time() - self.test_start_time)
91 self.messages.testFinished(test_name, duration=duration)
92 self.test_start_time = None
93 elif step.failed:
94 reason = step.why
95 assert isinstance(reason, ReasonToFail), reason
96 self.messages.testFailed(test_name, message=reason.exception, details=reason.traceback)
97
98 def _gen_location(self, description):
99 """
100 :param description: "described_at" (file, line)
101 :return: location in format file:line by "described_at"
102 """
103 return "file:///{}/{}:{}".format(self.base_dir, description.file, description.line)
104
105 def run(self):
106 """
107 Launches runner
108 """
109 self.report_tests()
110 self.messages.testMatrixEntered()
111
112 lettuce.before.each_feature(lambda f: self.report_suite(True, f.name, f.described_at))
113 lettuce.after.each_feature(lambda f: self.report_suite(False, f.name, f.described_at))
114
115 lettuce.before.each_scenario(lambda s: self.report_scenario_started(s))
116 lettuce.after.each_scenario(lambda s: self.report_suite(False, s.name, s.described_at))
117
118 lettuce.before.each_background(
119 lambda b, *args: self.report_suite(True, "Scenario background", b.feature.described_at))
120 lettuce.after.each_background(
121 lambda b, *args: self.report_suite(False, "Scenario background", b.feature.described_at))
122
123 lettuce.before.each_step(lambda s: self.report_step(True, s))
124 lettuce.after.each_step(lambda s: self.report_step(False, s))
125
126 self.runner.run()
127
128
129if __name__ == "__main__":
130 path = sys.argv[1] if len(sys.argv) > 1 else "."
131 assert os.path.exists(path), "{} does not exist".format(path)
132 LettuceRunner(path).run()