Netdata.cloud bot for Zulip
1"""Tests for webhook functionality."""
2
3from datetime import datetime
4
5import pytest
6
7from netdata_zulip_bot.formatter import ZulipMessageFormatter
8from netdata_zulip_bot.models import (
9 AlertNotification,
10 ReachabilityNotification,
11 WebhookPayload,
12)
13
14
15class TestWebhookPayload:
16 """Test webhook payload parsing."""
17
18 def test_parse_alert_notification(self):
19 """Test parsing alert notification payload."""
20 data = {
21 "message": "Critical alert on production server",
22 "alert": "high_cpu_usage",
23 "info": "CPU usage exceeded 90%",
24 "chart": "system.cpu",
25 "context": "cpu.utilization",
26 "space": "production",
27 "severity": "critical",
28 "date": "2024-01-15T14:30:00Z",
29 "alert_url": "https://app.netdata.cloud/spaces/abc/alerts/123",
30 }
31
32 notification = WebhookPayload.parse(data)
33 assert isinstance(notification, AlertNotification)
34 assert notification.severity.value == "critical"
35 assert notification.alert == "high_cpu_usage"
36 assert isinstance(notification.date, datetime)
37
38 def test_parse_reachability_notification(self):
39 """Test parsing reachability notification payload."""
40 data = {
41 "message": "Host web-server-01 is unreachable",
42 "url": "https://app.netdata.cloud/hosts/web-server-01",
43 "host": "web-server-01",
44 "severity": "critical",
45 "status": {"reachable": False, "text": "unreachable"},
46 }
47
48 notification = WebhookPayload.parse(data)
49 assert isinstance(notification, ReachabilityNotification)
50 assert notification.severity.value == "critical"
51 assert notification.host == "web-server-01"
52 assert not notification.status.reachable
53
54 def test_parse_unknown_payload_raises_error(self):
55 """Test that unknown payload types raise ValueError."""
56 data = {"unknown_field": "value"}
57
58 with pytest.raises(ValueError, match="Unknown notification type"):
59 WebhookPayload.parse(data)
60
61
62class TestZulipMessageFormatter:
63 """Test Zulip message formatting."""
64
65 def setup_method(self):
66 """Set up test fixtures."""
67 self.formatter = ZulipMessageFormatter()
68
69 def test_format_critical_alert(self):
70 """Test formatting critical alert notification."""
71 alert = AlertNotification(
72 message="Critical alert on production server",
73 alert="high_cpu_usage",
74 info="CPU usage exceeded 90% for 5 minutes",
75 chart="system.cpu",
76 context="cpu.utilization",
77 space="production",
78 severity="critical",
79 date=datetime(2024, 1, 15, 14, 30, 0),
80 alert_url="https://app.netdata.cloud/spaces/abc/alerts/123",
81 )
82
83 topic, content = self.formatter.format_alert(alert)
84
85 assert topic == "critical"
86 assert "🔴" in content
87 assert "**high_cpu_usage**" in content
88 assert "production" in content
89 assert "Critical" in content
90 assert "2024-01-15 14:30:00 UTC" in content
91 assert (
92 "[View Alert](https://app.netdata.cloud/spaces/abc/alerts/123)" in content
93 )
94
95 def test_format_warning_alert(self):
96 """Test formatting warning alert notification."""
97 alert = AlertNotification(
98 message="Warning: High memory usage",
99 alert="high_memory_usage",
100 info="Memory usage at 85%",
101 chart="system.ram",
102 context="memory.utilization",
103 space="staging",
104 severity="warning",
105 date=datetime(2024, 1, 15, 10, 15, 0),
106 alert_url="https://app.netdata.cloud/spaces/def/alerts/456",
107 )
108
109 topic, content = self.formatter.format_alert(alert)
110
111 assert topic == "warning"
112 assert "⚠️" in content
113 assert "Warning" in content
114
115 def test_format_clear_alert(self):
116 """Test formatting clear alert notification."""
117 alert = AlertNotification(
118 message="Alert cleared: CPU usage normal",
119 alert="high_cpu_usage",
120 info="CPU usage returned to normal levels",
121 chart="system.cpu",
122 context="cpu.utilization",
123 space="production",
124 severity="clear",
125 date=datetime(2024, 1, 15, 15, 0, 0),
126 alert_url="https://app.netdata.cloud/spaces/abc/alerts/123",
127 )
128
129 topic, content = self.formatter.format_alert(alert)
130
131 assert topic == "clear"
132 assert "✅" in content
133 assert "Clear" in content
134
135 def test_format_reachability_unreachable(self):
136 """Test formatting unreachable host notification."""
137 notification = ReachabilityNotification(
138 message="Host web-server-01 is unreachable",
139 url="https://app.netdata.cloud/hosts/web-server-01",
140 host="web-server-01",
141 severity="critical",
142 status={"reachable": False, "text": "unreachable"},
143 )
144
145 topic, content = self.formatter.format_reachability(notification)
146
147 assert topic == "reachability"
148 assert "🔴" in content # critical severity
149 assert "❌" in content # unreachable status
150 assert "web-server-01" in content
151 assert "Unreachable" in content
152 assert "[View Host](https://app.netdata.cloud/hosts/web-server-01)" in content
153
154 def test_format_reachability_reachable(self):
155 """Test formatting reachable host notification."""
156 notification = ReachabilityNotification(
157 message="Host web-server-01 is reachable again",
158 url="https://app.netdata.cloud/hosts/web-server-01",
159 host="web-server-01",
160 severity="info",
161 status={"reachable": True, "text": "reachable"},
162 )
163
164 topic, content = self.formatter.format_reachability(notification)
165
166 assert topic == "reachability"
167 assert "ℹ️" in content # info severity
168 assert "✅" in content # reachable status
169 assert "Reachable" in content