1- import os
2- import multiprocessing as mp
31import argparse
2+ import multiprocessing as mp
3+ import os
44import time
5+ import subprocess
56
67from testui .support import logger
78
@@ -13,10 +14,21 @@ def parallel_testui():
1314 os .remove ('report_fails.txt' )
1415 except FileNotFoundError :
1516 pass
17+ try :
18+ os .remove ('report_cases.txt' )
19+ except FileNotFoundError :
20+ pass
21+ test_run_id = None
22+ if args .testrail_id is not None :
23+ test_run_id = args .testrail_id
24+ logger .log_info (f'Starting testrail run { test_run_id } ' )
25+ elif args .testrail is not None :
26+ test_run_id = __start_run_id (args , args .testrail )
27+ logger .log_info (f'Created testrail run { test_run_id } with testrail name: { args .testrail } ' )
1628 number_of_cases = get_total_number_of_cases (args )
17- logger .log_test_name (f'------------ Total Number of Test Cases: { number_of_cases } ---------------' )
29+ logger .log_info (f'------------ Total Number of Test Cases: { number_of_cases } ---------------' )
1830 start = time .time ()
19- __start_processes (args .markers , args )
31+ __start_processes (args .markers , args , test_run_id )
2032 end_time = time .time () - start
2133 f = open ('fails.txt' )
2234 fails = f .read ()
@@ -88,8 +100,9 @@ def get_total_number_of_cases(args):
88100 number = cases .split (' selected' )[0 ]
89101 number_of_cases += int (number )
90102 if args .single_thread_marker is not None :
91- output = subprocess .run (['pytest' , '-m' , f'{ args .single_thread_marker } { args .general_markers } ' , f'--collect-only' ],
92- stdout = subprocess .PIPE )
103+ output = subprocess .run (
104+ ['pytest' , '-m' , f'{ args .single_thread_marker } { args .general_markers } ' , f'--collect-only' ],
105+ stdout = subprocess .PIPE )
93106 response = output .stdout
94107 string_response = response .__str__ ()
95108 if string_response .__contains__ (' / ' ):
@@ -122,10 +135,22 @@ def __arg_parser():
122135 parser .add_argument ('--parallel' , type = int ,
123136 help = 'number of parallel threads' )
124137
125- parser .add_argument ('--s' , type = __str2bool , nargs = '?' ,
138+ parser .add_argument ('--s' , type = __str2bool , nargs = '?' ,
126139 const = True , default = False ,
127140 help = 'make more verbose logs (pytest -s)' )
128141
142+ parser .add_argument ('--testrail' , type = str ,
143+ help = 'Use test rail and specify name. '
144+ 'You will have to add a file testrail.cfg in root project dir' )
145+
146+ parser .add_argument ('--testrail_id' , type = str ,
147+ help = 'Use test rail and specify testrail id. '
148+ 'You will have to add a file testrail.cfg in root project dir' )
149+
150+ parser .add_argument ('--testrail_pwd' , type = str ,
151+ help = 'Use test rail and specify password. '
152+ 'You will have to add a file testrail.cfg in root project dir' )
153+
129154 parser .add_argument ('--general' , type = str ,
130155 help = 'general flags to put in all threads' )
131156
@@ -159,13 +184,13 @@ def __arg_parser():
159184 else :
160185 logger .log (f'General flags: { args .general } ' )
161186 if args .single_thread_marker is not None :
162- logger .log_test_name (f'Single Thread marker: { args .single_thread_marker } { args .general_markers } ' )
187+ logger .log_info (f'Single Thread marker: { args .single_thread_marker } { args .general_markers } ' )
163188 return args
164189
165190
166191def __str2bool (v ):
167192 if isinstance (v , bool ):
168- return v
193+ return v
169194 if v .lower () in ('yes' , 'true' , 't' , 'y' , '1' ):
170195 return True
171196 elif v .lower () in ('no' , 'false' , 'f' , 'n' , '0' ):
@@ -174,7 +199,7 @@ def __str2bool(v):
174199 raise argparse .ArgumentTypeError ('Boolean value expected.' )
175200
176201
177- def __start_processes (markers : list , args ):
202+ def __start_processes (markers : list , args , test_run_id = None ):
178203 ps = list ()
179204 amount = len (markers ) // args .parallel
180205 amount_plus = 0
@@ -193,18 +218,62 @@ def __start_processes(markers: list, args):
193218 if len (markers ) > i :
194219 tags .append (markers [i ])
195220 i += 1
196- logger .log_test_name (f'Thread { j } has markers: { tags } ' )
197- ps .append (mp .Process (target = __process , args = (tags , args , j )))
221+ logger .log_info (f'Thread { j } has markers: { tags } ' )
222+ ps .append (mp .Process (target = __process , args = (tags , args , j , test_run_id )))
198223 for p in ps :
199224 p .daemon = True
200225 p .start ()
201226 for p in ps :
202227 p .join ()
203228 if args .single_thread_marker is not None :
204- __process ([args .single_thread_marker ], args )
229+ __process ([args .single_thread_marker ], args , 0 , test_run_id )
205230
206231
207- def __process (markers : list , args , thread = 0 ):
232+ def __start_run_id (args , test_run_name ):
233+ end_marker = ''
234+ for i , marker in enumerate (args .markers ):
235+ if i == len (args .markers ):
236+ end_marker += f'{ marker } { args .general_markers } '
237+ else :
238+ end_marker += f'{ marker } { args .general_markers } or '
239+ if args .single_thread_marker is not None :
240+ end_marker += f'{ args .single_thread_marker } { args .general_markers } '
241+ with open ('testrail_id_file.txt' , 'wb' ) as out :
242+ cmd = ['pytest' , '-m' , end_marker , '--testrail' , f'--tr-config=testrail.cfg' ,
243+ f'--tr-testrun-name={ test_run_name } ' ]
244+ if args .testrail_pwd is not None :
245+ cmd .append (f'--tr-password={ args .testrail_pwd } ' )
246+ process = subprocess .Popen (cmd , stdout = out , stderr = out )
247+ i = 0
248+ while True :
249+ time .sleep (0.1 )
250+ out = open ('testrail_id_file.txt' )
251+ text = out .read ()
252+ if text .__contains__ ("New testrun created" ) or i > 50 :
253+ out .close ()
254+ process .terminate ()
255+ process .wait ()
256+ os .remove ('testrail_id_file.txt' )
257+ if text .__contains__ ('ID=' ):
258+ id_test = text .split ("ID=" )[1 ]
259+ if text .split ("ID=" )[1 ].__contains__ ('\n ' ):
260+ id_test = text .split ("ID=" )[1 ].split ("\n " )[0 ]
261+ logger .log_info (f'Test run: { id_test } ' )
262+ return id_test
263+ raise Exception ('Failed to create Test Run' )
264+ elif text .__contains__ ("Failed to create testrun" ):
265+ out .close ()
266+ process .send_signal (signal = 2 )
267+ process .terminate ()
268+ process .wait ()
269+ os .remove ('testrail_id_file.txt' )
270+ logger .log_error (f'Failed to create Test Run: \n { text } ' )
271+ raise Exception (f'Failed to create Test Run' )
272+ out .close ()
273+ i += 1
274+
275+
276+ def __process (markers : list , args , thread = 0 , test_run_id = None ):
208277 for i , marker in enumerate (markers ):
209278 try :
210279 os .remove (f'.my_cache_dir_{ thread } /v/cache/lastfailed' )
@@ -215,10 +284,15 @@ def __process(markers: list, args, thread=0):
215284 quiet = '-q'
216285 if args .s :
217286 quiet = '-s'
287+ testrail = ''
288+ if test_run_id is not None :
289+ testrail = f'--testrail --tr-config=testrail.cfg --tr-run-id={ test_run_id } '
290+ if args .testrail_pwd is not None :
291+ testrail += f' --tr-password={ args .testrail_pwd } '
218292 cache = f'-o cache_dir=.my_cache_dir_{ thread } '
219293 start_1 = time .time ()
220- logger .log (f'Starting: pytest { quiet } -m "{ marker } { args .general_markers } " { args .general } { cache } ' )
221- pr_1 = os .system (f'pytest { quiet } -m "{ marker } { args .general_markers } " { args .general } { cache } ' )
294+ logger .log (f'Starting: pytest { quiet } -m "{ marker } { args .general_markers } " { testrail } { args .general } { cache } ' )
295+ pr_1 = os .system (f'pytest { quiet } -m "{ marker } { args .general_markers } " { testrail } { args .general } { cache } ' )
222296 file = open ('fails.txt' , 'a+' )
223297 file .write (f'{ pr_1 } ' )
224298 file .close ()
0 commit comments