Команда ищет спринт доски по имени, создаёт его или записывает только отличающиеся имя, даты (по дню), цель. Повтор после переименования находит спринт по новому имени; оба имени заняты — ошибка без записи. Даты проверяются первыми, доска берётся только из команды. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
92 lines
5.3 KiB
Python
92 lines
5.3 KiB
Python
import unittest
|
||
from datetime import datetime
|
||
|
||
from _common import SETTINGS, agent, jira_cfg, no_sleep
|
||
from fake_jira import FakeJira
|
||
|
||
B = {"board_id": 4216}
|
||
|
||
|
||
class ExecutorSprintsTest(unittest.TestCase):
|
||
def setUp(self):
|
||
self.fake = FakeJira()
|
||
self.jira = agent.JiraClient(jira_cfg(self.fake))
|
||
self.jira.sleep = no_sleep
|
||
self.ex = agent.Executor(self.jira, dict(SETTINGS))
|
||
self.gaps = []
|
||
self.ex.sleep = self.gaps.append
|
||
self.fake.add("AURORA-1")
|
||
|
||
def tearDown(self):
|
||
self.fake.stop()
|
||
|
||
def run_cmd(self, ctype, **params):
|
||
return self.ex.run({"id": 1, "type": ctype, "params": params})
|
||
|
||
# --- ensure_sprint_meta ---
|
||
def test_meta_create_then_repeat(self): # сценарий «Создание спринта повтором не дублируется»
|
||
self.fake.board_sprints[4216] = [{"id": 3, "name": "AWPCA_Sprint_3_Corrections", "state": "active"}]
|
||
params = dict(B, sprint="AWPCA_Sprint_4", start_date="2026-10-28", end_date="2026-11-11", goal="свод ВГО")
|
||
out = self.run_cmd("ensure_sprint_meta", **params)
|
||
self.assertEqual(out["status"], "done", out)
|
||
sid = out["result"]["sprint_id"]
|
||
self.assertEqual(out["result"], {"sprint_id": sid, "created": True})
|
||
sp = self.fake.board_sprints[4216][-1]
|
||
off = datetime.now().astimezone().strftime("%z")
|
||
self.assertEqual((sp["id"], sp["name"], sp["state"], sp["originBoardId"], sp["goal"]),
|
||
(sid, "AWPCA_Sprint_4", "future", 4216, "свод ВГО"))
|
||
self.assertEqual((sp["startDate"], sp["endDate"]),
|
||
("2026-10-28T09:00:00.000" + off, "2026-11-11T18:00:00.000" + off))
|
||
again = self.run_cmd("ensure_sprint_meta", **params)
|
||
self.assertEqual(again["result"], {"sprint_id": sid, "created": False})
|
||
self.assertEqual(len(self.fake.writes()), 1)
|
||
|
||
def test_meta_updates_only_diff(self): # даты совпадают по дню, отличается цель
|
||
self.fake.board_sprints[4216] = [{"id": 9, "name": "S", "state": "future", "goal": "старая",
|
||
"startDate": "2026-10-28T10:00:00.000+03:00",
|
||
"endDate": "2026-11-11T19:00:00.000+03:00"}]
|
||
out = self.run_cmd("ensure_sprint_meta", sprint="S", start_date="2026-10-28", end_date="2026-11-11",
|
||
goal="новая", **B)
|
||
self.assertEqual(out["result"], {"sprint_id": 9, "created": False})
|
||
self.assertEqual(self.fake.sprint_posts, [("/rest/agile/1.0/sprint/9", {"goal": "новая"})])
|
||
|
||
def test_meta_rename_and_name_taken(self): # S → T: POST {"name": "T"}; есть S и T — «имя занято», без записи
|
||
self.fake.board_sprints[4216] = [{"id": 9, "name": "S", "state": "future"}]
|
||
out = self.run_cmd("ensure_sprint_meta", sprint="S", rename_to="T", **B)
|
||
self.assertEqual(out["result"], {"sprint_id": 9, "created": False})
|
||
self.assertEqual(self.fake.sprint_posts, [("/rest/agile/1.0/sprint/9", {"name": "T"})])
|
||
self.fake.sprint_posts, self.fake.requests = [], []
|
||
self.fake.board_sprints[4216] = [{"id": 9, "name": "S", "state": "future"},
|
||
{"id": 10, "name": "T", "state": "future"}]
|
||
out = self.run_cmd("ensure_sprint_meta", sprint="S", rename_to="T", **B)
|
||
self.assertEqual(out["status"], "failed")
|
||
self.assertIn("занято", out["error"])
|
||
self.assertEqual(self.fake.writes(), [])
|
||
|
||
def test_meta_repeat_after_rename(self): # Review Focus 3, R-69
|
||
self.fake.board_sprints[4216] = [{"id": 9, "name": "T", "state": "future"}]
|
||
out = self.run_cmd("ensure_sprint_meta", sprint="S", rename_to="T", **B)
|
||
self.assertEqual(out["result"], {"sprint_id": 9, "created": False})
|
||
self.assertEqual(self.fake.writes(), [])
|
||
|
||
def test_meta_closed_and_duplicates(self):
|
||
self.fake.board_sprints[4216] = [{"id": 1, "name": "C", "state": "closed"},
|
||
{"id": 5, "name": "D", "state": "future"},
|
||
{"id": 6, "name": "D", "state": "active"}]
|
||
self.assertEqual(self.run_cmd("ensure_sprint_meta", sprint="C", goal="x", **B)["error"], "спринт закрыт")
|
||
self.assertEqual(self.run_cmd("ensure_sprint_meta", sprint="D", **B)["error"],
|
||
"несколько спринтов с именем «D»: 5, 6")
|
||
self.assertEqual(self.fake.writes(), [])
|
||
|
||
def test_meta_bad_date(self): # Review Focus 5
|
||
for bad in ("28.10.2026", "2026-13-01"):
|
||
out = self.run_cmd("ensure_sprint_meta", sprint="N", start_date=bad, **B)
|
||
self.assertEqual(out["status"], "failed")
|
||
self.assertIn("ГГГГ-ММ-ДД", out["error"])
|
||
self.assertEqual(self.fake.writes(), [])
|
||
|
||
def test_meta_without_board(self): # R-70
|
||
out = self.run_cmd("ensure_sprint_meta", sprint="N")
|
||
self.assertEqual((out["status"], out["error"]), ("failed", "board_id нет в команде — спринты недоступны"))
|
||
self.assertEqual(self.fake.requests, [])
|