Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit cda90f0

Browse files
chore: make reset_gitlab() better
Saw issues in the CI where reset_gitlab() would fail. It would fail to delete the group that is created when GitLab starts up. Extending the timeout didn't fix the issue. Changed the code so now it will check if the item is deleted and if it isn't it will call the delete() method again to ensure that GitLab knows it should be deleted. Since making this change I have not been able to reproduce the failure in reset_gitlab(). Also added some logging functionality that can be seen if logging is turned on in pytest.
1 parent f26bf7d commit cda90f0

File tree

2 files changed

+91
-11
lines changed

2 files changed

+91
-11
lines changed

pyproject.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,10 @@ disable = [
8787
"useless-object-inheritance",
8888

8989
]
90+
91+
[tool.pytest.ini_options]
92+
log_cli = true
93+
log_cli_level = "INFO"
94+
log_cli_format = "%(asctime)s.%(msecs)03d [%(levelname)8s] (%(filename)s:%(funcName)s:L%(lineno)s) %(message)s"
95+
log_cli_date_format = "%Y-%m-%d %H:%M:%S"
96+
addopts = "--color=yes"

tests/functional/conftest.py

Lines changed: 84 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import logging
12
import tempfile
23
import time
34
import uuid
@@ -10,58 +11,124 @@
1011
import gitlab.base
1112

1213
SLEEP_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")
1718
def fixture_dir(test_dir):
1819
return test_dir / "functional" / "fixtures"
1920

2021

21-
def reset_gitlab(gl):
22-
# previously tools/reset_gitlab.py
22+
def reset_gitlab(gl: gitlab.Gitlab) -> None:
23+
# Mark our resources for deletion. It takes time for them to actually be deleted
24+
# though.
25+
_reset_gitlab_delete_resources(gl=gl)
26+
27+
# Wait for all resources to be deleted
28+
_reset_gitlab_wait_deletion_finish(gl=gl)
29+
30+
31+
def _reset_gitlab_delete_resources(gl: gitlab.Gitlab) -> None:
32+
"""Mark for deletion, resources (such as projects, groups, users) that shouldn't
33+
exist. Once marked they will still take time to be deleted."""
2334
for project in gl.projects.list():
35+
logging.info(f"Mark for deletion project: {project.name!r}")
2436
for deploy_token in project.deploytokens.list():
37+
logging.info(
38+
f"Mark for deletion token: {deploy_token.name!r} in "
39+
f"project: {project.name!r}"
40+
)
2541
deploy_token.delete()
2642
project.delete()
2743
for group in gl.groups.list():
44+
logging.info(f"Mark for deletion group: {group.name!r}")
2845
for deploy_token in group.deploytokens.list():
46+
logging.info(
47+
f"Mark for deletion token: {deploy_token.name!r} in "
48+
f"group: {group.name!r}"
49+
)
2950
deploy_token.delete()
3051
group.delete()
3152
for variable in gl.variables.list():
53+
logging.info(f"Mark for deletion variable: {variable.name!r}")
3254
variable.delete()
3355
for user in gl.users.list():
3456
if user.username != "root":
57+
logging.info(f"Mark for deletion user: {user.username!r}")
3558
user.delete(hard_delete=True)
3659

60+
61+
def _reset_gitlab_wait_deletion_finish(gl: gitlab.Gitlab) -> None:
62+
"""Wait for all of our resources to be deleted.
63+
64+
If anything exists then mark it again for deletion in case initial call to delete
65+
didn't work, which has been seen :("""
66+
3767
max_iterations = int(TIMEOUT / SLEEP_INTERVAL)
3868

3969
# Ensure everything has been reset
4070
start_time = time.perf_counter()
4171

