Skip to content

Commit 112f07f

Browse files
chore: ensure reset_gitlab() succeeds
Ensure reset_gitlab() succeeds by waiting to make sure everything has been deleted as expected. If the timeout is exceeded fail the test. Not using `wait_for_sidekiq` as it didn't work. During testing I didn't see any sidekiq processes as being busy even though not everything was deleted.
1 parent d65ce36 commit 112f07f

File tree

1 file changed

+167
-9
lines changed

1 file changed

+167
-9
lines changed

tests/functional/conftest.py

Lines changed: 167 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
import dataclasses
12
import tempfile
23
import time
34
import uuid
45
from pathlib import Path
56
from subprocess import check_output
7+
from typing import Any, Dict, List
68

79
import pytest
810

@@ -30,6 +32,36 @@ def reset_gitlab(gl):
3032
if user.username != "root":
3133
user.delete(hard_delete=True)
3234

35+
sleep_interval = 0.1
36+
timeout = 60
37+
max_iterations = int(timeout / sleep_interval)
38+
39+
# Ensure everything has been reset
40+
start_time = time.perf_counter()
41+
42+
def ensure_list_empty(pg_object, description: str) -> None:
43+
for _ in range(max_iterations):
44+
if pg_object.list() == []:
45+
break
46+
time.sleep(sleep_interval)
47+
assert pg_object.list() == [], (
48+
f"Did not delete all {description}. "
49+
f"Elapsed_time: {time.perf_counter() - start_time}"
50+
)
51+
52+
ensure_list_empty(pg_object=gl.projects, description="projects")
53+
ensure_list_empty(pg_object=gl.groups, description="groups")
54+
ensure_list_empty(pg_object=gl.variables, description="variables")
55+
56+
for _ in range(max_iterations):
57+
if len(gl.users.list()) <= 1:
58+
break
59+
time.sleep(sleep_interval)
60+
assert len(gl.users.list()) <= 1, (
61+
f"Did not delete all users. "
62+
f"elapsed_time: {time.perf_counter() - start_time}"
63+
)
64+
3365

3466
def set_token(container, fixture_dir):
3567
set_token_rb = fixture_dir / "set_token.rb"
@@ -105,25 +137,59 @@ def _check(container):
105137
return _check
106138

107139

140+
@dataclasses.dataclass
141+
class WaitSidekiq:
142+
iterations: int
143+
step: float
144+
elapsed_time: float
145+
success: bool
146+
147+
108148
@pytest.fixture
109-
def wait_for_sidekiq(gl):
149+
def wait_for_sidekiq(gl: gitlab.Gitlab):
150+
"""
151+
Return a helper function to wait until there are no busy sidekiq processes.
152+
153+
Use this with asserts for slow tasks (group/project/user creation/deletion).
154+
"""
155+
return _wait_for_sidekiq(gl=gl)
156+
157+
158+
def _wait_for_sidekiq(gl: gitlab.Gitlab):
110159
"""
111160
Return a helper function to wait until there are no busy sidekiq processes.
112161
113162
Use this with asserts for slow tasks (group/project/user creation/deletion).
114163
"""
115164

116-
def _wait(timeout=30, step=0.5):
117-
for _ in range(timeout):
165+
def _wait(
166+
timeout: int = 60,
167+
step: float = 0.1,
168+
) -> WaitSidekiq:
169+
# timeout is approximately the timeout in seconds
170+
max_iterations = int(timeout / step)
171+
start_time = time.perf_counter()
172+
success = False
173+
for count in range(max_iterations):
174+
print(f"_wait: count: {count}")
118175
time.sleep(step)
119176
busy = False
120177
processes = gl.sidekiq.process_metrics()["processes"]
121178
for process in processes:
179+
print(f"_wait: process['busy']: {process['busy']}")
122180
if process["busy"]:
123181
busy = True
124182
if not busy:
125-
return True
126-
return False
183+
success = True
184+
break
185+
result = WaitSidekiq(
186+
iterations=count,
187+
step=step,
188+
elapsed_time=time.perf_counter() - start_time,
189+
success=success,
190+
)
191+
print(f"_wait: {result}")
192+
return result
127193

128194
return _wait
129195

@@ -194,6 +260,73 @@ def gitlab_runner(gl):
194260
check_output(docker_exec + unregister).decode()
195261

196262

