Skip to content

Commit f6c7cdd

Browse files
feat: error scenario test cases, refactor: consistent hashing
1 parent 3bc2b2d commit f6c7cdd

File tree

1 file changed

+58
-2
lines changed

1 file changed

+58
-2
lines changed

backend/tests/apps/github/management/commands/github_update_external_repositories_test.py

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from unittest import mock
33

44
import pytest
5+
from github.GithubException import BadCredentialsException
56

67
from apps.github.management.commands.github_update_external_repositories import (
78
Command,
@@ -119,12 +120,13 @@ def test_handle(self, scenario):
119120
mock_project = mock.Mock(spec=Project)
120121

121122
def sync_side_effect(repo):
122-
idx = hash(repo.name) % len(orgs) if orgs else 0
123+
# Use deterministic mapping based on repo name
124+
idx = sum(ord(c) for c in repo.name) % len(orgs) if orgs else 0
123125
return (orgs[idx], mock.Mock(project=mock_project))
124126

125127
self.mock_sync_repository.side_effect = sync_side_effect
126128

127-
with mock.patch("builtins.print"):
129+
with mock.patch("builtins.print"): # Suppress command output during testing
128130
self.command.handle()
129131

130132
assert self.mock_gh.get_organization.call_count == scenario.num_orgs
@@ -165,3 +167,57 @@ def test_sync_organization_repositories(
165167

166168
assert len(projects) == expected_project_count
167169
assert mock_sync_repository.call_count == num_repos
170+
171+
172+
@pytest.mark.parametrize(
173+
("side_effects", "expected_project_count"),
174+
[
175+
# First repo fails with error, second succeeds with project
176+
(
177+
[
178+
Exception("GitHub API error"),
179+
(mock.Mock(spec=Organization), mock.Mock(project=mock.Mock(spec=Project))),
180+
],
181+
1,
182+
),
183+
# First repo fails with network error, second succeeds with project
184+
(
185+
[
186+
ConnectionError("Network timeout"),
187+
(mock.Mock(spec=Organization), mock.Mock(project=mock.Mock(spec=Project))),
188+
],
189+
1,
190+
),
191+
# Credential error should return None immediately
192+
(BadCredentialsException(401), None),
193+
],
194+
)
195+
@mock.patch("apps.github.management.commands.github_update_external_repositories.sync_repository")
196+
def test_sync_organization_repositories_error_handling(
197+
mock_sync_repository, command, mock_gh_repository, side_effects, expected_project_count
198+
):
199+
"""Test repository synchronization error handling."""
200+
mock_organization = mock.Mock(spec=Organization)
201+
mock_organization.login = "TestOrg"
202+
203+
mock_repositories = mock.MagicMock()
204+
mock_repositories.totalCount = 2 # Try to sync 2 repositories
205+
mock_repositories.__iter__.return_value = [mock_gh_repository] * 2
206+
207+
mock_sync_repository.side_effect = side_effects
208+
209+
with mock.patch("builtins.print"): # Suppress command output during testing
210+
projects = command.sync_organization_repositories(mock_organization, mock_repositories)
211+
212+
if isinstance(side_effects, BadCredentialsException):
213+
assert projects is None
214+
assert mock_sync_repository.call_count == 1
215+
else:
216+
assert (
217+
len(projects) == expected_project_count
218+
) # Should get 1 project from second successful repo
219+
assert mock_sync_repository.call_count == 2 # Should try both repos
220+
# For successful cases, verify repository was added to project
221+
if projects:
222+
assert len(projects) == 1
223+
projects[0].repositories.add.assert_called_once()

0 commit comments

Comments
 (0)