Skip to content

Commit d36198d

Browse files
Refactor check_repo_exists to use git ls-remote with authentication support
Co-authored-by: nicoragne <nicoragne@hotmail.fr>
1 parent 7c31ee8 commit d36198d

File tree

1 file changed

+53
-18
lines changed

1 file changed

+53
-18
lines changed

tests/test_clone.py

Lines changed: 53 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -99,24 +99,30 @@ async def test_clone_nonexistent_repository(repo_exists_true: AsyncMock) -> None
9999

100100
@pytest.mark.asyncio
101101
@pytest.mark.parametrize(
102-
("status_code", "expected"),
102+
("returncode", "expected"),
103103
[
104-
(HTTP_200_OK, True),
105-
(HTTP_401_UNAUTHORIZED, False),
106-
(HTTP_403_FORBIDDEN, False),
107-
(HTTP_404_NOT_FOUND, False),
104+
(0, True), # Repository exists and is accessible
105+
(2, False), # Repository doesn't exist or is not accessible
106+
(128, False), # Git error (e.g., authentication failure)
108107
],
109108
)
110-
async def test_check_repo_exists(status_code: int, *, expected: bool, mocker: MockerFixture) -> None:
111-
"""Verify that ``check_repo_exists`` interprets httpx results correctly."""
112-
mock_client = AsyncMock()
113-
mock_client.__aenter__.return_value = mock_client # context-manager protocol
114-
mock_client.head.return_value = httpx.Response(status_code=status_code)
115-
mocker.patch("httpx.AsyncClient", return_value=mock_client)
109+
async def test_check_repo_exists(returncode: int, *, expected: bool, mocker: MockerFixture) -> None:
110+
"""Verify that ``check_repo_exists`` interprets git ls-remote results correctly."""
111+
mock_exec = mocker.patch("asyncio.create_subprocess_exec", new_callable=AsyncMock)
112+
mock_process = AsyncMock()
113+
mock_process.communicate.return_value = (b"", b"")
114+
mock_process.returncode = returncode
115+
mock_exec.return_value = mock_process
116116

117117
result = await check_repo_exists(DEMO_URL)
118118

119119
assert result is expected
120+
# Verify that git ls-remote was called with the correct arguments
121+
mock_exec.assert_called_once_with(
122+
"git", "ls-remote", "--exit-code", DEMO_URL, "HEAD",
123+
stdout=asyncio.subprocess.PIPE,
124+
stderr=asyncio.subprocess.PIPE,
125+
)
120126

121127

122128
@pytest.mark.asyncio
@@ -188,24 +194,53 @@ async def test_clone_commit(run_command_mock: AsyncMock) -> None:
188194

189195

190196
@pytest.mark.asyncio
191-
async def test_check_repo_exists_with_redirect(mocker: MockerFixture) -> None:
192-
"""Test ``check_repo_exists`` when a redirect (302) is returned.
197+
async def test_check_repo_exists_with_exception(mocker: MockerFixture) -> None:
198+
"""Test ``check_repo_exists`` when an exception occurs during git ls-remote.
193199
194-
Given a URL that responds with "302 Found":
200+
Given a git ls-remote command that raises an exception:
195201
When ``check_repo_exists`` is called,
196202
Then it should return ``False``, indicating the repo is inaccessible.
197203
"""
198204
mock_exec = mocker.patch("asyncio.create_subprocess_exec", new_callable=AsyncMock)
199-
mock_process = AsyncMock()
200-
mock_process.communicate.return_value = (b"302\n", b"")
201-
mock_process.returncode = 0 # Simulate successful request
202-
mock_exec.return_value = mock_process
205+
mock_exec.side_effect = Exception("Git command failed")
203206

204207
repo_exists = await check_repo_exists(DEMO_URL)
205208

206209
assert repo_exists is False
207210

208211

212+
@pytest.mark.asyncio
213+
async def test_check_repo_exists_with_token(mocker: MockerFixture) -> None:
214+
"""Test ``check_repo_exists`` with GitHub token authentication.
215+
216+
Given a GitHub URL and a token:
217+
When ``check_repo_exists`` is called,
218+
Then it should include the authentication header in the git ls-remote command.
219+
"""
220+
mock_exec = mocker.patch("asyncio.create_subprocess_exec", new_callable=AsyncMock)
221+
mock_process = AsyncMock()
222+
mock_process.communicate.return_value = (b"", b"")
223+
mock_process.returncode = 0
224+
mock_exec.return_value = mock_process
225+
226+
mock_auth_header = mocker.patch("gitingest.utils.git_utils.create_git_auth_header")
227+
mock_auth_header.return_value = "http.extraheader=Authorization: Bearer test_token"
228+
229+
github_url = "https://github.com/owner/repo"
230+
result = await check_repo_exists(github_url, token="test_token")
231+
232+
assert result is True
233+
# Verify that authentication header was created
234+
mock_auth_header.assert_called_once_with("test_token", url=github_url)
235+
# Verify that git ls-remote was called with the authentication config
236+
mock_exec.assert_called_once_with(
237+
"git", "ls-remote", "-c", "http.extraheader=Authorization: Bearer test_token",
238+
"--exit-code", github_url, "HEAD",
239+
stdout=asyncio.subprocess.PIPE,
240+
stderr=asyncio.subprocess.PIPE,
241+
)
242+
243+
209244
@pytest.mark.asyncio
210245
async def test_clone_with_timeout(run_command_mock: AsyncMock) -> None:
211246
"""Test cloning a repository when a timeout occurs.

0 commit comments

Comments
 (0)