1 | <?php |
||
2 | /** |
||
3 | * SmokepingCliTest.php |
||
4 | * |
||
5 | * Checks that smokeping configuration output is consistent |
||
6 | * |
||
7 | * This program is free software: you can redistribute it and/or modify |
||
8 | * it under the terms of the GNU General Public License as published by |
||
9 | * the Free Software Foundation, either version 3 of the License, or |
||
10 | * (at your option) any later version. |
||
11 | * |
||
12 | * This program is distributed in the hope that it will be useful, |
||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the |
||
15 | * GNU General Public License for more details. |
||
16 | * |
||
17 | * You should have received a copy of the GNU General Public License |
||
18 | * along with this program. If not, see <https://www.gnu.org/licenses/>. |
||
19 | * |
||
20 | * @link https://librenms.org |
||
21 | * |
||
22 | * @copyright 2020 Adam Bishop |
||
23 | * @author Adam Bishop <[email protected]> |
||
24 | */ |
||
25 | |||
26 | namespace LibreNMS\Tests; |
||
27 | |||
28 | use App\Console\Commands\SmokepingGenerateCommand; |
||
29 | use App\Models\Device; |
||
30 | use Illuminate\Foundation\Testing\DatabaseTransactions; |
||
31 | use Illuminate\Support\Arr; |
||
32 | use Illuminate\Support\Str; |
||
33 | |||
34 | class SmokepingCliTest extends DBTestCase |
||
35 | { |
||
36 | use DatabaseTransactions; |
||
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||
37 | |||
38 | protected $groups = [ |
||
39 | 'Le23HKVMvN' => [ |
||
40 | 'Cl09bZU4sn' => [ |
||
41 | 'transport' => 'udp', |
||
42 | ], |
||
43 | 'c559TvthzY' => [ |
||
44 | 'transport' => 'udp6', |
||
45 | ], |
||
46 | 'sNtzSdxdw8' => [ |
||
47 | 'transport' => 'udp6', |
||
48 | ], |
||
49 | '10.0.0.3' => [ |
||
50 | 'transport' => 'udp', |
||
51 | ], |
||
52 | '2600::' => [ |
||
53 | 'transport' => 'udp', |
||
54 | ], |
||
55 | ], |
||
56 | 'Psv9oZcxdC' => [ |
||
57 | 'oHiPfLzrmU' => [ |
||
58 | 'transport' => 'udp', |
||
59 | ], |
||
60 | 'kEn7hZ7N37' => [ |
||
61 | 'transport' => 'udp6', |
||
62 | ], |
||
63 | 'PcbZ5FKtS3' => [ |
||
64 | 'transport' => 'udp6', |
||
65 | ], |
||
66 | '192.168.1.1' => [ |
||
67 | 'transport' => 'udp', |
||
68 | ], |
||
69 | 'fe80::' => [ |
||
70 | 'transport' => 'udp', |
||
71 | ], |
||
72 | ], |
||
73 | '4diY0pWFik' => [ |
||
74 | 'example.org' => [ |
||
75 | 'transport' => 'udp', |
||
76 | ], |
||
77 | 'host_with_under_score.example.org' => [ |
||
78 | 'transport' => 'udp6', |
||
79 | ], |
||
80 | ], |
||
81 | ]; |
||
82 | |||
83 | private $instance = null; |
||
84 | |||
85 | protected function setUp(): void |
||
86 | { |
||
87 | // We need an app instance available for these tests to load the translation machinary |
||
88 | $this->app = $this->createApplication(); |
||
89 | |||
90 | $this->instance = new SmokePingGenerateCommand(); |
||
91 | $this->instance->disableDNSLookup(); |
||
92 | parent::setUp(); |
||
93 | } |
||
94 | |||
95 | public function testNonsense() |
||
96 | { |
||
97 | $this->assertNotEquals(0, \Artisan::call('smokeping:generate --probes --targets --no-header')); |
||
98 | $this->assertNotEquals(0, \Artisan::call('smokeping:generate --probes --targets --single-process')); |
||
99 | $this->assertNotEquals(0, \Artisan::call('smokeping:generate --probes --targets')); |
||
100 | $this->assertNotEquals(0, \Artisan::call('smokeping:generate --no-header')); |
||
101 | $this->assertNotEquals(0, \Artisan::call('smokeping:generate --single-process')); |
||
102 | $this->assertNotEquals(0, \Artisan::call('smokeping:generate')); |
||
103 | |||
104 | $this->expectException('RuntimeException'); |
||
105 | \Artisan::call('smokeping:generate --foobar'); |
||
106 | } |
||
107 | |||
108 | public function testBuildHeader() |
||
109 | { |
||
110 | $warnings = ['rpPvjwdI0M0hlg6ZgZA', '2aUjOMql6ZWN7H0DthWDOyCvkXs0kVShhnASnc', 'HYMWbDplSW9PLNK9o9tySeJF4Ac61uTRHUUxxBXHiCl']; |
||
111 | |||
112 | $this->instance->setWarning($warnings[0]); |
||
113 | $this->instance->setWarning($warnings[1]); |
||
114 | $this->instance->setWarning($warnings[2]); |
||
115 | |||
116 | $header = $this->instance->buildHeader(false, false); |
||
117 | |||
118 | $this->assertEmpty(array_pop($header)); |
||
119 | |||
120 | foreach ($header as $line) { |
||
121 | $this->assertTrue(Str::startsWith($line, '# '), $line); |
||
122 | $this->assertTrue(Str::contains($line, array_merge($warnings, [__('commands.smokeping:generate.header-first'), __('commands.smokeping:generate.header-second'), __('commands.smokeping:generate.header-third')])), $line); |
||
123 | } |
||
124 | |||
125 | $this->assertEquals($this->instance->buildHeader(true, false), []); |
||
126 | } |
||
127 | |||
128 | public function testAssembleProbes() |
||
129 | { |
||
130 | $tests = [0, -1]; |
||
131 | |||
132 | foreach ($tests as $test) { |
||
133 | $this->assertEmpty($this->instance->assembleProbes($test)); |
||
134 | } |
||
135 | } |
||
136 | |||
137 | public function testBuildProbe() |
||
138 | { |
||
139 | $saved = ['+ Pl0JnP2vfE', |
||
140 | ' binary = /usr/bin/G28F3fFeew', |
||
141 | ' blazemode = true', |
||
142 | '++ Xq93BufZAU', |
||
143 | '++ etzY41dSRj0', |
||
144 | '++ etzY41dSRj1', |
||
145 | '++ etzY41dSRj2', |
||
146 | '', |
||
147 | ]; |
||
148 | |||
149 | $output = $this->instance->buildProbes('Pl0JnP2vfE', 'Xq93BufZAU', 'etzY41dSRj', '/usr/bin/G28F3fFeew', 3); |
||
150 | |||
151 | $this->assertEquals(implode(PHP_EOL, $saved), implode(PHP_EOL, $output)); |
||
152 | } |
||
153 | |||
154 | public function testBuildTargets() |
||
155 | { |
||
156 | $saved = [ |
||
157 | '+ Le23HKVMvN', |
||
158 | ' menu = Le23HKVMvN', |
||
159 | ' title = Le23HKVMvN', |
||
160 | '', |
||
161 | '++ Cl09bZU4sn', |
||
162 | ' menu = Cl09bZU4sn', |
||
163 | ' title = Cl09bZU4sn', |
||
164 | ' probe = lnmsFPing-0', |
||
165 | ' host = Cl09bZU4sn', |
||
166 | '', |
||
167 | '++ c559TvthzY', |
||
168 | ' menu = c559TvthzY', |
||
169 | ' title = c559TvthzY', |
||
170 | ' probe = lnmsFPing6-0', |
||
171 | ' host = c559TvthzY', |
||
172 | '', |
||
173 | '++ sNtzSdxdw8', |
||
174 | ' menu = sNtzSdxdw8', |
||
175 | ' title = sNtzSdxdw8', |
||
176 | ' probe = lnmsFPing6-1', |
||
177 | ' host = sNtzSdxdw8', |
||
178 | '', |
||
179 | '++ 10_0_0_3', |
||
180 | ' menu = 10.0.0.3', |
||
181 | ' title = 10.0.0.3', |
||
182 | ' probe = lnmsFPing-1', |
||
183 | ' host = 10.0.0.3', |
||
184 | '', |
||
185 | '++ 2600::', |
||
186 | ' menu = 2600::', |
||
187 | ' title = 2600::', |
||
188 | ' probe = lnmsFPing-2', |
||
189 | ' host = 2600::', |
||
190 | '', |
||
191 | '+ Psv9oZcxdC', |
||
192 | ' menu = Psv9oZcxdC', |
||
193 | ' title = Psv9oZcxdC', |
||
194 | '', |
||
195 | '++ oHiPfLzrmU', |
||
196 | ' menu = oHiPfLzrmU', |
||
197 | ' title = oHiPfLzrmU', |
||
198 | ' probe = lnmsFPing-3', |
||
199 | ' host = oHiPfLzrmU', |
||
200 | '', |
||
201 | '++ kEn7hZ7N37', |
||
202 | ' menu = kEn7hZ7N37', |
||
203 | ' title = kEn7hZ7N37', |
||
204 | ' probe = lnmsFPing6-2', |
||
205 | ' host = kEn7hZ7N37', |
||
206 | '', |
||
207 | '++ PcbZ5FKtS3', |
||
208 | ' menu = PcbZ5FKtS3', |
||
209 | ' title = PcbZ5FKtS3', |
||
210 | ' probe = lnmsFPing6-3', |
||
211 | ' host = PcbZ5FKtS3', |
||
212 | '', |
||
213 | '++ 192_168_1_1', |
||
214 | ' menu = 192.168.1.1', |
||
215 | ' title = 192.168.1.1', |
||
216 | ' probe = lnmsFPing-0', |
||
217 | ' host = 192.168.1.1', |
||
218 | '', |
||
219 | '++ fe80::', |
||
220 | ' menu = fe80::', |
||
221 | ' title = fe80::', |
||
222 | ' probe = lnmsFPing-1', |
||
223 | ' host = fe80::', |
||
224 | '', |
||
225 | '+ 4diY0pWFik', |
||
226 | ' menu = 4diY0pWFik', |
||
227 | ' title = 4diY0pWFik', |
||
228 | '', |
||
229 | '++ example_org', |
||
230 | ' menu = example.org', |
||
231 | ' title = example.org', |
||
232 | ' probe = lnmsFPing-2', |
||
233 | ' host = example.org', |
||
234 | '', |
||
235 | '++ host_with_under_score_example_org', |
||
236 | ' menu = host_with_under_score.example.org', |
||
237 | ' title = host_with_under_score.example.org', |
||
238 | ' probe = lnmsFPing6-0', |
||
239 | ' host = host_with_under_score.example.org', |
||
240 | '', |
||
241 | ]; |
||
242 | |||
243 | $output = $this->instance->buildTargets($this->groups, 4, false); |
||
244 | |||
245 | $this->assertEquals(implode(PHP_EOL, $saved), implode(PHP_EOL, $output)); |
||
246 | } |
||
247 | |||
248 | public function testSingleProccess() |
||
249 | { |
||
250 | $saved = [ |
||
251 | '+ Le23HKVMvN', |
||
252 | ' menu = Le23HKVMvN', |
||
253 | ' title = Le23HKVMvN', |
||
254 | '', |
||
255 | '++ Cl09bZU4sn', |
||
256 | ' menu = Cl09bZU4sn', |
||
257 | ' title = Cl09bZU4sn', |
||
258 | ' host = Cl09bZU4sn', |
||
259 | '', |
||
260 | '++ c559TvthzY', |
||
261 | ' menu = c559TvthzY', |
||
262 | ' title = c559TvthzY', |
||
263 | ' host = c559TvthzY', |
||
264 | '', |
||
265 | '++ sNtzSdxdw8', |
||
266 | ' menu = sNtzSdxdw8', |
||
267 | ' title = sNtzSdxdw8', |
||
268 | ' host = sNtzSdxdw8', |
||
269 | '', |
||
270 | '++ 10_0_0_3', |
||
271 | ' menu = 10.0.0.3', |
||
272 | ' title = 10.0.0.3', |
||
273 | ' host = 10.0.0.3', |
||
274 | '', |
||
275 | '++ 2600::', |
||
276 | ' menu = 2600::', |
||
277 | ' title = 2600::', |
||
278 | ' host = 2600::', |
||
279 | '', |
||
280 | '+ Psv9oZcxdC', |
||
281 | ' menu = Psv9oZcxdC', |
||
282 | ' title = Psv9oZcxdC', |
||
283 | '', |
||
284 | '++ oHiPfLzrmU', |
||
285 | ' menu = oHiPfLzrmU', |
||
286 | ' title = oHiPfLzrmU', |
||
287 | ' host = oHiPfLzrmU', |
||
288 | '', |
||
289 | '++ kEn7hZ7N37', |
||
290 | ' menu = kEn7hZ7N37', |
||
291 | ' title = kEn7hZ7N37', |
||
292 | ' host = kEn7hZ7N37', |
||
293 | '', |
||
294 | '++ PcbZ5FKtS3', |
||
295 | ' menu = PcbZ5FKtS3', |
||
296 | ' title = PcbZ5FKtS3', |
||
297 | ' host = PcbZ5FKtS3', |
||
298 | '', |
||
299 | '++ 192_168_1_1', |
||
300 | ' menu = 192.168.1.1', |
||
301 | ' title = 192.168.1.1', |
||
302 | ' host = 192.168.1.1', |
||
303 | '', |
||
304 | '++ fe80::', |
||
305 | ' menu = fe80::', |
||
306 | ' title = fe80::', |
||
307 | ' host = fe80::', |
||
308 | '', |
||
309 | '+ 4diY0pWFik', |
||
310 | ' menu = 4diY0pWFik', |
||
311 | ' title = 4diY0pWFik', |
||
312 | '', |
||
313 | '++ example_org', |
||
314 | ' menu = example.org', |
||
315 | ' title = example.org', |
||
316 | ' host = example.org', |
||
317 | '', |
||
318 | '++ host_with_under_score_example_org', |
||
319 | ' menu = host_with_under_score.example.org', |
||
320 | ' title = host_with_under_score.example.org', |
||
321 | ' host = host_with_under_score.example.org', |
||
322 | '', |
||
323 | ]; |
||
324 | |||
325 | $output = $this->instance->buildTargets($this->groups, 4, true); |
||
326 | |||
327 | $this->assertEquals(implode(PHP_EOL, $saved), implode(PHP_EOL, $output)); |
||
328 | } |
||
329 | |||
330 | public function testCompareLegacy() |
||
331 | { |
||
332 | $data = []; |
||
333 | |||
334 | // Generate a ridiculous number of random devices for testing |
||
335 | foreach (range(1, 1000) as $i) { |
||
336 | $device = Device::factory()->create(); /** @var Device $device */ |
||
337 | $data[$device->type][] = $device->hostname; |
||
338 | } |
||
339 | |||
340 | // Sort the data so the output matches the one from the database |
||
341 | $data = Arr::sortRecursive($data); |
||
342 | |||
343 | // Disable DNS lookups |
||
344 | \Artisan::call('smokeping:generate --targets --no-header --no-dns --single-process --compat'); |
||
345 | $new = \Artisan::Output(); |
||
346 | $old = $this->legacyAlgo($data); |
||
347 | |||
348 | $this->assertEquals($this->canonicalise($new), $this->canonicalise($old)); |
||
349 | } |
||
350 | |||
351 | public function legacyAlgo($data) |
||
352 | { |
||
353 | // This is the code taken from the old gen_smokeping script, with echos and sql queries replaced |
||
354 | $lines = []; |
||
355 | $lines[] = '' . PHP_EOL; |
||
356 | $lines[] = 'menu = Top' . PHP_EOL; |
||
357 | $lines[] = 'title = Network Latency Grapher' . PHP_EOL; |
||
358 | $lines[] = '' . PHP_EOL; |
||
359 | |||
360 | foreach ($data as $groupName => $devices) { |
||
361 | //Dot and space need to be replaced, since smokeping doesn't accept it at this level |
||
362 | $lines[] = '+ ' . str_replace(['.', ' '], '_', $groupName) . PHP_EOL; |
||
363 | $lines[] = 'menu = ' . $groupName . PHP_EOL; |
||
364 | $lines[] = 'title = ' . $groupName . PHP_EOL; |
||
365 | foreach ($devices as $device) { |
||
366 | $lines[] = '++ ' . str_replace(['.', ' '], '_', $device) . PHP_EOL; |
||
367 | $lines[] = 'menu = ' . $device . PHP_EOL; |
||
368 | $lines[] = 'title = ' . $device . PHP_EOL; |
||
369 | $lines[] = 'host = ' . $device . PHP_EOL . PHP_EOL; |
||
370 | } |
||
371 | } |
||
372 | |||
373 | // Return a string as we need to evaluate the entire thing as a block |
||
374 | return implode('', $lines); |
||
375 | } |
||
376 | |||
377 | public function canonicalise($input) |
||
378 | { |
||
379 | $input = explode(PHP_EOL, $input); |
||
380 | |||
381 | $output = []; |
||
382 | |||
383 | foreach ($input as $line) { |
||
384 | if (trim($line) !== '') { |
||
385 | $output[] = trim($line); |
||
386 | } |
||
387 | } |
||
388 | |||
389 | return implode(PHP_EOL, $output); |
||
390 | } |
||
391 | } |
||
392 |