feat(v1.2.0): retry API, dernier commit, tri, coloration, export JSON
- client.py: _get_with_retry (max 2 retries, backoff lineaire), get_latest_commit - collector.py: champ last_commit_date dans RepoData - display.py: colonne "Dernier commit", _sort_repos (name/issues/release/activity), _colorize_milestone_due (rouge/jaune/vert selon echeance) - cli.py: options --sort/-s et --format/-f (table/json) - exporter.py: nouveau module, repos_to_dicts + export_json - 88 tests (35 nouveaux), ruff clean fixes #8, fixes #7, fixes #10, fixes #9, fixes #6 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
import requests
|
||||
|
||||
from gitea_dashboard.client import GiteaClient
|
||||
|
||||
@@ -129,7 +131,6 @@ class TestGetLatestRelease:
|
||||
|
||||
def test_raises_on_server_error(self):
|
||||
"""HTTP 500 raises an exception instead of silently returning bad data."""
|
||||
import pytest
|
||||
import requests as req
|
||||
|
||||
client = GiteaClient("http://gitea.local:3000", "tok")
|
||||
@@ -158,3 +159,92 @@ class TestGetMilestones:
|
||||
params={"state": "open"},
|
||||
)
|
||||
assert result == milestones
|
||||
|
||||
|
||||
class TestGetWithRetry:
|
||||
"""Test _get_with_retry method (retry on timeout)."""
|
||||
|
||||
def _make_client(self):
|
||||
return GiteaClient("http://gitea.local:3000", "tok")
|
||||
|
||||
@patch("time.sleep")
|
||||
def test_success_first_attempt(self, mock_sleep):
|
||||
"""No timeout — returns response directly without sleeping."""
|
||||
client = self._make_client()
|
||||
mock_resp = MagicMock()
|
||||
|
||||
with patch.object(client.session, "get", return_value=mock_resp):
|
||||
result = client._get_with_retry("http://gitea.local:3000/api/v1/test")
|
||||
|
||||
assert result is mock_resp
|
||||
mock_sleep.assert_not_called()
|
||||
|
||||
@patch("time.sleep")
|
||||
def test_success_after_timeout(self, mock_sleep):
|
||||
"""First call times out, second succeeds — one sleep of 1.0s."""
|
||||
client = self._make_client()
|
||||
mock_resp = MagicMock()
|
||||
|
||||
with patch.object(
|
||||
client.session, "get", side_effect=[requests.Timeout("timeout"), mock_resp]
|
||||
):
|
||||
result = client._get_with_retry("http://gitea.local:3000/api/v1/test")
|
||||
|
||||
assert result is mock_resp
|
||||
mock_sleep.assert_called_once_with(1.0)
|
||||
|
||||
@patch("time.sleep")
|
||||
def test_all_timeouts(self, mock_sleep):
|
||||
"""All 3 attempts timeout — raises Timeout, sleeps twice (1.0, 2.0)."""
|
||||
client = self._make_client()
|
||||
timeout_exc = requests.Timeout("timeout")
|
||||
|
||||
with patch.object(
|
||||
client.session, "get", side_effect=[timeout_exc, timeout_exc, timeout_exc]
|
||||
):
|
||||
with pytest.raises(requests.Timeout):
|
||||
client._get_with_retry("http://gitea.local:3000/api/v1/test")
|
||||
|
||||
assert mock_sleep.call_count == 2
|
||||
mock_sleep.assert_any_call(1.0)
|
||||
mock_sleep.assert_any_call(2.0)
|
||||
|
||||
|
||||
class TestGetLatestCommit:
|
||||
"""Test get_latest_commit method."""
|
||||
|
||||
def test_returns_first_commit(self):
|
||||
"""Returns the first commit from the list."""
|
||||
client = GiteaClient("http://gitea.local:3000", "tok")
|
||||
commit = {"sha": "abc123", "created": "2026-03-10T14:30:00Z"}
|
||||
mock_resp = MagicMock()
|
||||
mock_resp.status_code = 200
|
||||
mock_resp.json.return_value = [commit]
|
||||
|
||||
with patch.object(client.session, "get", return_value=mock_resp):
|
||||
result = client.get_latest_commit("admin", "my-repo")
|
||||
|
||||
assert result == commit
|
||||
|
||||
def test_empty_repo_returns_none(self):
|
||||
"""Returns None when repo has no commits."""
|
||||
client = GiteaClient("http://gitea.local:3000", "tok")
|
||||
mock_resp = MagicMock()
|
||||
mock_resp.status_code = 200
|
||||
mock_resp.json.return_value = []
|
||||
|
||||
with patch.object(client.session, "get", return_value=mock_resp):
|
||||
result = client.get_latest_commit("admin", "empty-repo")
|
||||
|
||||
assert result is None
|
||||
|
||||
def test_404_returns_none(self):
|
||||
"""Returns None when repo is not found (404)."""
|
||||
client = GiteaClient("http://gitea.local:3000", "tok")
|
||||
mock_resp = MagicMock()
|
||||
mock_resp.status_code = 404
|
||||
|
||||
with patch.object(client.session, "get", return_value=mock_resp):
|
||||
result = client.get_latest_commit("admin", "missing-repo")
|
||||
|
||||
assert result is None
|
||||
|
||||
Reference in New Issue
Block a user