test(palier-2): 13 tests — webhooks, SSE, étiquettes, milestones (65 verts)
FakeGitea: labels (repo_labels/label_ops), milestones (Sprint 1 sur issues 1 et 3), invalidate_cache compteur. Le flux SSE est testé au niveau du générateur: les clients de test HTTP ne ferment pas proprement un flux infini (vérifié empiriquement); le bout-en-bout HTTP a été validé en smoke test réel (curl + webhook).
This commit is contained in:
+51
-2
@@ -47,10 +47,10 @@ def _issue(number: int, title: str, state: str = "open", pr: bool = False) -> di
|
||||
"title": title,
|
||||
"body": f"Corps de l'issue {number} en **markdown**.",
|
||||
"state": state,
|
||||
"labels": [{"name": "bug", "color": "ff0000"}] if number == 1 else [],
|
||||
"labels": [{"id": 900, "name": "bug", "color": "ff0000"}] if number == 1 else [],
|
||||
"assignee": None,
|
||||
"assignees": [],
|
||||
"milestone": None,
|
||||
"milestone": {"id": 1, "title": "Sprint 1"} if number in (1, 3) else None,
|
||||
"due_date": None,
|
||||
"created_at": "2026-09-01T09:00:00Z",
|
||||
"updated_at": "2026-09-02T09:00:00Z",
|
||||
@@ -79,6 +79,10 @@ class FakeGitea:
|
||||
_issue(5, "Tâche focus"),
|
||||
],
|
||||
}
|
||||
self.repo_labels: dict[str, dict[str, dict]] = {"Projets/demo": {}}
|
||||
self.label_ops: list[tuple] = []
|
||||
self._label_seq = 100
|
||||
self.cache_invalidations = 0
|
||||
self.state_changes: list[tuple] = []
|
||||
self.created: list[tuple] = []
|
||||
self.comments: dict[tuple, list[dict]] = {
|
||||
@@ -150,6 +154,51 @@ class FakeGitea:
|
||||
self.posted_comments.append((owner, repo, number, body))
|
||||
return comment
|
||||
|
||||
def invalidate_cache(self):
|
||||
self.cache_invalidations += 1
|
||||
|
||||
async def get_labels(self, owner, repo):
|
||||
return list(self.repo_labels.setdefault(f"{owner}/{repo}", {}).values())
|
||||
|
||||
async def create_label(self, owner, repo, name, color):
|
||||
self._label_seq += 1
|
||||
label = {"id": self._label_seq, "name": name, "color": color.lstrip("#")}
|
||||
self.repo_labels.setdefault(f"{owner}/{repo}", {})[name] = label
|
||||
self.label_ops.append(("create", f"{owner}/{repo}", name))
|
||||
return label
|
||||
|
||||
async def ensure_label(self, owner, repo, name, color):
|
||||
existing = self.repo_labels.setdefault(f"{owner}/{repo}", {})
|
||||
if name in existing:
|
||||
return existing[name]
|
||||
return await self.create_label(owner, repo, name, color)
|
||||
|
||||
async def add_issue_label(self, owner, repo, number, label_id):
|
||||
issue = await self.get_issue(owner, repo, number)
|
||||
label = next(
|
||||
l for l in self.repo_labels[f"{owner}/{repo}"].values()
|
||||
if l["id"] == label_id
|
||||
)
|
||||
if label not in issue["labels"]:
|
||||
issue["labels"].append(label)
|
||||
self.label_ops.append(("add", number, label["name"]))
|
||||
|
||||
async def remove_issue_label(self, owner, repo, number, label_id):
|
||||
issue = await self.get_issue(owner, repo, number)
|
||||
removed = [l for l in issue["labels"] if l["id"] == label_id]
|
||||
issue["labels"] = [l for l in issue["labels"] if l["id"] != label_id]
|
||||
for label in removed:
|
||||
self.label_ops.append(("remove", number, label["name"]))
|
||||
|
||||
async def get_milestones(self, owner, repo, state="open"):
|
||||
return [
|
||||
{
|
||||
"id": 1, "title": "Sprint 1",
|
||||
"due_on": "2026-10-20T00:00:00Z",
|
||||
"open_issues": 1, "closed_issues": 1,
|
||||
}
|
||||
]
|
||||
|
||||
async def create_issue(self, owner, repo, title, body=""):
|
||||
self._next_number += 1
|
||||
issue = _issue(self._next_number, title)
|
||||
|
||||
Reference in New Issue
Block a user