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