jira-agent/tests/test_history.py
Andrey Epifancev de2d5b5252 Разбор журнала изменений Jira и фейк журнала (#39)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 10:27:00 +04:00

112 lines
5.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Журнал изменений Jira в refresh (агент v13, spec agent «Журнал изменений»)."""
import unittest
from datetime import datetime, timezone
from _common import SETTINGS, agent, jira_cfg, no_sleep
from fake_hub import FakeHub
from fake_jira import FakeJira
def _st(field, frm, to, fieldtype="jira", **kw):
return dict({"field": field, "fieldtype": fieldtype, "from": frm, "fromString": frm, "to": to, "toString": to}, **kw)
class Base(unittest.TestCase):
def setUp(self):
self.fake = FakeJira()
self.hub = FakeHub(SETTINGS)
cfg = jira_cfg(self.fake, hub_url=self.hub.base_url, hub_token=self.hub.token)
self.jira = agent.JiraClient(cfg)
self.jira.sleep = no_sleep
self.ex = agent.Executor(self.jira, dict(SETTINGS), agent.HubClient(cfg))
self.ex.sleep = no_sleep
self.logs = []
self._log = agent.log
agent.log = self.logs.append
def tearDown(self):
agent.log = self._log
self.fake.stop()
self.hub.stop()
class ChangelogItemsTest(Base):
def test_jira_time_forms(self):
want = datetime(2026, 10, 22, 10, 5, 11, tzinfo=timezone.utc)
for raw in ("2026-10-22T13:05:11.000+0300", "2026-10-22T13:05:11+03:00", "2026-10-22T10:05:11Z",
"2026-10-22T10:05:11.000Z", "2026-10-22T05:05:11.000-0500"):
self.assertEqual(agent._jira_time(raw), want, raw)
for raw in ("мусор", "", None, 42):
self.assertIsNone(agent._jira_time(raw))
def test_changelog_items_since_and_shape(self):
histories = [
{"id": "1", "author": {"name": "petrov", "displayName": "Петров Пётр"}, "created": "2026-10-21T10:00:00.000+0300",
"items": [_st("status", "Открыта", "В работе")]},
{"id": 2, "author": {"name": "ivanov"}, "created": "2026-10-22T12:10:00.000+0300",
"items": [dict(_st("status", "В работе", "Готово"), fieldId="status", **{"from": "3", "to": "10001"}),
_st("resolution", None, "Готово")]}]
items = self.ex.changelog_items("X", histories, agent._jira_time("2026-10-22T08:45:00Z"), lambda n: None)
self.assertEqual([(i["history_id"], i["seq"]) for i in items], [("2", 0), ("2", 1)])
self.assertEqual(items[0], {"history_id": "2", "seq": 0, "key": "X", "created": "2026-10-22T12:10:00.000+0300",
"author": "ivanov", "field_id": "status", "field_name": "status", "from": "3",
"from_string": "В работе", "to": "10001", "to_string": "Готово"})
self.assertEqual(items[1]["field_id"], "resolution")
self.assertIsNone(items[1]["from"])
def test_changelog_items_since_boundary_included(self):
h = [{"id": "1", "author": None, "created": "2026-10-22T11:45:00.000+0300", "items": [_st("status", "a", "b")]}]
items = self.ex.changelog_items("X", h, agent._jira_time("2026-10-22T08:45:00Z"), lambda n: None)
self.assertEqual(len(items), 1)
self.assertIsNone(items[0]["author"])
def test_changelog_items_custom_field_lookup(self):
asked = []
def field_id_of(name):
asked.append(name)
return "customfield_10201"
h = [{"id": "1", "author": {"name": "p"}, "created": "2026-10-22T12:00:00.000+0300",
"items": [_st("Плановое окончание", "2026-10-25", "2026-10-30", fieldtype="custom"),
_st("Sprint", "1", "2", fieldtype="custom", fieldId="customfield_10104"),
_st("duedate", "2026-10-25", "2026-10-30")]}]
items = self.ex.changelog_items("X", h, None, field_id_of)
self.assertEqual([i["field_id"] for i in items], ["customfield_10201", "customfield_10104", "duedate"])
self.assertEqual(asked, ["Плановое окончание"])
def test_changelog_items_drops_bad(self):
h = [{"id": None, "author": None, "created": "2026-10-22T12:00:00.000+0300", "items": [_st("status", "a", "b")]},
{"id": "2", "author": None, "created": "", "items": [_st("status", "a", "b")]},
{"id": "3", "author": None, "created": "2026-10-22T12:00:00.000+0300",
"items": [_st("", "a", "b"), _st("status", 1, 2)]}]
items = self.ex.changelog_items("X", h, None, lambda n: None)
self.assertEqual([(i["history_id"], i["seq"], i["from"], i["to"]) for i in items], [("3", 1, "1", "2")])
self.assertEqual(len([l for l in self.logs if "X" in l]), 3)
def test_changelog_items_no_since(self):
h = [{"id": str(n), "author": None, "created": "2020-01-01T00:00:00.000+0300", "items": [_st("status", "a", "b")]}
for n in range(3)]
self.assertEqual(len(self.ex.changelog_items("X", h, None, lambda n: None)), 3)
class FakeChangelogTest(Base):
def test_fake_search_expands_changelog(self):
self.fake.add("AURORA-1")
for n in range(3):
self.fake.add_history("AURORA-1", "2026-10-22T12:00:00.000+0300", [_st("status", "a", "b")])
self.fake.changelog_cap = 2
page = self.jira.get(agent.API + "/search", jql="key in (AURORA-1)", fields="key", expand="changelog")
cl = page["issues"][0]["changelog"]
self.assertEqual((cl["total"], len(cl["histories"])), (3, 2))
self.fake.issue_changelog_cap = 3
full = self.jira.get(agent.API + "/issue/AURORA-1", fields="key", expand="changelog")
self.assertEqual(len(full["changelog"]["histories"]), 3)
self.assertNotIn("changelog", self.jira.get(agent.API + "/issue/AURORA-1"))
self.fake.jql_results["x AND sprint in openSprints()"] = ["AURORA-1"]
self.assertEqual(self.fake.search_keys("x AND sprint in openSprints()"), ["AURORA-1"])
self.assertTrue(any(f["name"] == "Плановое окончание" for f in self.jira.get(agent.API + "/field")))
if __name__ == "__main__":
unittest.main()