4272
def wait_for_maximum_list_length(
43-
rest_manager: gitlab.base.RESTManager, description: str, max_length: int = 0
73+
rest_manager: gitlab.base.RESTManager,
74+
description: str,
75+
max_length: int = 0,
76+
should_delete_func=lambda x: True,
77+
delete_kwargs={},
4478
) -> None:
4579
"""Wait for the list() length to be no greater than expected maximum or fail
4680
test if timeout is exceeded"""
47-
for _ in range(max_iterations):
48-
if len(rest_manager.list()) <= max_length:
81+
for count in range(max_iterations):
82+
items = rest_manager.list()
83+
logging.info(
84+
f"Iteration: {count}: items in {description}: {[x.name for x in items]}"
85+
)
86+
for item in items:
87+
if should_delete_func(item):
88+
logging.info(
89+
f"Marking again for deletion {description}: {item.name!r}"
90+
)
91+
try:
92+
item.delete(**delete_kwargs)
93+
except gitlab.exceptions.GitlabDeleteError as exc:
94+
logging.info(
95+
f"Already marked for deletion: {item.name!r} {exc}"
96+
)
97+
if len(items) <= max_length:
4998
break
5099
time.sleep(SLEEP_INTERVAL)
51-
assert len(rest_manager.list()) <= max_length, (
100+
items = rest_manager.list()
101+
elapsed_time = time.perf_counter() - start_time
102+
if len(items) > max_length:
103+
logging.error(
104+
f"Too many items still remaining and timeout exceeded: {elapsed_time}"
105+
)
106+
assert len(items) <= max_length, (
52107
f"Did not delete required items for {description}. "
53-
f"Elapsed_time: {time.perf_counter() - start_time}"
108+
f"Elapsed_time: {elapsed_time}\n"
109+
f"items: {[str(x) for x in items]!r}"
54110
)
55111

56112
wait_for_maximum_list_length(rest_manager=gl.projects, description="projects")
57113
wait_for_maximum_list_length(rest_manager=gl.groups, description="groups")
58114
wait_for_maximum_list_length(rest_manager=gl.variables, description="variables")
115+
116+
def should_delete_user(user):
117+
if user.username == "root":
118+
return False
119+
return True
120+
59121
wait_for_maximum_list_length(
60-
rest_manager=gl.users, description="users", max_length=1
122+
rest_manager=gl.users,
123+
description="users",
124+
max_length=1,
125+
should_delete_func=should_delete_user,
126+
delete_kwargs={"hard_delete": True},
61127
)
62128

63129

64130
def set_token(container, fixture_dir):
131+
logging.info("Creating API token.")
65132
set_token_rb = fixture_dir / "set_token.rb"
66133

67134
with open(set_token_rb, "r") as f:
@@ -76,6 +143,7 @@ def set_token(container, fixture_dir):
76143
set_token_command,
77144
]
78145
output = check_output(rails_command).decode().strip()
146+
logging.info("Finished creating API token.")
79147

80148
return output
81149

@@ -144,7 +212,7 @@ def wait_for_sidekiq(gl):
144212
"""
145213

146214
def _wait(timeout=30, step=0.5):
147-
for _ in range(timeout):
215+
for count in range(timeout):
148216
time.sleep(step)
149217
busy = False
150218
processes = gl.sidekiq.process_metrics()["processes"]
@@ -153,6 +221,7 @@ def _wait(timeout=30, step=0.5):
153221
busy = True
154222
if not busy:
155223
return True
224+
logging.info(f"sidekiq busy {count} of {timeout}")
156225
return False
157226

158227
return _wait
@@ -163,9 +232,11 @@ def gitlab_config(check_is_alive, docker_ip, docker_services, temp_dir, fixture_
163232
config_file = temp_dir / "python-gitlab.cfg"
164233
port = docker_services.port_for("gitlab", 80)
165234

235+
logging.info("Waiting for GitLab container to become ready.")
166236
docker_services.wait_until_responsive(
167237
timeout=200, pause=5, check=lambda: check_is_alive("gitlab-test")
168238
)
239+
logging.info("GitLab container is now ready.")
169240

170241
token = set_token("gitlab-test", fixture_dir=fixture_dir)
171242

@@ -188,8 +259,10 @@ def gitlab_config(check_is_alive, docker_ip, docker_services, temp_dir, fixture_
188259
def gl(gitlab_config):
189260
"""Helper instance to make fixtures and asserts directly via the API."""
190261

262+
logging.info("Create python-gitlab gitlab.Gitlab object")
191263
instance = gitlab.Gitlab.from_config("local", [gitlab_config])
192-
reset_gitlab(instance)
264+
265+
reset_gitlab(gl=instance)
193266

194267
return instance
195268

0 commit comments

Comments
 (0)