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