0
0
Fork 0
mirror of https://github.com/healthchecks/healthchecks.git synced 2025-04-11 07:41:19 +00:00
healthchecks_healthchecks/hc/api/tests/test_notify_opsgenie.py
Pēteris Caune 83f161d657
Update transport classes to use Transport.last_ping() consistently
* Instead of check.n_pings (int) use last_ping().n
* Instead of check.last_ping (datetime) use last_ping().created

There is a time gap from creating a flip object to processing
it (sending out an alert). We want the notification to reflect
the check's state at the moment the flip was created. To do this,
we use the Transport.last_ping() helper method which retrieves
the last ping *that is not newer than the flip*.

This commit updates transport classes and templates to use
Transport.last_ping() consistently everywhere.
2024-04-15 15:09:17 +03:00

141 lines
5.4 KiB
Python

# coding: utf-8
from __future__ import annotations
import json
from datetime import timedelta as td
from unittest.mock import Mock, patch
from django.test.utils import override_settings
from django.utils.timezone import now
from hc.api.models import Channel, Check, Flip, Notification, Ping
from hc.test import BaseTestCase
class NotifyOpsgenieTestCase(BaseTestCase):
def _setup_data(
self, value: str, status: str = "down", email_verified: bool = True
) -> None:
self.check = Check(project=self.project)
self.check.name = "Foo"
# Transport classes should use flip.new_status,
# so the status "paused" should not appear anywhere
self.check.status = "paused"
self.check.last_ping = now()
self.check.save()
self.ping = Ping(owner=self.check)
self.ping.created = now() - td(minutes=10)
self.ping.n = 112233
self.ping.save()
self.channel = Channel(project=self.project)
self.channel.kind = "opsgenie"
self.channel.value = value
self.channel.email_verified = email_verified
self.channel.save()
self.channel.checks.add(self.check)
self.flip = Flip(owner=self.check)
self.flip.created = now()
self.flip.old_status = "new"
self.flip.new_status = status
@patch("hc.api.transports.curl.request", autospec=True)
def test_it_works(self, mock_post: Mock) -> None:
self._setup_data(json.dumps({"key": "123", "region": "us"}))
mock_post.return_value.status_code = 202
self.channel.notify(self.flip)
n = Notification.objects.get()
self.assertEqual(n.error, "")
payload = mock_post.call_args.kwargs["json"]
self.assertIn("""The check "Foo" is DOWN.""", payload["message"])
self.assertIn("""The check "Foo" is DOWN.""", payload["description"])
self.assertIn("Last ping was 10 minutes ago.", payload["description"])
self.assertIn("Last ping was 10 minutes ago.", payload["note"])
@patch("hc.api.transports.curl.request", autospec=True)
def test_opsgenie_with_legacy_value(self, mock_post: Mock) -> None:
self._setup_data(json.dumps({"key": "123", "region": "us"}))
mock_post.return_value.status_code = 202
self.channel.notify(self.flip)
n = Notification.objects.get()
self.assertEqual(n.error, "")
self.assertEqual(mock_post.call_count, 1)
url = mock_post.call_args.args[1]
self.assertIn("api.opsgenie.com", url)
payload = mock_post.call_args.kwargs["json"]
self.assertIn("DOWN", payload["message"])
@patch("hc.api.transports.curl.request", autospec=True)
def test_opsgenie_up(self, mock_post: Mock) -> None:
self._setup_data(json.dumps({"key": "123", "region": "us"}), status="up")
mock_post.return_value.status_code = 202
self.channel.notify(self.flip)
n = Notification.objects.get()
self.assertEqual(n.error, "")
self.assertEqual(mock_post.call_count, 1)
method, url = mock_post.call_args.args
self.assertTrue(str(self.check.code) in url)
@patch("hc.api.transports.curl.request", autospec=True)
def test_opsgenie_with_eu_region(self, mock_post: Mock) -> None:
self._setup_data(json.dumps({"key": "456", "region": "eu"}))
mock_post.return_value.status_code = 202
self.channel.notify(self.flip)
n = Notification.objects.get()
self.assertEqual(n.error, "")
self.assertEqual(mock_post.call_count, 1)
url = mock_post.call_args.args[1]
self.assertIn("api.eu.opsgenie.com", url)
@patch("hc.api.transports.curl.request", autospec=True)
def test_opsgenie_returns_error(self, mock_post: Mock) -> None:
self._setup_data(json.dumps({"key": "123", "region": "us"}))
mock_post.return_value.status_code = 403
mock_post.return_value.content = b"""{"message": "Nice try"}"""
self.channel.notify(self.flip)
n = Notification.objects.get()
self.assertEqual(n.error, 'Received status code 403 with a message: "Nice try"')
@patch("hc.api.transports.curl.request", autospec=True)
def test_it_handles_non_json_error_response(self, mock_post: Mock) -> None:
self._setup_data(json.dumps({"key": "123", "region": "us"}))
mock_post.return_value.status_code = 403
mock_post.return_value.json = Mock(side_effect=ValueError)
self.channel.notify(self.flip)
n = Notification.objects.get()
self.assertEqual(n.error, "Received status code 403")
@override_settings(OPSGENIE_ENABLED=False)
def test_it_requires_opsgenie_enabled(self) -> None:
self._setup_data(json.dumps({"key": "123", "region": "us"}))
self.channel.notify(self.flip)
n = Notification.objects.get()
self.assertEqual(n.error, "Opsgenie notifications are not enabled.")
@patch("hc.api.transports.curl.request", autospec=True)
def test_it_handles_no_last_ping(self, mock_post: Mock) -> None:
self._setup_data(json.dumps({"key": "123", "region": "us"}))
self.ping.delete()
mock_post.return_value.status_code = 202
self.channel.notify(self.flip)
n = Notification.objects.get()
self.assertEqual(n.error, "")
payload = mock_post.call_args.kwargs["json"]
self.assertNotIn("Last ping was", payload["description"])
self.assertNotIn("Last ping was", payload["note"])