49 @rtype list of dict |
54 @rtype list of dict |
50 """ |
55 """ |
51 return self.versions |
56 return self.versions |
52 |
57 |
53 |
58 |
|
59 class EricPlugin(): |
|
60 """ |
|
61 Class implementing a pytest plugin which reports the data in a format |
|
62 suitable for the PytestExecutor. |
|
63 """ |
|
64 def __init__(self, writer): |
|
65 """ |
|
66 Constructor |
|
67 |
|
68 @param writer reference to the object to write the results to |
|
69 @type EricJsonWriter |
|
70 """ |
|
71 self.__writer = writer |
|
72 |
|
73 self.__testsRun = 0 |
|
74 |
|
75 def __initializeReportData(self): |
|
76 """ |
|
77 Private method to initialize attributes for data collection. |
|
78 """ |
|
79 self.__status = '---' |
|
80 self.__duration = 0 |
|
81 self.__report = [] |
|
82 self.__reportPhase = "" |
|
83 self.__sections = [] |
|
84 self.__hadError = False |
|
85 self.__wasSkipped = False |
|
86 self.__wasXfail = False |
|
87 |
|
88 def pytest_report_header(self, config, startdir): |
|
89 """ |
|
90 Public method called by pytest before any reporting. |
|
91 |
|
92 @param config reference to the configuration object |
|
93 @type Config |
|
94 @param startdir starting directory |
|
95 @type LocalPath |
|
96 """ |
|
97 self.__writer.write({ |
|
98 "event": "config", |
|
99 "root": str(config.rootdir) |
|
100 }) |
|
101 |
|
102 def pytest_collectreport(self, report): |
|
103 """ |
|
104 Public method called by pytest after the tests have been collected. |
|
105 |
|
106 @param report reference to the report object |
|
107 @type CollectReport |
|
108 """ |
|
109 if report.outcome == "failed": |
|
110 self.__writer.write({ |
|
111 "event": "collecterror", |
|
112 "nodeid": report.nodeid, |
|
113 "report": str(report.longrepr), |
|
114 }) |
|
115 |
|
116 def pytest_itemcollected(self, item): |
|
117 """ |
|
118 Public malled by pytest after a test item has been collected. |
|
119 |
|
120 @param item reference to the collected test item |
|
121 @type Item |
|
122 """ |
|
123 self.__writer.write({ |
|
124 "event": "collected", |
|
125 "nodeid": item.nodeid, |
|
126 "name": item.name, |
|
127 }) |
|
128 |
|
129 def pytest_runtest_logstart(self, nodeid, location): |
|
130 """ |
|
131 Public method called by pytest before running a test. |
|
132 |
|
133 @param nodeid node id of the test item |
|
134 @type str |
|
135 @param location tuple containing the file name, the line number and |
|
136 the test name |
|
137 @type tuple of (str, int, str) |
|
138 """ |
|
139 self.__testsRun += 1 |
|
140 |
|
141 self.__writer.write({ |
|
142 "event": "starttest", |
|
143 "nodeid": nodeid, |
|
144 }) |
|
145 |
|
146 self.__initializeReportData() |
|
147 |
|
148 def pytest_runtest_logreport(self, report): |
|
149 """ |
|
150 Public method called by pytest when a test phase (setup, call and |
|
151 teardown) has been completed. |
|
152 |
|
153 @param report reference to the test report object |
|
154 @type TestReport |
|
155 """ |
|
156 if report.when == "call": |
|
157 self.__status = report.outcome |
|
158 self.__duration = report.duration |
|
159 else: |
|
160 if report.outcome == "failed": |
|
161 self.__hadError = True |
|
162 elif report.outcome == "skipped": |
|
163 self.__wasSkipped = True |
|
164 |
|
165 if hasattr(report, "wasxfail"): |
|
166 self.__wasXfail = True |
|
167 self.__report.append(report.wasxfail) |
|
168 self.__reportPhase = report.when |
|
169 |
|
170 self.__sections = report.sections |
|
171 |
|
172 if report.longrepr: |
|
173 self.__reportPhase = report.when |
|
174 if ( |
|
175 hasattr(report.longrepr, "reprcrash") and |
|
176 report.longrepr.reprcrash is not None |
|
177 ): |
|
178 self.__report.append( |
|
179 report.longrepr.reprcrash.message) |
|
180 if isinstance(report.longrepr, tuple): |
|
181 self.__report.append(report.longrepr[2]) |
|
182 elif isinstance(report.longrepr, str): |
|
183 self.__report.append(report.longrepr) |
|
184 else: |
|
185 self.__report.append(str(report.longrepr)) |
|
186 |
|
187 def pytest_runtest_logfinish(self, nodeid, location): |
|
188 """ |
|
189 Public method called by pytest after a test has been completed. |
|
190 |
|
191 @param nodeid node id of the test item |
|
192 @type str |
|
193 @param location tuple containing the file name, the line number and |
|
194 the test name |
|
195 @type tuple of (str, int, str) |
|
196 """ |
|
197 if self.__wasXfail: |
|
198 self.__status = ( |
|
199 "xpassed" |
|
200 if self.__status == "passed" else |
|
201 "xfailed" |
|
202 ) |
|
203 elif self.__wasSkipped: |
|
204 self.__status = "skipped" |
|
205 |
|
206 data = { |
|
207 "event": "result", |
|
208 "status": self.__status, |
|
209 "with_error": self.__hadError, |
|
210 "sections": self.__sections, |
|
211 "duration_s": self.__duration, |
|
212 "nodeid": nodeid, |
|
213 "filename": location[0], |
|
214 "linenumber": location[1], |
|
215 "report_phase": self.__reportPhase, |
|
216 } |
|
217 if self.__report: |
|
218 messageLines = self.__report[0].rstrip().splitlines() |
|
219 data["message"] = messageLines[0] |
|
220 data["report"] = "\n".join(self.__report) |
|
221 |
|
222 self.__writer.write(data) |
|
223 |
|
224 def pytest_sessionstart(self, session): |
|
225 """ |
|
226 Public method called by pytest before performing collection and |
|
227 entering the run test loop. |
|
228 |
|
229 @param session reference to the session object |
|
230 @type Session |
|
231 """ |
|
232 self.__totalStartTime = time.monotonic_ns() |
|
233 self.__testsRun = 0 |
|
234 |
|
235 def pytest_sessionfinish(self, session, exitstatus): |
|
236 """ |
|
237 Public method called by pytest after the whole test run finished. |
|
238 |
|
239 @param session reference to the session object |
|
240 @type Session |
|
241 @param exitstatus exit status |
|
242 @type int or ExitCode |
|
243 """ |
|
244 stopTime = time.monotonic_ns() |
|
245 duration = (stopTime - self.__totalStartTime) / 1_000_000_000 # s |
|
246 |
|
247 self.__writer.write({ |
|
248 "event": "finished", |
|
249 "duration_s": duration, |
|
250 "tests": self.__testsRun, |
|
251 }) |
|
252 |
|
253 |
54 def getVersions(): |
254 def getVersions(): |
55 """ |
255 """ |
56 Function to determine the framework version and versions of all available |
256 Function to determine the framework version and versions of all available |
57 plugins. |
257 plugins. |
58 """ |
258 """ |
59 try: |
259 try: |
60 import pytest # __IGNORE_WARNING__ |
260 import pytest |
61 versions = { |
261 versions = { |
62 "name": "pytest", |
262 "name": "pytest", |
63 "version": pytest.__version__, |
263 "version": pytest.__version__, |
64 "plugins": [], |
264 "plugins": [], |
65 } |
265 } |