import pytest from jira_hub.core import projects, settings from jira_hub.modules.jira import mirror from jira_hub.modules.jira import projects as jira_projects @pytest.fixture def conn(open_db): c = open_db() settings.ensure_defaults(c) return c def test_boards_type_unknown_if_any_project_unknown(conn): # I-1: новый проект на известной доске projects.create(conn, "AWPCA", "a", 4216) jira_projects.record_board_types(conn, {"4216": "scrum"}) projects.create(conn, "NEW", "n", 4216) assert projects.get(conn, "NEW")["board_type"] is None assert jira_projects.boards(conn) == [{"id": 4216, "type": None}] jira_projects.record_board_types(conn, {"4216": "scrum"}) assert jira_projects.boards(conn) == [{"id": 4216, "type": "scrum"}] assert [p["board_type"] for p in projects.list_projects(conn)] == ["scrum", "scrum"] def test_boards_diverged_types_first_by_order(conn): projects.create(conn, "A", "a", 7); projects.create(conn, "B", "b", 7) conn.execute("UPDATE project SET board_type = 'kanban' WHERE label = 'B'") conn.execute("UPDATE project SET board_type = 'scrum' WHERE label = 'A'") assert jira_projects.boards(conn) == [{"id": 7, "type": "scrum"}] def test_light_list_same_order_no_count(conn): projects.create(conn, "B", "b", 1); projects.create(conn, "A", "a") got = projects.light_list(conn) assert [p["label"] for p in got] == [p["label"] for p in projects.list_projects(conn)] assert all("issues_count" not in p and set(p) == {"label", "board_id", "board_type"} for p in got) @pytest.mark.parametrize("label", ["", "STOCKS DRRK", "A\tB", "A\nB", "A\\B", "A\x00B", "A\x07B", "A\x7fB", "A,B", 'A"B', "A'B", "A(B", "A)B", "X" * 101, 5, None]) def test_bad_label(conn, label): with pytest.raises(projects.ProjectError) as e: projects.create(conn, label, "Название") assert e.value.field == "label" assert projects.list_projects(conn) == [] @pytest.mark.parametrize("name", ["", " ", "Я" * 101, None, 7]) def test_bad_name(conn, name): with pytest.raises(projects.ProjectError) as e: projects.create(conn, "AWPCA", name) assert e.value.field == "name" assert projects.list_projects(conn) == [] @pytest.mark.parametrize("board", [0, -1, True, "5120", 1.5]) def test_bad_board(conn, board): with pytest.raises(projects.ProjectError) as e: projects.create(conn, "AWPCA", "АРМ КА", board) assert e.value.field == "board_id" assert projects.list_projects(conn) == [] def test_create_and_list(conn): a = projects.create(conn, "AWPCA", " АРМ КА ", 4216) assert a == {"label": "AWPCA", "name": "АРМ КА", "board_id": 4216, "board_type": None, "created_at": a["created_at"]} projects.create(conn, "STOCKS_DRRK", "Запасы ДРРК") mirror.apply_state(conn, [{"key": "A-1", "labels": ["AWPCA"]}, {"key": "A-2", "labels": ["awpca", "x"]}], []) got = projects.list_projects(conn) assert [(p["label"], p["board_id"], p["issues_count"]) for p in got] == [("AWPCA", 4216, 1), ("STOCKS_DRRK", None, 0)] def test_order_created_then_label(conn): projects.create(conn, "ZZZ", "z"); projects.create(conn, "AAA", "a"); projects.create(conn, "MMM", "m") conn.execute("UPDATE project SET created_at = '2026-01-01T00:00:00+00:00' WHERE label IN ('AAA', 'MMM')") conn.execute("UPDATE project SET created_at = '2026-01-02T00:00:00+00:00' WHERE label = 'ZZZ'") assert projects.labels(conn) == ["AAA", "MMM", "ZZZ"] def test_same_label_other_case(conn): projects.create(conn, "AWPCA", "АРМ КА") with pytest.raises(projects.ProjectExists) as e: projects.create(conn, "awpca", "…") assert "уже есть" in str(e.value) and len(projects.list_projects(conn)) == 1 def test_base_jql(conn): assert jira_projects.base_jql(conn) is None projects.create(conn, "AWPCA", "АРМ КА"); projects.create(conn, "STOCKS_DRRK", "Запасы ДРРК") assert jira_projects.base_jql(conn) == 'project = AURORA AND labels in ("AWPCA", "STOCKS_DRRK")' settings.set_(conn, "project_key", "AUR") assert jira_projects.base_jql(conn).startswith("project = AUR AND") def test_base_jql_single_and_reserved_words(conn): projects.create(conn, "AWPCA", "АРМ КА") assert jira_projects.base_jql(conn) == 'project = AURORA AND labels in ("AWPCA")' projects.create(conn, "EMPTY", "Пустой") # зарезервированное слово JQL — в кавычках assert jira_projects.base_jql(conn) == 'project = AURORA AND labels in ("AWPCA", "EMPTY")' def test_boards_dedup_and_types(conn): projects.create(conn, "AWPCA", "a", 4216); projects.create(conn, "B", "b", 5120) projects.create(conn, "C", "c", 4216); projects.create(conn, "D", "d") jira_projects.record_board_types(conn, {"4216": "scrum"}) assert jira_projects.boards(conn) == [{"id": 4216, "type": "scrum"}, {"id": 5120, "type": None}] assert projects.get(conn, "C")["board_type"] == "scrum" # тип — у всех проектов с этой доской @pytest.mark.parametrize("boards", [{"5120": None}, {"5120": "simple"}, {"x": "kanban"}, ["5120"], None, {}]) def test_record_board_types_ignores(conn, boards): projects.create(conn, "B", "b", 5120) assert jira_projects.record_board_types(conn, boards) == 0 assert projects.get(conn, "B")["board_type"] is None @pytest.mark.parametrize("jql, labels", [ ("project = AURORA AND labels = AWPCA", ["AWPCA"]), ("project = AURORA AND labels in (AWPCA, STOCKS_DRRK)", ["AWPCA", "STOCKS_DRRK"]), ("project = AURORA AND labels IN (A,B)", ["A", "B"]), ('project = AURORA AND labels = "AWPCA"', ["AWPCA"]), ("project = AURORA AND labels in (AWPCA, awpca)", ["AWPCA"]), ("project = AURORA", None), ("project = AURORA AND labels = AWPCA ORDER BY key", None), ("project = AURORA AND labels in (A B)", None), ("", None), (None, None), (5, None), ]) def test_parse_legacy_labels(jql, labels): assert jira_projects.parse_legacy_labels(jql) == labels def test_add_project_fixture(conn, add_project): p = add_project(conn) assert (p["name"], p["board_id"], p["board_type"]) == ("АРМ КА", 4216, "scrum") def test_ensure_legacy(conn): assert jira_projects.ensure_legacy(conn, 4216) is True assert projects.get(conn, "AWPCA")["board_id"] == 4216 and projects.get(conn, "AWPCA")["name"] == "АРМ КА" assert jira_projects.ensure_legacy(conn, 1) is False def test_ensure_legacy_skips_case_variant_and_bad_board(open_db): c = open_db() settings.ensure_defaults(c) projects.create(c, "awpca", "x") assert jira_projects.ensure_legacy(c, 4216) is False c2 = open_db() settings.ensure_defaults(c2) assert jira_projects.ensure_legacy(c2, "oops") is True and projects.get(c2, "AWPCA")["board_id"] is None