Some checks failed
Deploy Nexus / deploy (push) Failing after 5s
Staging Verification Gate / verify-staging (push) Failing after 6s
CI / test (pull_request) Failing after 1m43s
CI / validate (pull_request) Failing after 1m47s
Review Approval Gate / verify-review (pull_request) Successful in 13s
Merge PR #1487
125 lines
5.5 KiB
Python
125 lines
5.5 KiB
Python
"""Tests for gitea_safe_push — Branch existence checks before file operations."""
|
|
import json
|
|
from unittest.mock import MagicMock, patch, call
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
import sys
|
|
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
|
|
|
from bin.gitea_safe_push import GiteaSafePush, GiteaAPIError
|
|
|
|
|
|
class TestGiteaAPIError:
|
|
def test_creation(self):
|
|
e = GiteaAPIError(404, "not found", '{"message":"not found"}')
|
|
assert e.status == 404
|
|
assert "404" in str(e)
|
|
|
|
def test_is_exception(self):
|
|
e = GiteaAPIError(500, "internal")
|
|
assert isinstance(e, Exception)
|
|
|
|
|
|
class TestBranchExists:
|
|
def test_branch_exists(self):
|
|
push = GiteaSafePush("https://forge.example.com", "token123")
|
|
with patch.object(push, "_api", return_value={"name": "main"}):
|
|
assert push.branch_exists("owner/repo", "main") is True
|
|
|
|
def test_branch_not_exists(self):
|
|
push = GiteaSafePush("https://forge.example.com", "token123")
|
|
with patch.object(push, "_api", side_effect=GiteaAPIError(404, "not found")):
|
|
assert push.branch_exists("owner/repo", "nonexistent") is False
|
|
|
|
def test_api_error_propagates(self):
|
|
push = GiteaSafePush("https://forge.example.com", "token123")
|
|
with patch.object(push, "_api", side_effect=GiteaAPIError(500, "server error")):
|
|
with pytest.raises(GiteaAPIError):
|
|
push.branch_exists("owner/repo", "main")
|
|
|
|
|
|
class TestEnsureBranch:
|
|
def test_already_exists(self):
|
|
push = GiteaSafePush("https://forge.example.com", "token123")
|
|
with patch.object(push, "branch_exists", return_value=True):
|
|
assert push.ensure_branch("owner/repo", "my-branch") is True
|
|
|
|
def test_creates_branch(self):
|
|
push = GiteaSafePush("https://forge.example.com", "token123")
|
|
with patch.object(push, "branch_exists", side_effect=[False, True]):
|
|
with patch.object(push, "_api", return_value={"name": "my-branch"}):
|
|
assert push.ensure_branch("owner/repo", "my-branch", base="main") is True
|
|
|
|
def test_creation_fails(self):
|
|
push = GiteaSafePush("https://forge.example.com", "token123")
|
|
with patch.object(push, "branch_exists", return_value=False):
|
|
with patch.object(push, "_api", side_effect=GiteaAPIError(422, "invalid")):
|
|
assert push.ensure_branch("owner/repo", "bad-branch") is False
|
|
|
|
|
|
class TestPushFile:
|
|
def test_rejects_missing_branch(self):
|
|
push = GiteaSafePush("https://forge.example.com", "token123")
|
|
with patch.object(push, "branch_exists", return_value=False):
|
|
result = push.push_file("owner/repo", "missing", "file.py", "content", "msg")
|
|
assert result is False
|
|
|
|
def test_creates_new_file(self):
|
|
push = GiteaSafePush("https://forge.example.com", "token123")
|
|
with patch.object(push, "branch_exists", return_value=True):
|
|
with patch.object(push, "_api", side_effect=[
|
|
GiteaAPIError(404, "not found"), # GET existing file
|
|
{}, # POST new file
|
|
]):
|
|
result = push.push_file("owner/repo", "branch", "new.py", "content", "msg")
|
|
assert result is True
|
|
|
|
def test_updates_existing_file(self):
|
|
push = GiteaSafePush("https://forge.example.com", "token123")
|
|
with patch.object(push, "branch_exists", return_value=True):
|
|
with patch.object(push, "_api", side_effect=[
|
|
{"sha": "abc123"}, # GET existing file
|
|
{}, # PUT update
|
|
]):
|
|
result = push.push_file("owner/repo", "branch", "existing.py", "new content", "msg")
|
|
assert result is True
|
|
|
|
def test_create_branch_when_missing(self):
|
|
push = GiteaSafePush("https://forge.example.com", "token123")
|
|
# Mock branch_exists: first call returns False (doesn't exist),
|
|
# second call (inside ensure_branch) returns True (created externally)
|
|
exists_calls = [False, True]
|
|
exists_idx = [0]
|
|
def mock_exists(repo, branch):
|
|
idx = min(exists_idx[0], len(exists_calls) - 1)
|
|
exists_idx[0] += 1
|
|
return exists_calls[idx]
|
|
with patch.object(push, "branch_exists", side_effect=mock_exists):
|
|
with patch.object(push, "_api") as mock_api:
|
|
mock_api.side_effect = [
|
|
GiteaAPIError(404, "not found"), # GET existing file (not found)
|
|
{"content": {"path": "f.py"}}, # POST new file
|
|
]
|
|
result = push.push_file("owner/repo", "new-branch", "f.py", "c", "m", create_branch=True)
|
|
assert result is True
|
|
|
|
|
|
class TestPushFiles:
|
|
def test_push_multiple_files(self):
|
|
push = GiteaSafePush("https://forge.example.com", "token123")
|
|
with patch.object(push, "ensure_branch", return_value=True):
|
|
with patch.object(push, "push_file", return_value=True):
|
|
results = push.push_files("owner/repo", "branch", {
|
|
"a.py": "content a",
|
|
"b.py": "content b",
|
|
}, "message")
|
|
assert all(results.values())
|
|
assert len(results) == 2
|
|
|
|
def test_branch_creation_fails_aborts_all(self):
|
|
push = GiteaSafePush("https://forge.example.com", "token123")
|
|
with patch.object(push, "ensure_branch", return_value=False):
|
|
results = push.push_files("owner/repo", "bad", {"a.py": "x"}, "msg")
|
|
assert all(v is False for v in results.values())
|