1
+ from unittest import mock
2
+
3
+ import pytest
4
+
5
+ from apps .github .management .commands .github_update_external_repositories import (
6
+ GITHUB_ITEMS_PER_PAGE ,
7
+ Command ,
8
+ Organization ,
9
+ Project
10
+ )
11
+
12
+ @pytest .fixture
13
+ def command ():
14
+ return Command ()
15
+
16
+ @pytest .fixture
17
+ def mock_gh_repository ():
18
+ repo = mock .Mock ()
19
+ repo .name = "test-repo"
20
+ repo .html_url = "https://github.com/TestOrg/test-repo"
21
+ return repo
22
+
23
+ @pytest .mark .parametrize (
24
+ "num_orgs, num_repos_per_org, expected_sync_calls, expected_bulk_save_calls" ,
25
+ [
26
+ (1 , [2 ], 2 , 1 ), # 1 org with 2 repos
27
+ (2 , [1 , 3 ], 4 , 2 ), # 2 orgs with 1 and 3 repos
28
+ (2 , [0 , 2 ], 2 , 1 ), # 1 org with repos, 1 without
29
+ ]
30
+ )
31
+ @mock .patch .dict ("os.environ" , {"GITHUB_TOKEN" : "valid-token" })
32
+ @mock .patch ("apps.github.management.commands.github_update_external_repositories.github.Github" )
33
+ @mock .patch ("apps.github.management.commands.github_update_external_repositories.sync_repository" )
34
+ @mock .patch ("apps.github.management.commands.github_update_external_repositories.Project.bulk_save" )
35
+ @mock .patch ("apps.github.management.commands.github_update_external_repositories.Organization.objects.filter" )
36
+ def test_handle_success (
37
+ mock_org_filter ,
38
+ mock_bulk_save ,
39
+ mock_sync_repository ,
40
+ mock_github ,
41
+ command ,
42
+ mock_gh_repository ,
43
+ num_orgs ,
44
+ num_repos_per_org ,
45
+ expected_sync_calls ,
46
+ expected_bulk_save_calls
47
+ ):
48
+ """Test command execution with varying organizations and repositories."""
49
+ mock_gh = mock_github .return_value
50
+
51
+ orgs = []
52
+ gh_orgs = []
53
+ for i in range (num_orgs ):
54
+ org = mock .Mock (spec = Organization )
55
+ org .login = f"TestOrg{ i + 1 } "
56
+ org .is_owasp_related_organization = True
57
+ orgs .append (org )
58
+
59
+ gh_org = mock .Mock ()
60
+ gh_repos = mock .MagicMock ()
61
+ gh_repos .totalCount = num_repos_per_org [i ]
62
+ gh_repos .__iter__ .return_value = [mock_gh_repository ] * num_repos_per_org [i ]
63
+ gh_org .get_repos .return_value = gh_repos
64
+ gh_orgs .append (gh_org )
65
+
66
+ qs_mock = mock .MagicMock ()
67
+ qs_mock .count .return_value = num_orgs
68
+ qs_mock .__iter__ .return_value = orgs
69
+ mock_org_filter .return_value .exclude .return_value = qs_mock
70
+
71
+ mock_gh .get_organization .side_effect = gh_orgs
72
+
73
+ mock_project = mock .Mock (spec = Project )
74
+ mock_sync_repository .side_effect = lambda gh_repo : (orgs [0 ], mock .Mock (project = mock_project ))
75
+
76
+ with mock .patch ("builtins.print" ):
77
+ command .handle ()
78
+
79
+ mock_github .assert_called_once_with ("valid-token" , per_page = GITHUB_ITEMS_PER_PAGE )
80
+
81
+ assert mock_gh .get_organization .call_count == num_orgs
82
+ for i , org in enumerate (orgs ):
83
+ mock_gh .get_organization .assert_any_call (org .login )
84
+
85
+ assert mock_sync_repository .call_count == expected_sync_calls
86
+
87
+ assert mock_bulk_save .call_count == expected_bulk_save_calls
88
+
89
+ @pytest .mark .parametrize (
90
+ "num_repos, expected_project_count" ,
91
+ [
92
+ (1 , 1 ), # 1 repo with 1 project
93
+ (3 , 3 ), # 3 repos with 3 projects
94
+ (2 , 0 ), # 2 repos without 0 projects
95
+ ]
96
+ )
97
+ @mock .patch ("apps.github.management.commands.github_update_external_repositories.sync_repository" )
98
+ def test_sync_organization_repositories (
99
+ mock_sync_repository ,
100
+ command ,
101
+ mock_gh_repository ,
102
+ num_repos ,
103
+ expected_project_count
104
+ ):
105
+ """Test repository synchronization with varying repository counts."""
106
+ mock_organization = mock .Mock (spec = Organization )
107
+ mock_organization .login = "TestOrg"
108
+
109
+ mock_repositories = mock .MagicMock ()
110
+ mock_repositories .totalCount = num_repos
111
+ mock_repositories .__iter__ .return_value = [mock_gh_repository ] * num_repos
112
+
113
+ mock_project = mock .Mock (spec = Project )
114
+ if expected_project_count > 0 :
115
+ mock_sync_repository .return_value = (mock_organization , mock .Mock (project = mock_project ))
116
+ else :
117
+ mock_sync_repository .return_value = (mock_organization , mock .Mock (project = None ))
118
+
119
+ projects = command .sync_organization_repositories (mock_organization , mock_repositories )
120
+
121
+ assert len (projects ) == expected_project_count
122
+ assert mock_sync_repository .call_count == num_repos
0 commit comments