diff --git a/CHANGELOG.md b/CHANGELOG.md index 592313e5..adfacfe4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,8 @@ All notable changes to this project will be documented in this file. ### Improvements - Add the `prunetokenbucket` management command - Show check counts in JSON "badges" (#251) -- Webhooks support PUT method (#249) -- Webhooks can have different request bodies and headers for "up" and "events" (#249) +- Webhooks support HTTP PUT (#249) +- Webhooks can use different req. bodies and headers for "up" and "down" events. (#249) ### Bug Fixes - Fix badges for tags containing special characters (#240, #237) diff --git a/hc/api/tests/test_channel_model.py b/hc/api/tests/test_channel_model.py new file mode 100644 index 00000000..d64163cc --- /dev/null +++ b/hc/api/tests/test_channel_model.py @@ -0,0 +1,151 @@ +import json + +from hc.api.models import Channel +from hc.test import BaseTestCase + + +class ChannelModelTestCase(BaseTestCase): + def test_webhook_spec_handles_plain_single_address(self): + c = Channel(kind="webhook") + c.value = "http://example.org" + self.assertEqual( + c.down_webhook_spec, + {"method": "GET", "url": "http://example.org", "body": "", "headers": {}}, + ) + + self.assertEqual( + c.up_webhook_spec, {"method": "GET", "url": "", "body": "", "headers": {}} + ) + + def test_webhook_spec_handles_plain_pair(self): + c = Channel(kind="webhook") + c.value = "http://example.org\nhttp://example.com/up/" + self.assertEqual( + c.down_webhook_spec, + {"method": "GET", "url": "http://example.org", "body": "", "headers": {}}, + ) + + self.assertEqual( + c.up_webhook_spec, + { + "method": "GET", + "url": "http://example.com/up/", + "body": "", + "headers": {}, + }, + ) + + def test_webhook_spec_handles_plain_post(self): + c = Channel(kind="webhook") + c.value = "http://example.org\n\nhello world" + self.assertEqual( + c.down_webhook_spec, + { + "method": "POST", + "url": "http://example.org", + "body": "hello world", + "headers": {}, + }, + ) + + self.assertEqual( + c.up_webhook_spec, + {"method": "POST", "url": "", "body": "hello world", "headers": {}}, + ) + + def test_webhook_spec_handles_legacy_get(self): + c = Channel(kind="webhook") + c.value = json.dumps( + { + "url_down": "http://example.org", + "url_up": "http://example.org/up/", + "headers": {"X-Name": "value"}, + "post_data": "", + } + ) + + self.assertEqual( + c.down_webhook_spec, + { + "method": "GET", + "url": "http://example.org", + "body": "", + "headers": {"X-Name": "value"}, + }, + ) + + self.assertEqual( + c.up_webhook_spec, + { + "method": "GET", + "url": "http://example.org/up/", + "body": "", + "headers": {"X-Name": "value"}, + }, + ) + + def test_webhook_spec_handles_legacy_post(self): + c = Channel(kind="webhook") + c.value = json.dumps( + { + "url_down": "http://example.org", + "url_up": "http://example.org/up/", + "headers": {"X-Name": "value"}, + "post_data": "hello world", + } + ) + + self.assertEqual( + c.down_webhook_spec, + { + "method": "POST", + "url": "http://example.org", + "body": "hello world", + "headers": {"X-Name": "value"}, + }, + ) + + self.assertEqual( + c.up_webhook_spec, + { + "method": "POST", + "url": "http://example.org/up/", + "body": "hello world", + "headers": {"X-Name": "value"}, + }, + ) + + def test_webhook_spec_handles_mixed(self): + c = Channel(kind="webhook") + c.value = json.dumps( + { + "method_down": "GET", + "url_down": "http://example.org", + "body_down": "", + "headers_down": {"X-Status": "X"}, + "method_up": "POST", + "url_up": "http://example.org/up/", + "body_up": "hello world", + "headers_up": {"X-Status": "OK"}, + } + ) + + self.assertEqual( + c.down_webhook_spec, + { + "method": "GET", + "url": "http://example.org", + "body": "", + "headers": {"X-Status": "X"}, + }, + ) + + self.assertEqual( + c.up_webhook_spec, + { + "method": "POST", + "url": "http://example.org/up/", + "body": "hello world", + "headers": {"X-Status": "OK"}, + }, + ) diff --git a/hc/api/tests/test_notify.py b/hc/api/tests/test_notify.py index 24303846..6eac293a 100644 --- a/hc/api/tests/test_notify.py +++ b/hc/api/tests/test_notify.py @@ -146,8 +146,13 @@ class NotifyTestCase(BaseTestCase): self.assertIsInstance(kwargs["data"], bytes) @patch("hc.api.transports.requests.request") - def test_legacy_webhooks_handle_json_value(self, mock_request): - definition = {"url_down": "http://foo.com", "post_data": "", "headers": {}} + def test_webhooks_handle_json_value(self, mock_request): + definition = { + "method_down": "GET", + "url_down": "http://foo.com", + "body_down": "", + "headers_down": {}, + } self._setup_data("webhook", json.dumps(definition)) self.channel.notify(self.check) @@ -156,23 +161,13 @@ class NotifyTestCase(BaseTestCase): "get", "http://foo.com", headers=headers, timeout=5 ) - @patch("hc.api.transports.requests.request") - def test_legacy_webhooks_handle_json_up_event(self, mock_request): - definition = {"url_up": "http://bar", "post_data": "", "headers": {}} - - self._setup_data("webhook", json.dumps(definition), status="up") - self.channel.notify(self.check) - - headers = {"User-Agent": "healthchecks.io"} - mock_request.assert_called_with("get", "http://bar", headers=headers, timeout=5) - @patch("hc.api.transports.requests.request") def test_webhooks_handle_json_up_event(self, mock_request): definition = { "method_up": "GET", "url_up": "http://bar", "body_up": "", - "headers_up": {} + "headers_up": {}, } self._setup_data("webhook", json.dumps(definition), status="up") @@ -181,22 +176,6 @@ class NotifyTestCase(BaseTestCase): headers = {"User-Agent": "healthchecks.io"} mock_request.assert_called_with("get", "http://bar", headers=headers, timeout=5) - @patch("hc.api.transports.requests.request") - def test_legacy_webhooks_handle_post_headers(self, mock_request): - definition = { - "url_down": "http://foo.com", - "post_data": "data", - "headers": {"Content-Type": "application/json"}, - } - - self._setup_data("webhook", json.dumps(definition)) - self.channel.notify(self.check) - - headers = {"User-Agent": "healthchecks.io", "Content-Type": "application/json"} - mock_request.assert_called_with( - "post", "http://foo.com", data=b"data", headers=headers, timeout=5 - ) - @patch("hc.api.transports.requests.request") def test_webhooks_handle_post_headers(self, mock_request): definition = { @@ -214,22 +193,6 @@ class NotifyTestCase(BaseTestCase): "post", "http://foo.com", data=b"data", headers=headers, timeout=5 ) - @patch("hc.api.transports.requests.request") - def test_legacy_webhooks_handle_get_headers(self, mock_request): - definition = { - "url_down": "http://foo.com", - "post_data": "", - "headers": {"Content-Type": "application/json"}, - } - - self._setup_data("webhook", json.dumps(definition)) - self.channel.notify(self.check) - - headers = {"User-Agent": "healthchecks.io", "Content-Type": "application/json"} - mock_request.assert_called_with( - "get", "http://foo.com", headers=headers, timeout=5 - ) - @patch("hc.api.transports.requests.request") def test_webhooks_handle_get_headers(self, mock_request): definition = { @@ -247,22 +210,6 @@ class NotifyTestCase(BaseTestCase): "get", "http://foo.com", headers=headers, timeout=5 ) - @patch("hc.api.transports.requests.request") - def test_legacy_webhooks_allow_user_agent_override(self, mock_request): - definition = { - "url_down": "http://foo.com", - "post_data": "", - "headers": {"User-Agent": "My-Agent"}, - } - - self._setup_data("webhook", json.dumps(definition)) - self.channel.notify(self.check) - - headers = {"User-Agent": "My-Agent"} - mock_request.assert_called_with( - "get", "http://foo.com", headers=headers, timeout=5 - ) - @patch("hc.api.transports.requests.request") def test_webhooks_allow_user_agent_override(self, mock_request): definition = {