263+
@pytest.fixture
264+
def ensure_raises_exception():
265+
"""
266+
Return a helper function to wait until specified exception is raised
267+
268+
Use this with asserts for slow tasks (group/project/user creation/deletion).
269+
"""
270+
return _ensure_raises_exception_wrapped()
271+
272+
273+
def _ensure_raises_exception(
274+
*,
275+
func,
276+
exception: Exception,
277+
args: List[Any],
278+
kwargs: Dict[str, Any],
279+
description: str,
280+
) -> None:
281+
"""Ensure the exception is specified when calling `func`. If no exception is raided
282+
after timeout period, fail the test"""
283+
sleep_interval = 0.1
284+
timeout = 60
285+
max_iterations = int(timeout / sleep_interval)
286+
287+
for _ in range(max_iterations):
288+
try:
289+
func(*args, **kwargs)
290+
except exception:
291+
return
292+
time.sleep(sleep_interval)
293+
pytest.fail(f"{description} did not raise exception {exception}")
294+
295+
296+
def _ensure_raises_exception_wrapped():
297+
return _ensure_raises_exception
298+
299+
300+
@pytest.fixture
301+
def ensure_deleted():
302+
"""
303+
Return a helper function to wait until specified object is deleted
304+
305+
Use this with asserts for slow tasks (group/project/user creation/deletion).
306+
"""
307+
return _ensure_deleted_wrapped()
308+
309+
310+
def _ensure_deleted(*, pg_object, object_id: int, description: str) -> None:
311+
"""Ensure the object specified can not be retrieved. If object still exists after
312+
timeout period, fail the test"""
313+
sleep_interval = 0.1
314+
timeout = 60
315+
max_iterations = int(timeout / sleep_interval)
316+
317+
for _ in range(max_iterations):
318+
try:
319+
pg_object.get(object_id)
320+
except gitlab.exceptions.GitlabGetError:
321+
return
322+
time.sleep(sleep_interval)
323+
pytest.fail(f"{description} {object_id} was not deleted")
324+
325+
326+
def _ensure_deleted_wrapped():
327+
return _ensure_deleted
328+
329+
197330
@pytest.fixture(scope="module")
198331
def group(gl):
199332
"""Group fixture for group API resource tests."""
@@ -203,6 +336,7 @@ def group(gl):
203336
"path": f"group-{_id}",
204337
}
205338
group = gl.groups.create(data)
339+
group_id = group.id
206340

207341
yield group
208342

@@ -211,6 +345,8 @@ def group(gl):
211345
except gitlab.exceptions.GitlabDeleteError as e:
212346
print(f"Group already deleted: {e}")
213347

348+
_ensure_deleted(pg_object=gl.groups, object_id=group_id, description="Group")
349+
214350

215351
@pytest.fixture(scope="module")
216352
def project(gl):
@@ -219,6 +355,7 @@ def project(gl):
219355
name = f"test-project-{_id}"
220356

221357
project = gl.projects.create(name=name)
358+
project_id = project.id
222359

223360
yield project
224361

@@ -227,6 +364,8 @@ def project(gl):
227364
except gitlab.exceptions.GitlabDeleteError as e:
228365
print(f"Project already deleted: {e}")
229366

367+
_ensure_deleted(pg_object=gl.projects, object_id=project_id, description="Project")
368+
230369

231370
@pytest.fixture(scope="function")
232371
def merge_request(project, wait_for_sidekiq):
@@ -249,8 +388,10 @@ def _merge_request(*, source_branch: str):
249388
# NOTE(jlvillal): Sometimes the CI would give a "500 Internal Server
250389
# Error". Hoping that waiting until all other processes are done will
251390
# help with that.
252-
result = wait_for_sidekiq(timeout=60)
253-
assert result is True, "sidekiq process should have terminated but did not"
391+
result = wait_for_sidekiq()
392+
assert (
393+
result.success is True
394+
), f"sidekiq process should have terminated but did not: {result}"
254395

255396
project.refresh() # Gets us the current default branch
256397
project.branches.create(
@@ -274,8 +415,10 @@ def _merge_request(*, source_branch: str):
274415
"remove_source_branch": True,
275416
}
276417
)
277-
result = wait_for_sidekiq(timeout=60)
278-
assert result is True, "sidekiq process should have terminated but did not"
418+
result = wait_for_sidekiq()
419+
assert (
420+
result.success is True
421+
), f"sidekiq process should have terminated but did not: {result}"
279422

280423
mr_iid = mr.iid
281424
for _ in range(60):
@@ -298,6 +441,18 @@ def _merge_request(*, source_branch: str):
298441
# Ignore if branch was already deleted
299442
pass
300443

444+
for mr_iid, source_branch in to_delete:
445+
_ensure_deleted(
446+
pg_object=project.mergerequests,
447+
object_id=mr_iid,
448+
description="Project mergerequest",
449+
)
450+
_ensure_deleted(
451+
pg_object=project.branches,
452+
object_id=source_branch,
453+
description="Project branch",
454+
)
455+
301456

302457
@pytest.fixture(scope="module")
303458
def project_file(project):
@@ -342,6 +497,7 @@ def user(gl):
342497
password = "fakepassword"
343498

344499
user = gl.users.create(email=email, username=username, name=name, password=password)
500+
user_id = user.id
345501

346502
yield user
347503

@@ -350,6 +506,8 @@ def user(gl):
350506
except gitlab.exceptions.GitlabDeleteError as e:
351507
print(f"User already deleted: {e}")
352508

509+
_ensure_deleted(pg_object=gl.users, object_id=user_id, description="User")
510+
353511

354512
@pytest.fixture(scope="module")
355513
def issue(project):

0 commit comments

Comments
 (0)