1
1
# -*- coding: UTF-8 -*-
2
2
from datetime import datetime
3
+ from operator import itemgetter
4
+
3
5
import pytest
4
6
import re
5
7
import warnings
20
22
GET_TESTRUN_URL = 'get_run/{}'
21
23
GET_TESTPLAN_URL = 'get_plan/{}'
22
24
25
+ COMMENT_SIZE_LIMIT = 4000
26
+
23
27
24
28
class DeprecatedTestDecorator (DeprecationWarning ):
25
29
pass
@@ -150,44 +154,52 @@ def pytest_runtest_makereport(self, item, call):
150
154
""" Collect result and associated testcases (TestRail) of an execution """
151
155
outcome = yield
152
156
rep = outcome .get_result ()
153
- comment = ""
154
- if call .excinfo :
155
- comment = str (item .repr_failure (call .excinfo ))
156
157
if item .get_marker (TESTRAIL_PREFIX ):
157
158
testcaseids = item .get_marker (TESTRAIL_PREFIX ).kwargs .get ('ids' )
158
159
159
160
if rep .when == 'call' and testcaseids :
160
161
self .add_result (
161
162
clean_test_ids (testcaseids ),
162
163
get_test_outcome (outcome .result .outcome ),
163
- comment )
164
+ comment = rep .longrepr ,
165
+ duration = rep .duration
166
+ )
164
167
165
168
def pytest_sessionfinish (self , session , exitstatus ):
166
169
""" Publish results in TestRail """
170
+ print ('[{}] Start publishing' .format (TESTRAIL_PREFIX ))
167
171
if self .results :
172
+ tests_list = [str (result ['case_id' ]) for result in self .results ]
173
+ print ('[{}] Testcases to publish: {}' .format (TESTRAIL_PREFIX , ', ' .join (tests_list )))
168
174
169
175
if self .testrun_id :
170
176
self .add_results (self .testrun_id )
171
177
elif self .testplan_id :
172
- for testrun_id in self .get_available_testruns (self .testplan_id ):
178
+ testruns = self .get_available_testruns (self .testplan_id )
179
+ print ('[{}] Testruns to update: {}' .format (TESTRAIL_PREFIX , ', ' .join ([str (elt ) for elt in testruns ])))
180
+ for testrun_id in testruns :
173
181
self .add_results (testrun_id )
174
182
else :
175
- print ('No data published' )
183
+ print ('[{}] No data published' .format (TESTRAIL_PREFIX ))
184
+ print ('[{}] End publishing' .format (TESTRAIL_PREFIX ))
176
185
177
186
# plugin
178
187
179
- def add_result (self , test_ids , status , comment ):
188
+ def add_result (self , test_ids , status , comment = '' , duration = 0 ):
180
189
"""
181
190
Add a new result to results dict to be submitted at the end.
182
191
183
192
:param list test_ids: list of test_ids.
184
193
:param int status: status code of test (pass or fail).
194
+ :param comment: None or a failure representation.
195
+ :param duration: Time it took to run just the test.
185
196
"""
186
197
for test_id in test_ids :
187
198
data = {
188
199
'case_id' : test_id ,
189
- 'comment' : comment ,
190
200
'status_id' : status ,
201
+ 'comment' : comment ,
202
+ 'duration' : duration
191
203
}
192
204
self .results .append (data )
193
205
@@ -198,18 +210,35 @@ def add_results(self, testrun_id):
198
210
:param testrun_id: Id of the testrun to feed
199
211
200
212
"""
213
+ # Results are sorted by 'case_id' and by 'status_id' (worst result at the end)
214
+ self .results .sort (key = itemgetter ('status_id' ))
215
+ self .results .sort (key = itemgetter ('case_id' ))
216
+
217
+ # Publish results
201
218
for result in self .results :
202
219
data = {'status_id' : result ['status_id' ]}
203
220
if self .version :
204
221
data ['version' ] = self .version
222
+ comment = result .get ('comment' , '' )
223
+ if comment :
224
+ # Indent text to avoid string formatting by TestRail. Limit size of comment.
225
+ data ['comment' ] = "# Pytest result: #\n "
226
+ data ['comment' ] += 'Log truncated\n ...\n ' if len (str (comment )) > COMMENT_SIZE_LIMIT else ''
227
+ data ['comment' ] += " " + str (comment )[- COMMENT_SIZE_LIMIT :].replace ('\n ' , '\n ' )
228
+ duration = result .get ('duration' )
229
+ if duration :
230
+ duration = 1 if (duration < 1 ) else int (round (duration )) # TestRail API doesn't manage milliseconds
231
+ data ['elapsed' ] = str (duration ) + 's'
205
232
response = self .client .send_post (
206
233
ADD_RESULT_URL .format (testrun_id , result ['case_id' ]),
207
234
data ,
208
235
cert_check = self .cert_check
209
236
)
210
237
error = self .client .get_error (response )
211
238
if error :
212
- print ('Info: Testcase #{} not published for following reason: "{}"' .format (result ['case_id' ], error ))
239
+ print ('[{}] Info: Testcase #{} not published for following reason: "{}"' .format (TESTRAIL_PREFIX ,
240
+ result ['case_id' ],
241
+ error ))
213
242
214
243
def create_test_run (
215
244
self , assign_user_id , project_id , suite_id , testrun_name , tr_keys ):
@@ -233,10 +262,12 @@ def create_test_run(
233
262
)
234
263
error = self .client .get_error (response )
235
264
if error :
236
- print ('Failed to create testrun: "{}"' .format (error ))
265
+ print ('[{}] Failed to create testrun: "{}"' .format (TESTRAIL_PREFIX , error ))
237
266
else :
238
267
self .testrun_id = response ['id' ]
239
- print ('New testrun created with name "{}" and ID={}' .format (testrun_name , self .testrun_id ))
268
+ print ('[{}] New testrun created with name "{}" and ID={}' .format (TESTRAIL_PREFIX ,
269
+ testrun_name ,
270
+ self .testrun_id ))
240
271
241
272
def is_testrun_available (self ):
242
273
"""
@@ -250,10 +281,10 @@ def is_testrun_available(self):
250
281
)
251
282
error = self .client .get_error (response )
252
283
if error :
253
- print ('Failed to retrieve testrun: "{}"' .format (error ))
284
+ print ('[{}] Failed to retrieve testrun: "{}"' .format (TESTRAIL_PREFIX , error ))
254
285
return False
255
- else :
256
- return response ['is_completed' ] is False
286
+
287
+ return response ['is_completed' ] is False
257
288
258
289
def is_testplan_available (self ):
259
290
"""
@@ -267,10 +298,10 @@ def is_testplan_available(self):
267
298
)
268
299
error = self .client .get_error (response )
269
300
if error :
270
- print ('Failed to retrieve testplan: "{}"' .format (error ))
301
+ print ('[{}] Failed to retrieve testplan: "{}"' .format (TESTRAIL_PREFIX , error ))
271
302
return False
272
- else :
273
- return response ['is_completed' ] is False
303
+
304
+ return response ['is_completed' ] is False
274
305
275
306
def get_available_testruns (self , plan_id ):
276
307
"""
@@ -284,7 +315,7 @@ def get_available_testruns(self, plan_id):
284
315
)
285
316
error = self .client .get_error (response )
286
317
if error :
287
- print ('Failed to retrieve testplan: "{}"' .format (error ))
318
+ print ('[{}] Failed to retrieve testplan: "{}"' .format (TESTRAIL_PREFIX , error ))
288
319
else :
289
320
for entry in response ['entries' ]:
290
321
for run in entry ['runs' ]:
0 commit comments