1 /*****************************************************************************
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 *
17 *****************************************************************************/
18
19 #define NSCORE 1
20 #include "config.h"
21 #include "comments.h"
22 #include "common.h"
23 #include "statusdata.h"
24 #include "downtime.h"
25 #include "macros.h"
26 #include "nagios.h"
27 #include "broker.h"
28 #include "perfdata.h"
29 #include "tap.h"
30 #include "test-stubs.c"
31 #include "stub_sehandlers.c"
32 #include "stub_comments.c"
33 #include "stub_perfdata.c"
34 #include "stub_downtime.c"
35 #include "../common/shared.c"
36
37 int log_host_retries = 0;
38 int date_format;
39
40 /* Test specific functions + variables */
41 service *svc1 = NULL, *svc2 = NULL;
42 host *host1 = NULL;
43 int found_log_rechecking_host_when_service_wobbles = 0;
44 int found_log_run_async_host_check_3x = 0;
45 check_result *tmp_check_result;
46
setup_check_result()47 void setup_check_result() {
48 struct timeval start_time, finish_time;
49 start_time.tv_sec = 1234567890L;
50 start_time.tv_usec = 0L;
51 finish_time.tv_sec = 1234567891L;
52 finish_time.tv_usec = 0L;
53
54 tmp_check_result = (check_result *)malloc(sizeof(check_result));
55 tmp_check_result->check_type = SERVICE_CHECK_ACTIVE;
56 tmp_check_result->check_options = 0;
57 tmp_check_result->scheduled_check = TRUE;
58 tmp_check_result->reschedule_check = TRUE;
59 tmp_check_result->exited_ok = TRUE;
60 tmp_check_result->return_code = 0;
61 tmp_check_result->output = strdup("Fake result");
62 tmp_check_result->latency = 0.6969;
63 tmp_check_result->start_time = start_time;
64 tmp_check_result->finish_time = finish_time;
65 }
66
67 int c = 0;
update_program_status(int aggregated_dump)68 int update_program_status(int aggregated_dump) {
69 c++;
70 /* printf ("# In the update_program_status hook: %d\n", c); */
71
72 /* Set this to break out of event_execution_loop */
73 if(c > 10) {
74 sigshutdown = TRUE;
75 c = 0;
76 }
77 }
log_debug_info(int level,int verbosity,const char * fmt,...)78 int log_debug_info(int level, int verbosity, const char *fmt, ...) {
79 va_list ap;
80 char *buffer = NULL;
81
82 va_start(ap, fmt);
83 /* vprintf( fmt, ap ); */
84 vasprintf(&buffer, fmt, ap);
85 if(strcmp(buffer, "Service wobbled between non-OK states, so we'll recheck the host state...\n") == 0) {
86 found_log_rechecking_host_when_service_wobbles++;
87 }
88 if(strcmp(buffer, "run_async_host_check_3x()\n") == 0) {
89 found_log_run_async_host_check_3x++;
90 }
91 free(buffer);
92 va_end(ap);
93 }
94
95
96 void
setup_objects(time_t time)97 setup_objects(time_t time) {
98 timed_event *new_event = NULL;
99
100 enable_predictive_service_dependency_checks = FALSE;
101
102 host1 = (host *)calloc(1, sizeof(host));
103 host1->name = strdup("Host1");
104 host1->address = strdup("127.0.0.1");
105 host1->retry_interval = 1;
106 host1->check_interval = 5;
107 host1->check_options = 0;
108 host1->state_type = SOFT_STATE;
109 host1->current_state = HOST_DOWN;
110 host1->has_been_checked = TRUE;
111 host1->last_check = time;
112 host1->next_check = time;
113
114 /* First service is a normal one */
115 svc1 = (service *)calloc(1, sizeof(service));
116 svc1->host_name = strdup("Host1");
117 svc1->host_ptr = host1;
118 svc1->description = strdup("Normal service");
119 svc1->check_options = 0;
120 svc1->next_check = time;
121 svc1->state_type = SOFT_STATE;
122 svc1->current_state = STATE_CRITICAL;
123 svc1->retry_interval = 1;
124 svc1->check_interval = 5;
125 svc1->current_attempt = 1;
126 svc1->max_attempts = 4;
127 svc1->last_state_change = 0;
128 svc1->last_state_change = 0;
129 svc1->last_check = (time_t)1234560000;
130 svc1->host_problem_at_last_check = FALSE;
131 svc1->plugin_output = strdup("Initial state");
132 svc1->last_hard_state_change = (time_t)1111111111;
133
134 /* Second service .... to be configured! */
135 svc2 = (service *)calloc(1, sizeof(service));
136 svc2->host_name = strdup("Host1");
137 svc2->description = strdup("To be nudged");
138 svc2->check_options = 0;
139 svc2->next_check = time;
140 svc2->state_type = SOFT_STATE;
141 svc2->current_state = STATE_OK;
142 svc2->retry_interval = 1;
143 svc2->check_interval = 5;
144
145 }
146
147 int
main(int argc,char ** argv)148 main(int argc, char **argv) {
149 time_t now = 0L;
150
151
152 plan_tests(42);
153
154 time(&now);
155
156
157 /* Test to confirm that if a service is warning, the notified_on_critical is reset */
158 tmp_check_result = (check_result *)calloc(1, sizeof(check_result));
159 tmp_check_result->host_name = strdup("host1");
160 tmp_check_result->service_description = strdup("Normal service");
161 tmp_check_result->object_check_type = SERVICE_CHECK;
162 tmp_check_result->check_type = SERVICE_CHECK_ACTIVE;
163 tmp_check_result->check_options = 0;
164 tmp_check_result->scheduled_check = TRUE;
165 tmp_check_result->reschedule_check = TRUE;
166 tmp_check_result->latency = 0.666;
167 tmp_check_result->start_time.tv_sec = 1234567890;
168 tmp_check_result->start_time.tv_usec = 56565;
169 tmp_check_result->finish_time.tv_sec = 1234567899;
170 tmp_check_result->finish_time.tv_usec = 45454;
171 tmp_check_result->early_timeout = 0;
172 tmp_check_result->exited_ok = TRUE;
173 tmp_check_result->return_code = 1;
174 tmp_check_result->output = strdup("Warning - check notified_on_critical reset");
175
176 setup_objects(now);
177 svc1->last_state = STATE_CRITICAL;
178 svc1->notified_on_critical = TRUE;
179 svc1->current_notification_number = 999;
180 svc1->last_notification = (time_t)11111;
181 svc1->next_notification = (time_t)22222;
182 svc1->no_more_notifications = TRUE;
183
184 handle_async_service_check_result(svc1, tmp_check_result);
185
186 /* This has been taken out because it is not required
187 ok( svc1->notified_on_critical==FALSE, "notified_on_critical reset" );
188 */
189 ok(svc1->last_notification == (time_t)0, "last notification reset due to state change");
190 ok(svc1->next_notification == (time_t)0, "next notification reset due to state change");
191 ok(svc1->no_more_notifications == FALSE, "no_more_notifications reset due to state change");
192 ok(svc1->current_notification_number == 999, "notification number NOT reset");
193
194 /* Test case:
195 service that transitions from OK to CRITICAL (where its host is set to DOWN) will get set to a hard state
196 even though check attempts = 1 of 4
197 */
198 setup_objects((time_t) 1234567800L);
199 host1->current_state = HOST_DOWN;
200 svc1->current_state = STATE_OK;
201 svc1->state_type = HARD_STATE;
202 setup_check_result();
203 tmp_check_result->return_code = STATE_CRITICAL;
204 tmp_check_result->output = strdup("CRITICAL failure");
205 log_service_event_flag = 0;
206
207 handle_async_service_check_result(svc1, tmp_check_result);
208
209 ok(log_service_event_flag == 1, "log_service_event() was called");
210 ok(svc1->last_hard_state_change == (time_t)1234567890, "Got last_hard_state_change time=%lu", svc1->last_hard_state_change);
211 ok(svc1->last_state_change == svc1->last_hard_state_change, "Got same last_state_change");
212 ok(svc1->last_hard_state == 2, "Should save the last hard state as critical for next time");
213 ok(svc1->host_problem_at_last_check == TRUE, "Got host_problem_at_last_check set to TRUE due to host failure - this needs to be saved otherwise extra alerts raised in subsequent runs");
214 ok(svc1->state_type == HARD_STATE, "This should be a HARD state since the host is in a failure state");
215 ok(svc1->current_attempt == 1, "Previous status was OK, so this failure should show current_attempt=1") || diag("Current attempt=%d", svc1->current_attempt);
216
217
218
219
220
221 /* Test case:
222 OK -> WARNING 1/4 -> ack -> WARNING 2/4 -> OK transition
223 Tests that the ack is left for 2/4
224 */
225 setup_objects(now);
226 host1->current_state = HOST_UP;
227 host1->max_attempts = 4;
228 svc1->last_state = STATE_OK;
229 svc1->last_hard_state = STATE_OK;
230 svc1->current_state = STATE_OK;
231 svc1->state_type = SOFT_STATE;
232
233 setup_check_result();
234 tmp_check_result->return_code = STATE_WARNING;
235 tmp_check_result->output = strdup("WARNING failure");
236 handle_async_service_check_result(svc1, tmp_check_result);
237
238 ok(svc1->last_notification == (time_t)0, "last notification reset due to state change");
239 ok(svc1->next_notification == (time_t)0, "next notification reset due to state change");
240 ok(svc1->no_more_notifications == FALSE, "no_more_notifications reset due to state change");
241 ok(svc1->current_notification_number == 0, "notification number reset");
242 ok(svc1->acknowledgement_type == ACKNOWLEDGEMENT_NONE, "No acks");
243
244 svc1->acknowledgement_type = ACKNOWLEDGEMENT_NORMAL;
245
246 setup_check_result();
247 tmp_check_result->return_code = STATE_WARNING;
248 tmp_check_result->output = strdup("WARNING failure");
249 handle_async_service_check_result(svc1, tmp_check_result);
250
251 ok(svc1->acknowledgement_type == ACKNOWLEDGEMENT_NORMAL, "Ack left");
252
253 setup_check_result();
254 tmp_check_result->return_code = STATE_OK;
255 tmp_check_result->output = strdup("Back to OK");
256 handle_async_service_check_result(svc1, tmp_check_result);
257
258 ok(svc1->acknowledgement_type == ACKNOWLEDGEMENT_NONE, "Ack reset to none");
259
260
261
262
263 /* Test case:
264 OK -> WARNING 1/4 -> ack -> WARNING 2/4 -> WARNING 3/4 -> WARNING 4/4 -> WARNING 4/4 -> OK transition
265 Tests that the ack is not removed on hard state change
266 */
267 setup_objects(now);
268 host1->current_state = HOST_UP;
269 host1->max_attempts = 4;
270 svc1->last_state = STATE_OK;
271 svc1->last_hard_state = STATE_OK;
272 svc1->current_state = STATE_OK;
273 svc1->state_type = SOFT_STATE;
274 svc1->current_attempt = 1;
275
276 setup_check_result();
277 tmp_check_result->return_code = STATE_OK;
278 tmp_check_result->output = strdup("Reset to OK");
279 handle_async_service_check_result(svc1, tmp_check_result);
280
281 setup_check_result();
282 tmp_check_result->return_code = STATE_WARNING;
283 tmp_check_result->output = strdup("WARNING failure 1");
284 handle_async_service_check_result(svc1, tmp_check_result);
285
286 ok(svc1->state_type == SOFT_STATE, "Soft state");
287 ok(svc1->acknowledgement_type == ACKNOWLEDGEMENT_NONE, "No acks - testing transition to hard warning state");
288
289 svc1->acknowledgement_type = ACKNOWLEDGEMENT_NORMAL;
290
291 setup_check_result();
292 tmp_check_result->return_code = STATE_WARNING;
293 tmp_check_result->output = strdup("WARNING failure 2");
294 handle_async_service_check_result(svc1, tmp_check_result);
295 ok(svc1->state_type == SOFT_STATE, "Soft state");
296 ok(svc1->acknowledgement_type == ACKNOWLEDGEMENT_NORMAL, "Ack left");
297
298 setup_check_result();
299 tmp_check_result->return_code = STATE_WARNING;
300 tmp_check_result->output = strdup("WARNING failure 3");
301 handle_async_service_check_result(svc1, tmp_check_result);
302 ok(svc1->state_type == SOFT_STATE, "Soft state");
303 ok(svc1->acknowledgement_type == ACKNOWLEDGEMENT_NORMAL, "Ack left");
304
305 setup_check_result();
306 tmp_check_result->return_code = STATE_WARNING;
307 tmp_check_result->output = strdup("WARNING failure 4");
308 handle_async_service_check_result(svc1, tmp_check_result);
309 ok(svc1->state_type == HARD_STATE, "Hard state");
310 ok(svc1->acknowledgement_type == ACKNOWLEDGEMENT_NORMAL, "Ack left on hard failure");
311
312 setup_check_result();
313 tmp_check_result->return_code = STATE_OK;
314 tmp_check_result->output = strdup("Back to OK");
315 handle_async_service_check_result(svc1, tmp_check_result);
316 ok(svc1->acknowledgement_type == ACKNOWLEDGEMENT_NONE, "Ack removed");
317
318
319
320
321 /* Test case:
322 OK -> WARNING 1/1 -> ack -> WARNING -> OK transition
323 Tests that the ack is not removed on 2nd warning, but is on OK
324 */
325 setup_objects(now);
326 host1->current_state = HOST_UP;
327 host1->max_attempts = 4;
328 svc1->last_state = STATE_OK;
329 svc1->last_hard_state = STATE_OK;
330 svc1->current_state = STATE_OK;
331 svc1->state_type = SOFT_STATE;
332 svc1->current_attempt = 1;
333 svc1->max_attempts = 2;
334 setup_check_result();
335 tmp_check_result->return_code = STATE_WARNING;
336 tmp_check_result->output = strdup("WARNING failure 1");
337
338 handle_async_service_check_result(svc1, tmp_check_result);
339
340 ok(svc1->acknowledgement_type == ACKNOWLEDGEMENT_NONE, "No acks - testing transition to immediate hard then OK");
341
342 svc1->acknowledgement_type = ACKNOWLEDGEMENT_NORMAL;
343
344 setup_check_result();
345 tmp_check_result->return_code = STATE_WARNING;
346 tmp_check_result->output = strdup("WARNING failure 2");
347 handle_async_service_check_result(svc1, tmp_check_result);
348 ok(svc1->acknowledgement_type == ACKNOWLEDGEMENT_NORMAL, "Ack left");
349
350 setup_check_result();
351 tmp_check_result->return_code = STATE_OK;
352 tmp_check_result->output = strdup("Back to OK");
353 handle_async_service_check_result(svc1, tmp_check_result);
354 ok(svc1->acknowledgement_type == ACKNOWLEDGEMENT_NONE, "Ack removed");
355
356
357 /* Test case:
358 UP -> DOWN 1/4 -> ack -> DOWN 2/4 -> DOWN 3/4 -> DOWN 4/4 -> UP transition
359 Tests that the ack is not removed on 2nd DOWN, but is on UP
360 */
361 setup_objects(now);
362 host1->current_state = HOST_UP;
363 host1->last_state = HOST_UP;
364 host1->last_hard_state = HOST_UP;
365 host1->state_type = SOFT_STATE;
366 host1->current_attempt = 1;
367 host1->max_attempts = 4;
368 host1->acknowledgement_type = ACKNOWLEDGEMENT_NONE;
369 host1->plugin_output = strdup("");
370 host1->long_plugin_output = strdup("");
371 host1->perf_data = strdup("");
372 host1->host_check_command = strdup("Dummy command required");
373 host1->accept_passive_host_checks = TRUE;
374 passive_host_checks_are_soft = TRUE;
375 setup_check_result();
376
377 tmp_check_result->return_code = STATE_CRITICAL;
378 tmp_check_result->output = strdup("DOWN failure 2");
379 tmp_check_result->check_type = HOST_CHECK_PASSIVE;
380 handle_async_host_check_result_3x(host1, tmp_check_result);
381 ok(host1->acknowledgement_type == ACKNOWLEDGEMENT_NONE, "No ack set");
382 ok(host1->current_attempt == 2, "Attempts right (not sure why this goes into 2 and not 1)") || diag("current_attempt=%d", host1->current_attempt);
383 ok(strcmp(host1->plugin_output, "DOWN failure 2") == 0, "output set") || diag("plugin_output=%s", host1->plugin_output);
384
385 host1->acknowledgement_type = ACKNOWLEDGEMENT_NORMAL;
386
387 tmp_check_result->output = strdup("DOWN failure 3");
388 handle_async_host_check_result_3x(host1, tmp_check_result);
389 ok(host1->acknowledgement_type == ACKNOWLEDGEMENT_NORMAL, "Ack should be retained as in soft state");
390 ok(host1->current_attempt == 3, "Attempts incremented") || diag("current_attempt=%d", host1->current_attempt);
391 ok(strcmp(host1->plugin_output, "DOWN failure 3") == 0, "output set") || diag("plugin_output=%s", host1->plugin_output);
392
393
394 tmp_check_result->output = strdup("DOWN failure 4");
395 handle_async_host_check_result_3x(host1, tmp_check_result);
396 ok(host1->acknowledgement_type == ACKNOWLEDGEMENT_NORMAL, "Ack should be retained as in soft state");
397 ok(host1->current_attempt == 4, "Attempts incremented") || diag("current_attempt=%d", host1->current_attempt);
398 ok(strcmp(host1->plugin_output, "DOWN failure 4") == 0, "output set") || diag("plugin_output=%s", host1->plugin_output);
399
400
401 tmp_check_result->return_code = STATE_OK;
402 tmp_check_result->output = strdup("UP again");
403 handle_async_host_check_result_3x(host1, tmp_check_result);
404 ok(host1->acknowledgement_type == ACKNOWLEDGEMENT_NONE, "Ack reset due to state change");
405 ok(host1->current_attempt == 1, "Attempts reset") || diag("current_attempt=%d", host1->current_attempt);
406 ok(strcmp(host1->plugin_output, "UP again") == 0, "output set") || diag("plugin_output=%s", host1->plugin_output);
407
408
409 return exit_status();
410 }
411
412