Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions buildbotapi.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import json
import time
from dataclasses import dataclass
from typing import Any, cast

from aiohttp.client import ClientSession

JSON = dict[str, Any]

# Builders whose most recent build was more than this many days ago
# are considered inactive and ignored when checking for failures
STALE_BUILDER_DAYS = 14
SECONDS_PER_DAY = 24 * 60 * 60


@dataclass
class Builder:
Expand Down Expand Up @@ -66,6 +72,10 @@ async def is_builder_failing_currently(self, builder: Builder) -> bool:
if not builds:
return False
(build,) = builds

age_days = (time.time() - build["complete_at"]) / SECONDS_PER_DAY
if age_days > STALE_BUILDER_DAYS:
return False
if build["results"] == 2:
return True
return False
24 changes: 18 additions & 6 deletions tests/test_buildbotapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,24 +108,36 @@ async def test_buildbotapi_stable_builders() -> None:
assert "stable" in all_builders[3].tags


# The most recent builds in success.json and failure.json
SUCCESS_COMPLETE_AT = 1728312495
FAILURE_COMPLETE_AT = 1734198808
DAY = buildbotapi.SECONDS_PER_DAY


@pytest.mark.asyncio
@pytest.mark.parametrize(
["json_data", "expected"],
["json_data", "now", "expected"],
[
("tests/buildbotapi/success.json", False),
("tests/buildbotapi/failure.json", True),
("tests/buildbotapi/no-builds.json", False),
# Recent builds: judged on their result
("tests/buildbotapi/success.json", SUCCESS_COMPLETE_AT + DAY, False),
("tests/buildbotapi/failure.json", FAILURE_COMPLETE_AT + DAY, True),
("tests/buildbotapi/no-builds.json", FAILURE_COMPLETE_AT + DAY, False),
# Just inside the staleness cutoff: failure still counts
("tests/buildbotapi/failure.json", FAILURE_COMPLETE_AT + 13 * DAY, True),
# Stale build (last run > 14 days ago): builder ignored
("tests/buildbotapi/failure.json", FAILURE_COMPLETE_AT + 15 * DAY, False),
],
)
async def test_buildbotapi_is_builder_failing_currently_yes(
json_data: str, expected: bool
async def test_buildbotapi_is_builder_failing_currently(
monkeypatch: pytest.MonkeyPatch, json_data: str, now: int, expected: bool
) -> None:
# Arrange
mock_session = AsyncMock(aiohttp.ClientSession)
mock_session.get.return_value.__aenter__.return_value.status = 200
mock_session.get.return_value.__aenter__.return_value.text.return_value = load(
json_data
)
monkeypatch.setattr("buildbotapi.time.time", lambda: now)
api = buildbotapi.BuildBotAPI(mock_session)
builder = buildbotapi.Builder(builderid=3)

Expand Down
Loading