Skip to content

Commit 3f93f2c

Browse files
committed
Try to prevent database access and add a test
1 parent 5e9e79d commit 3f93f2c

File tree

3 files changed

+289
-6
lines changed

3 files changed

+289
-6
lines changed

app/Http/Formatters/AlertLogDetailFormatter.php

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22

33
namespace App\Http\Formatters;
44

5-
use App\Facades\DeviceCache;
6-
use App\Facades\PortCache;
5+
use App\Models\Port;
76
use App\Models\Sensor;
87
use App\Models\StateTranslation;
98
use Illuminate\Support\Str;
@@ -106,7 +105,7 @@ private function formatPort(array $detail): ?string
106105
return null;
107106
}
108107

109-
$port = PortCache::get($detail['port_id']);
108+
$port = new Port($detail);
110109

111110
return $this->lines([
112111
$this->line('Port', Url::portLink($port), escape: false),
@@ -182,9 +181,9 @@ private function formatService(array $detail): ?string
182181
}
183182

184183
$service_url = Url::deviceUrl($device_id, ['tab' => 'services', 'view' => 'detail']);
185-
$service_host = empty($detail['service_ip'])
186-
? DeviceCache::get($device_id)->displayName()
187-
: $detail['service_ip'];
184+
$service_host = ! empty($detail['service_ip'])
185+
? $detail['service_ip']
186+
: ($detail['hostname'] ?? 'Unknown');
188187

189188
return $this->lines([
190189
$this->linkLine('Service', $service_url, $service_name),

app/Models/Port.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class Port extends DeviceRelatedModel
2222

2323
public $timestamps = false;
2424
protected $primaryKey = 'port_id';
25+
protected $guarded = [];
2526

2627
/**
2728
* Initialize this class
Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
<?php
2+
3+
namespace LibreNMS\Tests\Unit\Http\Formatters;
4+
5+
use App\Http\Formatters\AlertLogDetailFormatter;
6+
use LibreNMS\Tests\TestCase;
7+
8+
class AlertLogDetailFormatterTest extends TestCase
9+
{
10+
private AlertLogDetailFormatter $formatter;
11+
12+
protected function setUp(): void
13+
{
14+
parent::setUp();
15+
$this->formatter = new AlertLogDetailFormatter();
16+
}
17+
18+
public function testFormatBasicRuleAlert(): void
19+
{
20+
$details = [
21+
'rule' => [
22+
['message' => 'Test alert', 'value' => 10]
23+
]
24+
];
25+
26+
$output = $this->formatter->format($details);
27+
28+
$this->assertStringContainsString('#1:', $output);
29+
$this->assertStringContainsString('message: Test alert', $output);
30+
$this->assertStringContainsString('value: 10', $output);
31+
}
32+
33+
public function testFormatAlertWithDiff(): void
34+
{
35+
$details = [
36+
'diff' => [
37+
'added' => [
38+
['message' => 'New item']
39+
],
40+
'resolved' => [
41+
['message' => 'Fixed item']
42+
]
43+
],
44+
'rule' => [
45+
['message' => 'Still alert']
46+
]
47+
];
48+
49+
$output = $this->formatter->format($details);
50+
51+
$this->assertStringContainsString('<b>Modifications:</b>', $output);
52+
$this->assertStringContainsString('Added #1: message: New item', $output);
53+
$this->assertStringContainsString('Resolved #1: message: Fixed item', $output);
54+
$this->assertStringContainsString('<b>All current items:</b>', $output);
55+
$this->assertStringContainsString('#1: message: Still alert', $output);
56+
}
57+
58+
public function testFormatBill(): void
59+
{
60+
$details = [
61+
'rule' => [
62+
[
63+
'bill_id' => 123,
64+
'bill_name' => 'Test Bill'
65+
]
66+
]
67+
];
68+
69+
$output = $this->formatter->format($details);
70+
71+
$this->assertStringContainsString('Bill:', $output);
72+
$this->assertStringContainsString('bill_id=123', $output);
73+
$this->assertStringContainsString('Test Bill', $output);
74+
}
75+
76+
public function testFormatPort(): void
77+
{
78+
$details = [
79+
'rule' => [
80+
[
81+
'port_id' => 1,
82+
'device_id' => 1,
83+
'ifDescr' => 'eth0',
84+
'ifAlias' => 'WAN Interface',
85+
]
86+
]
87+
];
88+
89+
$output = $this->formatter->format($details);
90+
91+
$this->assertStringContainsString('Port:', $output);
92+
$this->assertStringContainsString('eth0', $output);
93+
$this->assertStringContainsString('Alias: WAN Interface', $output);
94+
}
95+
96+
public function testFormatSensor(): void
97+
{
98+
$details = [
99+
'rule' => [
100+
[
101+
'device_id' => 1,
102+
'sensor_id' => 456,
103+
'sensor_class' => 'temperature',
104+
'sensor_current' => 35,
105+
'sensor_limit' => 40,
106+
'sensor_limit_warn' => 38,
107+
'sensor_descr' => 'CPU Temp'
108+
]
109+
]
110+
];
111+
112+
$output = $this->formatter->format($details);
113+
114+
$this->assertStringContainsString('Sensor:', $output);
115+
$this->assertStringContainsString('Value: 35', $output); // Check for value, ignore unit if it varies
116+
$this->assertStringContainsString('(temperature)', $output);
117+
$this->assertStringContainsString('Thresholds: High Warn: 38, High: 40', $output);
118+
}
119+
120+
public function testFormatSensorState(): void
121+
{
122+
$details = [
123+
'rule' => [
124+
[
125+
'device_id' => 1,
126+
'sensor_id' => 789,
127+
'sensor_class' => 'state',
128+
'sensor_current' => 2,
129+
'state_descr' => 'Critical',
130+
'state_value' => 2, // Used by StateTranslation if constructor receives it
131+
'sensor_descr' => 'Power State'
132+
]
133+
]
134+
];
135+
136+
$output = $this->formatter->format($details);
137+
138+
$this->assertStringContainsString('Sensor:', $output);
139+
// The formatter pre-loads the translation if state_descr is set
140+
$this->assertStringContainsString('State: Critical (numerical: 2)', $output);
141+
}
142+
143+
public function testFormatAccessPoint(): void
144+
{
145+
$details = [
146+
'rule' => [
147+
[
148+
'accesspoint_id' => 101,
149+
'device_id' => 1,
150+
'name' => 'AP-01'
151+
]
152+
]
153+
];
154+
155+
$output = $this->formatter->format($details);
156+
157+
$this->assertStringContainsString('Access Point:', $output);
158+
$this->assertStringContainsString('accesspoints/ap=101', $output);
159+
$this->assertStringContainsString('AP-01', $output);
160+
}
161+
162+
public function testFormatService(): void
163+
{
164+
$details = [
165+
'rule' => [
166+
[
167+
'service_id' => 202,
168+
'device_id' => 1,
169+
'service_name' => 'HTTP',
170+
'service_type' => 'http',
171+
'service_ip' => '1.2.3.4',
172+
'service_desc' => 'Web Service',
173+
'service_message' => 'Connection refused'
174+
]
175+
]
176+
];
177+
178+
$output = $this->formatter->format($details);
179+
180+
$this->assertStringContainsString('Service:', $output);
181+
$this->assertStringContainsString('services/view=detail', $output);
182+
$this->assertStringContainsString('HTTP (http)', $output);
183+
$this->assertStringContainsString('Host: 1.2.3.4', $output);
184+
$this->assertStringContainsString('Description: Web Service', $output);
185+
$this->assertStringContainsString('Message: Connection refused', $output);
186+
}
187+
188+
public function testFormatBgpPeer(): void
189+
{
190+
$details = [
191+
'rule' => [
192+
[
193+
'bgpPeer_id' => 303,
194+
'device_id' => 1,
195+
'bgpPeerIdentifier' => '10.0.0.1',
196+
'bgpPeerDescr' => 'ISP-A',
197+
'bgpPeerRemoteAs' => 65001,
198+
'bgpPeerState' => 'idle'
199+
]
200+
]
201+
];
202+
203+
$output = $this->formatter->format($details);
204+
205+
$this->assertStringContainsString('BGP Peer:', $output);
206+
$this->assertStringContainsString('routing/proto=bgp', $output);
207+
$this->assertStringContainsString('10.0.0.1', $output);
208+
$this->assertStringContainsString('Description: ISP-A', $output);
209+
$this->assertStringContainsString('Remote AS: 65001', $output);
210+
$this->assertStringContainsString('State: idle', $output);
211+
}
212+
213+
public function testFormatMempool(): void
214+
{
215+
$details = [
216+
'rule' => [
217+
[
218+
'mempool_id' => 404,
219+
'mempool_descr' => 'System RAM',
220+
'mempool_perc' => 85.5,
221+
'mempool_free' => 1024 * 1024 * 100, // 100MB
222+
'mempool_total' => 1024 * 1024 * 1024 // 1GB
223+
]
224+
]
225+
];
226+
227+
$output = $this->formatter->format($details);
228+
229+
$this->assertStringContainsString('Memory Pool:', $output);
230+
$this->assertStringContainsString('mempool_usage/404', $output);
231+
$this->assertStringContainsString('System RAM', $output);
232+
$this->assertStringContainsString('Usage: 85.5', $output);
233+
$this->assertStringContainsString('Free: 104.86 MB', $output);
234+
$this->assertStringContainsString('Total: 1.07 GB', $output);
235+
}
236+
237+
public function testFormatApplication(): void
238+
{
239+
$details = [
240+
'rule' => [
241+
[
242+
'app_id' => 505,
243+
'device_id' => 1,
244+
'app_type' => 'nginx',
245+
'app_status' => 'up',
246+
'metric' => 'requests',
247+
'value' => 5000
248+
]
249+
]
250+
];
251+
252+
$output = $this->formatter->format($details);
253+
254+
$this->assertStringContainsString('Application:', $output);
255+
$this->assertStringContainsString('apps/app=nginx', $output);
256+
$this->assertStringContainsString('nginx', $output);
257+
$this->assertStringContainsString('Status: up', $output);
258+
$this->assertStringContainsString('Metric: requests = 5000', $output);
259+
}
260+
261+
public function testFallbackFormatting(): void
262+
{
263+
$details = [
264+
'rule' => [
265+
[
266+
'custom_key' => 'custom_value',
267+
'device_id' => 1, // should be skipped
268+
'some_id' => 123, // should be skipped (contains id)
269+
'description' => 'test', // should be skipped (contains desc)
270+
'another_val' => 'present'
271+
]
272+
]
273+
];
274+
275+
$output = $this->formatter->format($details);
276+
277+
$this->assertStringContainsString('custom_key: custom_value', $output);
278+
$this->assertStringContainsString('another_val: present', $output);
279+
$this->assertStringNotContainsString('device_id:', $output);
280+
$this->assertStringNotContainsString('some_id:', $output);
281+
$this->assertStringNotContainsString('description:', $output);
282+
}
283+
}

0 commit comments

Comments
 (0)