1+ import logging
12import tempfile
23import time
34import uuid
1011import gitlab .base
1112
1213SLEEP_INTERVAL = 0.1
13- TIMEOUT = 60 # seconds before timeout will occur
14+ TIMEOUT = 3 * 60 # seconds before timeout will occur
1415
1516
1617@pytest .fixture (scope = "session" )
1718def fixture_dir (test_dir ):
1819 return test_dir / "functional" / "fixtures"
1920
2021
21- def reset_gitlab (gl ):
22- # previously tools/reset_gitlab.py
23- for project in gl .projects .list ():
24- for deploy_token in project .deploytokens .list ():
25- deploy_token .delete ()
26- project .delete ()
27- for group in gl .groups .list ():
28- for deploy_token in group .deploytokens .list ():
29- deploy_token .delete ()
30- group .delete ()
31- for variable in gl .variables .list ():
32- variable .delete ()
33- for user in gl .users .list ():
34- if user .username != "root" :
35- user .delete (hard_delete = True )
36-
37- max_iterations = int (TIMEOUT / SLEEP_INTERVAL )
38-
39- # Ensure everything has been reset
40- start_time = time .perf_counter ()
41-
42- def wait_for_maximum_list_length (
43- rest_manager : gitlab .base .RESTManager , description : str , max_length : int = 0
44- ) -> None :
45- """Wait for the list() length to be no greater than expected maximum or fail
46- test if timeout is exceeded"""
47- for _ in range (max_iterations ):
48- if len (rest_manager .list ()) <= max_length :
49- break
50- time .sleep (SLEEP_INTERVAL )
51- assert len (rest_manager .list ()) <= max_length , (
52- f"Did not delete required items for { description } . "
53- f"Elapsed_time: { time .perf_counter () - start_time } "
54- )
55-
56- wait_for_maximum_list_length (rest_manager = gl .projects , description = "projects" )
57- wait_for_maximum_list_length (rest_manager = gl .groups , description = "groups" )
58- wait_for_maximum_list_length (rest_manager = gl .variables , description = "variables" )
59- wait_for_maximum_list_length (
60- rest_manager = gl .users , description = "users" , max_length = 1
61- )
62-
63-
6422def set_token (container , fixture_dir ):
6523 set_token_rb = fixture_dir / "set_token.rb"
6624
@@ -163,9 +121,11 @@ def gitlab_config(check_is_alive, docker_ip, docker_services, temp_dir, fixture_
163121 config_file = temp_dir / "python-gitlab.cfg"
164122 port = docker_services .port_for ("gitlab" , 80 )
165123
124+ logging .info ("Waiting for GitLab container to come up..." )
166125 docker_services .wait_until_responsive (
167- timeout = 200 , pause = 5 , check = lambda : check_is_alive ("gitlab-test" )
126+ timeout = 300 , pause = 5 , check = lambda : check_is_alive ("gitlab-test" )
168127 )
128+ logging .info ("GitLab container is now up" )
169129
170130 token = set_token ("gitlab-test" , fixture_dir = fixture_dir )
171131
@@ -188,12 +148,136 @@ def gitlab_config(check_is_alive, docker_ip, docker_services, temp_dir, fixture_
188148def gl (gitlab_config ):
189149 """Helper instance to make fixtures and asserts directly via the API."""
190150
151+ logging .info ("Create python-gitlab gitlab.Gitlab object" )
191152 instance = gitlab .Gitlab .from_config ("local" , [gitlab_config ])
192- reset_gitlab (instance )
153+
154+ # wait for any running busy sidekiq processes to complete
155+ for count in range (TIMEOUT ):
156+ time .sleep (SLEEP_INTERVAL )
157+ busy = False
158+ processes = instance .sidekiq .process_metrics ()["processes" ]
159+ for process in processes :
160+ if process ["busy" ]:
161+ logging .info (f"sidekiq: count: { count } process_busy: { process ['busy' ]} " )
162+ busy = True
163+ if not busy :
164+ logging .info (f"sidekiq idle check completed after { count } iterations" )
165+ break
166+
167+ if is_gitlab_ee (instance ):
168+ logging .info ("GitLab EE detected" )
169+ # NOTE(jlvillal): By default in GitLab EE it will wait 7 days before
170+ # deleting a group. Change it to 0 days.
171+ settings = instance .settings .get ()
172+ if settings .deletion_adjourned_period != 0 :
173+ settings .deletion_adjourned_period = 0
174+ settings .save ()
175+ # Clean up any extraneous resources which may exist
176+ for project in instance .projects .list ():
177+ logging .info (f"Mark for deletion project: { project .name !r} " )
178+ for deploy_token in project .deploytokens .list ():
179+ logging .info (
180+ f"Mark for deletion token: { deploy_token .name !r} in "
181+ f"project: { project .name !r} "
182+ )
183+ deploy_token .delete ()
184+ project .delete ()
185+ for group in instance .groups .list ():
186+ logging .info (f"Mark for deletion group: { group .name !r} " )
187+ for deploy_token in group .deploytokens .list ():
188+ logging .info (
189+ f"Mark for deletion token: { deploy_token .name !r} in "
190+ f"group: { group .name !r} "
191+ )
192+ deploy_token .delete ()
193+ group .delete ()
194+ for variable in instance .variables .list ():
195+ logging .info (f"Mark for deletion variable: { variable .name !r} " )
196+ variable .delete ()
197+ for user in instance .users .list ():
198+ if user .username != "root" :
199+ logging .info (f"Mark for deletion user: { user .username !r} " )
200+ user .delete (hard_delete = True )
201+
202+ timeout = TIMEOUT
203+ sleep_interval = 0.5
204+ max_iterations = int (timeout / sleep_interval )
205+
206+ # Ensure everything has been reset
207+ start_time = time .perf_counter ()
208+
209+ def wait_for_maximum_list_length (
210+ rest_manager : gitlab .base .RESTManager ,
211+ description : str ,
212+ max_length : int = 0 ,
213+ should_delete_func = lambda x : True ,
214+ ) -> None :
215+ """Wait for the list() length to be no greater than expected maximum or fail
216+ test if timeout is exceeded"""
217+ for count in range (max_iterations ):
218+ items = rest_manager .list ()
219+ logging .info (
220+ f"Iteration: { count } : items in { description } : { [x .name for x in items ]} "
221+ )
222+ for item in items :
223+ if should_delete_func (item ):
224+ logging .info (
225+ f"Marking again for deletion { description } : { item .name !r} "
226+ )
227+ try :
228+ item .delete ()
229+ except gitlab .exceptions .GitlabDeleteError as exc :
230+ logging .info (
231+ f"Already marked for deletion: { item .name !r} { exc } "
232+ )
233+ if len (items ) <= max_length :
234+ break
235+ time .sleep (sleep_interval )
236+ items = rest_manager .list ()
237+ elapsed_time = time .perf_counter () - start_time
238+ if len (items ) > max_length :
239+ logging .error (
240+ f"Too many items still remaining and timeout exceeded: { elapsed_time } "
241+ )
242+ assert len (items ) <= max_length , (
243+ f"Did not delete required items for { description } . "
244+ f"Elapsed_time: { time .perf_counter () - start_time } \n "
245+ f"items: { [str (x ) for x in items ]!r} "
246+ )
247+
248+ wait_for_maximum_list_length (rest_manager = instance .projects , description = "projects" )
249+ wait_for_maximum_list_length (rest_manager = instance .groups , description = "groups" )
250+ wait_for_maximum_list_length (
251+ rest_manager = instance .variables , description = "variables"
252+ )
253+
254+ def should_delete_user (user ):
255+ if user .username == "root" :
256+ return False
257+ return True
258+
259+ wait_for_maximum_list_length (
260+ rest_manager = instance .users ,
261+ description = "users" ,
262+ max_length = 1 ,
263+ should_delete_func = should_delete_user ,
264+ )
193265
194266 return instance
195267
196268
269+ def is_gitlab_ee (gl : gitlab .Gitlab ) -> bool :
270+ """Determine if we are running with GitLab EE as opposed to GitLab CE"""
271+ try :
272+ license = gl .get_license ()
273+ except gitlab .exceptions .GitlabLicenseError :
274+ license = None
275+ # If we have a license then we assume we are running on GitLab EE
276+ if license :
277+ return True
278+ return False
279+
280+
197281@pytest .fixture (scope = "session" )
198282def gitlab_runner (gl ):
199283 container = "gitlab-runner-test"
0 commit comments