From 2a0ae809a7664ee0c9e1a94482a3b83cac45510b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C4=93teris=20Caune?= <cuu508@gmail.com> Date: Wed, 27 Sep 2023 17:43:18 +0300 Subject: [PATCH] Add DowntimeRecord.no_data field --- hc/api/models.py | 35 +++++++++++------------ hc/api/tests/test_check_model.py | 19 ++++++++++-- templates/emails/report-summary-html.html | 2 +- templates/front/details_downtimes.html | 6 ++-- 4 files changed, 37 insertions(+), 25 deletions(-) diff --git a/hc/api/models.py b/hc/api/models.py index 3df77d6e..95dda315 100644 --- a/hc/api/models.py +++ b/hc/api/models.py @@ -133,27 +133,34 @@ class CheckDict(TypedDict, total=False): @dataclass class DowntimeRecord: - boundary: datetime - tz: str - duration: td - count: int | None + boundary: datetime # The start of this time interval (timezone-aware) + tz: str # For calculating total seconds in a month + no_data: bool # True if the check did not yet exist in this time interval + duration: td # Total downtime in this time interval + count: int # The number of downtime events in this time interval def monthly_uptime(self) -> float: # NB: this method assumes monthly boundaries. # It will yield incorrect results for weekly boundaries - max_seconds = seconds_in_month(self.boundary.date(), self.tz) up_seconds = max_seconds - self.duration.total_seconds() return up_seconds / max_seconds class DowntimeSummary(object): - def __init__(self, boundaries: list[datetime], tz: str) -> None: + def __init__(self, boundaries: list[datetime], tz: str, created: datetime) -> None: """ - `boundaries` are timezone-aware datetimes of the first days of time intervals - (months or weeks), and should be pre-sorted in descending order. + `boundaries` is a list of timezone-aware datetimes of the starts of time + intervals (months or weeks), and should be pre-sorted in descending order. """ - self.records = [DowntimeRecord(b, tz, td(), 0) for b in boundaries] + self.records = [] + prev_boundary = None + for b in boundaries: + # If the check was created *after* the start of the previous time + # interval then the check did not yet exist during this time interval: + no_data = prev_boundary and created > prev_boundary + self.records.append(DowntimeRecord(b, tz, no_data, td(), 0)) + prev_boundary = b def add(self, when: datetime, duration: td) -> None: for record in self.records: @@ -513,7 +520,7 @@ class Check(models.Model): """ - summary = DowntimeSummary(boundaries, tz) + summary = DowntimeSummary(boundaries, tz, self.created) # A list of flips and time interval boundaries events = [(b, "---") for b in boundaries] @@ -535,14 +542,6 @@ class Check(models.Model): if prev_status != "---": status = prev_status - # Set count to None for intervals when the check didn't exist yet - prev_boundary = None - for record in summary.records: - if prev_boundary and self.created > prev_boundary: - record.count = None - - prev_boundary = record.boundary - return summary.records def downtimes(self, months: int, tz: str) -> list[DowntimeRecord]: diff --git a/hc/api/tests/test_check_model.py b/hc/api/tests/test_check_model.py index be732984..800f6f72 100644 --- a/hc/api/tests/test_check_model.py +++ b/hc/api/tests/test_check_model.py @@ -188,16 +188,22 @@ class CheckModelTestCase(BaseTestCase): # Jan. 2020 self.assertEqual(jan.boundary.strftime("%m-%Y"), "01-2020") + self.assertEqual(jan.tz, "UTC") + self.assertFalse(jan.no_data) self.assertEqual(jan.duration, td()) self.assertEqual(jan.count, 0) # Dec. 2019 self.assertEqual(dec.boundary.strftime("%m-%Y"), "12-2019") + self.assertEqual(jan.tz, "UTC") + self.assertFalse(jan.no_data) self.assertEqual(dec.duration, td()) self.assertEqual(dec.count, 0) # Nov. 2019 self.assertEqual(nov.boundary.strftime("%m-%Y"), "11-2019") + self.assertEqual(jan.tz, "UTC") + self.assertFalse(jan.no_data) self.assertEqual(nov.duration, td()) self.assertEqual(nov.count, 0) @@ -272,16 +278,19 @@ class CheckModelTestCase(BaseTestCase): jan, dec, nov = r self.assertEqual(jan.boundary.isoformat(), "2020-01-01T00:00:00+00:00") + self.assertFalse(jan.no_data) self.assertEqual(jan.duration, td(days=14)) self.assertEqual(jan.monthly_uptime(), (31 - 14) / 31) self.assertEqual(jan.count, 1) self.assertEqual(dec.boundary.isoformat(), "2019-12-01T00:00:00+00:00") + self.assertFalse(dec.no_data) self.assertEqual(dec.duration, td(days=31)) self.assertEqual(dec.monthly_uptime(), 0.0) self.assertEqual(dec.count, 1) self.assertEqual(nov.boundary.isoformat(), "2019-11-01T00:00:00+00:00") + self.assertFalse(nov.no_data) self.assertEqual(nov.duration, td(days=16)) self.assertEqual(nov.monthly_uptime(), 14 / 30) self.assertEqual(nov.count, 1) @@ -304,6 +313,8 @@ class CheckModelTestCase(BaseTestCase): jan, dec = r self.assertEqual(jan.boundary.isoformat(), "2020-01-01T00:00:00+02:00") + self.assertEqual(jan.tz, "Europe/Riga") + self.assertFalse(jan.no_data) self.assertEqual(jan.duration, td(days=14, hours=1)) total_hours = 31 * 24 up_hours = total_hours - 14 * 24 - 1 @@ -311,6 +322,8 @@ class CheckModelTestCase(BaseTestCase): self.assertEqual(jan.count, 1) self.assertEqual(dec.boundary.isoformat(), "2019-12-01T00:00:00+02:00") + self.assertEqual(dec.tz, "Europe/Riga") + self.assertFalse(dec.no_data) self.assertEqual(dec.duration, td()) self.assertEqual(dec.count, 0) @@ -324,13 +337,13 @@ class CheckModelTestCase(BaseTestCase): jan, dec, nov = check.downtimes(3, "UTC") # Jan. 2020 - self.assertEqual(jan.count, 0) + self.assertFalse(jan.no_data) # Dec. 2019 - self.assertIsNone(dec.count) + self.assertTrue(dec.no_data) # Nov. 2019 - self.assertIsNone(nov.count) + self.assertTrue(nov.no_data) @override_settings(S3_BUCKET=None) def test_it_prunes(self) -> None: diff --git a/templates/emails/report-summary-html.html b/templates/emails/report-summary-html.html index 52b4561d..e8ce6a56 100644 --- a/templates/emails/report-summary-html.html +++ b/templates/emails/report-summary-html.html @@ -73,7 +73,7 @@ </td> {% else %} <td style="border-top: 1px solid #EDEFF2; padding: 16px 8px; font-family: Helvetica, Arial, sans-serif; color: #9BA2AB;"> - {% if d.count is None %} + {% if d.no_data %} {% comment %} The check didn't exist yet {% endcomment %} {% else %} All good! diff --git a/templates/front/details_downtimes.html b/templates/front/details_downtimes.html index 8aaa8ca1..48d353d4 100644 --- a/templates/front/details_downtimes.html +++ b/templates/front/details_downtimes.html @@ -5,11 +5,11 @@ <tr> <th>{{ d.boundary|date:"N Y"}}</th> <td> - {% if d.count %} + {% if d.no_data %} + – + {% elif d.count %} {{ d.count }} downtime{{ d.count|pluralize }}, {{ d.duration|hc_approx_duration }} total <span class="uptime">{{ d.monthly_uptime|pct }}% uptime</span> - {% elif d.count is None %} - – {% else %} All good! {% endif %}