This source file includes following definitions.
- mode_cb
- mainloop_test_done
- dispatch_helper
- st_callback
- st_global_callback
- passive_test
- run_fence_failure_test
- run_fence_failure_rollover_test
- run_standard_test
- sanity_tests
- standard_dev_test
- mainloop_callback
- register_callback_helper
- test_async_fence_pass
- test_async_fence_custom_timeout
- test_async_fence_timeout
- test_async_monitor
- test_register_async_devices
- try_mainloop_connect
- iterate_mainloop_tests
- trigger_iterate_mainloop_tests
- test_shutdown
- mainloop_tests
- build_arg_context
- main
1
2
3
4
5
6
7
8 #include <crm_internal.h>
9
10 #include <sys/param.h>
11 #include <stdio.h>
12 #include <sys/time.h>
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <unistd.h>
16 #include <sys/utsname.h>
17
18 #include <stdlib.h>
19 #include <errno.h>
20 #include <fcntl.h>
21
22 #include <crm/crm.h>
23 #include <crm/msg_xml.h>
24 #include <crm/common/ipc.h>
25 #include <crm/cluster/internal.h>
26
27 #include <crm/stonith-ng.h>
28 #include <crm/fencing/internal.h>
29 #include <crm/common/agents.h>
30 #include <crm/common/cmdline_internal.h>
31 #include <crm/common/xml.h>
32
33 #include <crm/common/mainloop.h>
34
35 #define SUMMARY "cts-fence-helper - inject commands into the Pacemaker fencer and watch for events"
36
37 static GMainLoop *mainloop = NULL;
38 static crm_trigger_t *trig = NULL;
39 static int mainloop_iter = 0;
40 static pcmk__action_result_t result = PCMK__UNKNOWN_RESULT;
41
42 typedef void (*mainloop_test_iteration_cb) (int check_event);
43
44 #define MAINLOOP_DEFAULT_TIMEOUT 2
45
46 enum test_modes {
47 test_standard = 0,
48 test_passive,
49 test_api_sanity,
50 test_api_mainloop,
51 };
52
53 struct {
54 enum test_modes mode;
55 } options = {
56 .mode = test_standard
57 };
58
59 static gboolean
60 mode_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
61 if (pcmk__str_any_of(option_name, "--mainloop_api_test", "-m", NULL)) {
62 options.mode = test_api_mainloop;
63 } else if (pcmk__str_any_of(option_name, "--api_test", "-t", NULL)) {
64 options.mode = test_api_sanity;
65 } else if (pcmk__str_any_of(option_name, "--passive", "-p", NULL)) {
66 options.mode = test_passive;
67 }
68
69 return TRUE;
70 }
71
72 static GOptionEntry entries[] = {
73 { "mainloop_api_test", 'm', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, mode_cb,
74 NULL, NULL,
75 },
76
77 { "api_test", 't', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, mode_cb,
78 NULL, NULL,
79 },
80
81 { "passive", 'p', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, mode_cb,
82 NULL, NULL,
83 },
84
85 { NULL }
86 };
87
88 static stonith_t *st = NULL;
89 static struct pollfd pollfd;
90 static const int st_opts = st_opt_sync_call;
91 static int expected_notifications = 0;
92 static int verbose = 0;
93
94 static void
95 mainloop_test_done(const char *origin, bool pass)
96 {
97 if (pass) {
98 crm_info("SUCCESS - %s", origin);
99 mainloop_iter++;
100 mainloop_set_trigger(trig);
101 result.execution_status = PCMK_EXEC_DONE;
102 result.exit_status = CRM_EX_OK;
103 } else {
104 crm_err("FAILURE - %s (%d: %s)", origin, result.exit_status,
105 pcmk_exec_status_str(result.execution_status));
106 crm_exit(CRM_EX_ERROR);
107 }
108 }
109
110
111 static void
112 dispatch_helper(int timeout)
113 {
114 int rc;
115
116 crm_debug("Looking for notification");
117 pollfd.events = POLLIN;
118 while (true) {
119 rc = poll(&pollfd, 1, timeout);
120 if (rc > 0) {
121 if (!stonith_dispatch(st)) {
122 break;
123 }
124 } else {
125 break;
126 }
127 }
128 }
129
130 static void
131 st_callback(stonith_t * st, stonith_event_t * e)
132 {
133 char *desc = NULL;
134
135 if (st->state == stonith_disconnected) {
136 crm_exit(CRM_EX_DISCONNECT);
137 }
138
139 desc = stonith__event_description(e);
140 crm_notice("%s", desc);
141 free(desc);
142
143 if (expected_notifications) {
144 expected_notifications--;
145 }
146 }
147
148 static void
149 st_global_callback(stonith_t * stonith, stonith_callback_data_t * data)
150 {
151 crm_notice("Call %d exited %d: %s (%s)",
152 data->call_id, stonith__exit_status(data),
153 stonith__execution_status(data),
154 pcmk__s(stonith__exit_reason(data), "unspecified reason"));
155 }
156
157 static void
158 passive_test(void)
159 {
160 int rc = 0;
161
162 rc = st->cmds->connect(st, crm_system_name, &pollfd.fd);
163 if (rc != pcmk_ok) {
164 stonith_api_delete(st);
165 crm_exit(CRM_EX_DISCONNECT);
166 }
167 st->cmds->register_notification(st, T_STONITH_NOTIFY_DISCONNECT, st_callback);
168 st->cmds->register_notification(st, T_STONITH_NOTIFY_FENCE, st_callback);
169 st->cmds->register_notification(st, STONITH_OP_DEVICE_ADD, st_callback);
170 st->cmds->register_notification(st, STONITH_OP_DEVICE_DEL, st_callback);
171 st->cmds->register_callback(st, 0, 120, st_opt_timeout_updates, NULL, "st_global_callback",
172 st_global_callback);
173
174 dispatch_helper(600 * 1000);
175 }
176
177 #define single_test(cmd, str, num_notifications, expected_rc) \
178 { \
179 int rc = 0; \
180 rc = cmd; \
181 expected_notifications = 0; \
182 if (num_notifications) { \
183 expected_notifications = num_notifications; \
184 dispatch_helper(500); \
185 } \
186 if (rc != expected_rc) { \
187 crm_err("FAILURE - expected rc %d != %d(%s) for cmd - %s", expected_rc, rc, pcmk_strerror(rc), str); \
188 crm_exit(CRM_EX_ERROR); \
189 } else if (expected_notifications) { \
190 crm_err("FAILURE - expected %d notifications, got only %d for cmd - %s", \
191 num_notifications, num_notifications - expected_notifications, str); \
192 crm_exit(CRM_EX_ERROR); \
193 } else { \
194 if (verbose) { \
195 crm_info("SUCCESS - %s: %d", str, rc); \
196 } else { \
197 crm_debug("SUCCESS - %s: %d", str, rc); \
198 } \
199 } \
200 }\
201
202 static void
203 run_fence_failure_test(void)
204 {
205 stonith_key_value_t *params = NULL;
206
207 params = stonith_key_value_add(params, PCMK_STONITH_HOST_MAP,
208 "false_1_node1=1,2 false_1_node2=3,4");
209 params = stonith_key_value_add(params, "mode", "fail");
210
211 single_test(st->
212 cmds->register_device(st, st_opts, "test-id1", "stonith-ng", "fence_dummy", params),
213 "Register device1 for failure test", 1, 0);
214
215 single_test(st->cmds->fence(st, st_opts, "false_1_node2", PCMK_ACTION_OFF,
216 3, 0),
217 "Fence failure results off", 1, -ENODATA);
218
219 single_test(st->cmds->fence(st, st_opts, "false_1_node2",
220 PCMK_ACTION_REBOOT, 3, 0),
221 "Fence failure results reboot", 1, -ENODATA);
222
223 single_test(st->cmds->remove_device(st, st_opts, "test-id1"),
224 "Remove device1 for failure test", 1, 0);
225
226 stonith_key_value_freeall(params, 1, 1);
227 }
228
229 static void
230 run_fence_failure_rollover_test(void)
231 {
232 stonith_key_value_t *params = NULL;
233
234 params = stonith_key_value_add(params, PCMK_STONITH_HOST_MAP,
235 "false_1_node1=1,2 false_1_node2=3,4");
236 params = stonith_key_value_add(params, "mode", "fail");
237
238 single_test(st->
239 cmds->register_device(st, st_opts, "test-id1", "stonith-ng", "fence_dummy", params),
240 "Register device1 for rollover test", 1, 0);
241 stonith_key_value_freeall(params, 1, 1);
242 params = NULL;
243 params = stonith_key_value_add(params, PCMK_STONITH_HOST_MAP,
244 "false_1_node1=1,2 false_1_node2=3,4");
245 params = stonith_key_value_add(params, "mode", "pass");
246
247 single_test(st->
248 cmds->register_device(st, st_opts, "test-id2", "stonith-ng", "fence_dummy", params),
249 "Register device2 for rollover test", 1, 0);
250
251 single_test(st->cmds->fence(st, st_opts, "false_1_node2", PCMK_ACTION_OFF,
252 3, 0),
253 "Fence rollover results off", 1, 0);
254
255
256 single_test(st->cmds->fence(st, st_opts, "false_1_node2", PCMK_ACTION_ON, 3,
257 0),
258 "Fence rollover results on", 1, -ENODEV);
259
260 single_test(st->cmds->remove_device(st, st_opts, "test-id1"),
261 "Remove device1 for rollover tests", 1, 0);
262
263 single_test(st->cmds->remove_device(st, st_opts, "test-id2"),
264 "Remove device2 for rollover tests", 1, 0);
265
266 stonith_key_value_freeall(params, 1, 1);
267 }
268
269 static void
270 run_standard_test(void)
271 {
272 stonith_key_value_t *params = NULL;
273
274 params = stonith_key_value_add(params, PCMK_STONITH_HOST_MAP,
275 "false_1_node1=1,2 false_1_node2=3,4");
276 params = stonith_key_value_add(params, "mode", "pass");
277 params = stonith_key_value_add(params, "mock_dynamic_hosts", "false_1_node1 false_1_node2");
278
279 single_test(st->
280 cmds->register_device(st, st_opts, "test-id", "stonith-ng", "fence_dummy", params),
281 "Register", 1, 0);
282 stonith_key_value_freeall(params, 1, 1);
283 params = NULL;
284
285 single_test(st->cmds->list(st, st_opts, "test-id", NULL, 1),
286 PCMK_ACTION_LIST, 1, 0);
287
288 single_test(st->cmds->monitor(st, st_opts, "test-id", 1), "Monitor", 1, 0);
289
290 single_test(st->cmds->status(st, st_opts, "test-id", "false_1_node2", 1),
291 "Status false_1_node2", 1, 0);
292
293 single_test(st->cmds->status(st, st_opts, "test-id", "false_1_node1", 1),
294 "Status false_1_node1", 1, 0);
295
296 single_test(st->cmds->fence(st, st_opts, "unknown-host", PCMK_ACTION_OFF,
297 1, 0),
298 "Fence unknown-host (expected failure)", 0, -ENODEV);
299
300 single_test(st->cmds->fence(st, st_opts, "false_1_node1", PCMK_ACTION_OFF,
301 1, 0),
302 "Fence false_1_node1", 1, 0);
303
304
305 single_test(st->cmds->fence(st, st_opts, "false_1_node1", PCMK_ACTION_ON, 1,
306 0),
307 "Unfence false_1_node1", 1, -ENODEV);
308
309
310 single_test(st->cmds->register_level(st, st_opts, "node1", 999, params),
311 "Attempt to register an invalid level index", 0, -EINVAL);
312
313 single_test(st->cmds->remove_device(st, st_opts, "test-id"), "Remove test-id", 1, 0);
314
315 stonith_key_value_freeall(params, 1, 1);
316 }
317
318 static void
319 sanity_tests(void)
320 {
321 int rc = 0;
322
323 rc = st->cmds->connect(st, crm_system_name, &pollfd.fd);
324 if (rc != pcmk_ok) {
325 stonith_api_delete(st);
326 crm_exit(CRM_EX_DISCONNECT);
327 }
328 st->cmds->register_notification(st, T_STONITH_NOTIFY_DISCONNECT, st_callback);
329 st->cmds->register_notification(st, T_STONITH_NOTIFY_FENCE, st_callback);
330 st->cmds->register_notification(st, STONITH_OP_DEVICE_ADD, st_callback);
331 st->cmds->register_notification(st, STONITH_OP_DEVICE_DEL, st_callback);
332 st->cmds->register_callback(st, 0, 120, st_opt_timeout_updates, NULL, "st_global_callback",
333 st_global_callback);
334
335 crm_info("Starting API Sanity Tests");
336 run_standard_test();
337 run_fence_failure_test();
338 run_fence_failure_rollover_test();
339 crm_info("Sanity Tests Passed");
340 }
341
342 static void
343 standard_dev_test(void)
344 {
345 int rc = 0;
346 char *tmp = NULL;
347 stonith_key_value_t *params = NULL;
348
349 rc = st->cmds->connect(st, crm_system_name, &pollfd.fd);
350 if (rc != pcmk_ok) {
351 stonith_api_delete(st);
352 crm_exit(CRM_EX_DISCONNECT);
353 }
354
355 params = stonith_key_value_add(params, PCMK_STONITH_HOST_MAP,
356 "some-host=pcmk-7 true_1_node1=3,4");
357
358 rc = st->cmds->register_device(st, st_opts, "test-id", "stonith-ng", "fence_xvm", params);
359 crm_debug("Register: %d", rc);
360
361 rc = st->cmds->list(st, st_opts, "test-id", &tmp, 10);
362 crm_debug("List: %d output: %s", rc, tmp ? tmp : "<none>");
363
364 rc = st->cmds->monitor(st, st_opts, "test-id", 10);
365 crm_debug("Monitor: %d", rc);
366
367 rc = st->cmds->status(st, st_opts, "test-id", "false_1_node2", 10);
368 crm_debug("Status false_1_node2: %d", rc);
369
370 rc = st->cmds->status(st, st_opts, "test-id", "false_1_node1", 10);
371 crm_debug("Status false_1_node1: %d", rc);
372
373 rc = st->cmds->fence(st, st_opts, "unknown-host", PCMK_ACTION_OFF, 60, 0);
374 crm_debug("Fence unknown-host: %d", rc);
375
376 rc = st->cmds->status(st, st_opts, "test-id", "false_1_node1", 10);
377 crm_debug("Status false_1_node1: %d", rc);
378
379 rc = st->cmds->fence(st, st_opts, "false_1_node1", PCMK_ACTION_OFF, 60, 0);
380 crm_debug("Fence false_1_node1: %d", rc);
381
382 rc = st->cmds->status(st, st_opts, "test-id", "false_1_node1", 10);
383 crm_debug("Status false_1_node1: %d", rc);
384
385 rc = st->cmds->fence(st, st_opts, "false_1_node1", PCMK_ACTION_ON, 10, 0);
386 crm_debug("Unfence false_1_node1: %d", rc);
387
388 rc = st->cmds->status(st, st_opts, "test-id", "false_1_node1", 10);
389 crm_debug("Status false_1_node1: %d", rc);
390
391 rc = st->cmds->fence(st, st_opts, "some-host", PCMK_ACTION_OFF, 10, 0);
392 crm_debug("Fence alias: %d", rc);
393
394 rc = st->cmds->status(st, st_opts, "test-id", "some-host", 10);
395 crm_debug("Status alias: %d", rc);
396
397 rc = st->cmds->fence(st, st_opts, "false_1_node1", PCMK_ACTION_ON, 10, 0);
398 crm_debug("Unfence false_1_node1: %d", rc);
399
400 rc = st->cmds->remove_device(st, st_opts, "test-id");
401 crm_debug("Remove test-id: %d", rc);
402
403 stonith_key_value_freeall(params, 1, 1);
404 }
405
406 static void
407 iterate_mainloop_tests(gboolean event_ready);
408
409 static void
410 mainloop_callback(stonith_t * stonith, stonith_callback_data_t * data)
411 {
412 pcmk__set_result(&result, stonith__exit_status(data),
413 stonith__execution_status(data),
414 stonith__exit_reason(data));
415 iterate_mainloop_tests(TRUE);
416 }
417
418 static int
419 register_callback_helper(int callid)
420 {
421 return st->cmds->register_callback(st,
422 callid,
423 MAINLOOP_DEFAULT_TIMEOUT,
424 st_opt_timeout_updates, NULL, "callback", mainloop_callback);
425 }
426
427 static void
428 test_async_fence_pass(int check_event)
429 {
430 int rc = 0;
431
432 if (check_event) {
433 mainloop_test_done(__func__, (result.exit_status == CRM_EX_OK));
434 return;
435 }
436
437 rc = st->cmds->fence(st, 0, "true_1_node1", PCMK_ACTION_OFF,
438 MAINLOOP_DEFAULT_TIMEOUT, 0);
439 if (rc < 0) {
440 crm_err("fence failed with rc %d", rc);
441 mainloop_test_done(__func__, false);
442 }
443 register_callback_helper(rc);
444
445 }
446
447 #define CUSTOM_TIMEOUT_ADDITION 10
448 static void
449 test_async_fence_custom_timeout(int check_event)
450 {
451 int rc = 0;
452 static time_t begin = 0;
453
454 if (check_event) {
455 uint32_t diff = (time(NULL) - begin);
456
457 if (result.execution_status != PCMK_EXEC_TIMEOUT) {
458 mainloop_test_done(__func__, false);
459 } else if (diff < CUSTOM_TIMEOUT_ADDITION + MAINLOOP_DEFAULT_TIMEOUT) {
460 crm_err
461 ("Custom timeout test failed, callback expiration should be updated to %d, actual timeout was %d",
462 CUSTOM_TIMEOUT_ADDITION + MAINLOOP_DEFAULT_TIMEOUT, diff);
463 mainloop_test_done(__func__, false);
464 } else {
465 mainloop_test_done(__func__, true);
466 }
467 return;
468 }
469 begin = time(NULL);
470
471 rc = st->cmds->fence(st, 0, "custom_timeout_node1", PCMK_ACTION_OFF,
472 MAINLOOP_DEFAULT_TIMEOUT, 0);
473 if (rc < 0) {
474 crm_err("fence failed with rc %d", rc);
475 mainloop_test_done(__func__, false);
476 }
477 register_callback_helper(rc);
478
479 }
480
481 static void
482 test_async_fence_timeout(int check_event)
483 {
484 int rc = 0;
485
486 if (check_event) {
487 mainloop_test_done(__func__,
488 (result.execution_status == PCMK_EXEC_NO_FENCE_DEVICE));
489 return;
490 }
491
492 rc = st->cmds->fence(st, 0, "false_1_node2", PCMK_ACTION_OFF,
493 MAINLOOP_DEFAULT_TIMEOUT, 0);
494 if (rc < 0) {
495 crm_err("fence failed with rc %d", rc);
496 mainloop_test_done(__func__, false);
497 }
498 register_callback_helper(rc);
499
500 }
501
502 static void
503 test_async_monitor(int check_event)
504 {
505 int rc = 0;
506
507 if (check_event) {
508 mainloop_test_done(__func__, (result.exit_status == CRM_EX_OK));
509 return;
510 }
511
512 rc = st->cmds->monitor(st, 0, "false_1", MAINLOOP_DEFAULT_TIMEOUT);
513 if (rc < 0) {
514 crm_err("monitor failed with rc %d", rc);
515 mainloop_test_done(__func__, false);
516 }
517
518 register_callback_helper(rc);
519
520 }
521
522 static void
523 test_register_async_devices(int check_event)
524 {
525 char buf[16] = { 0, };
526 stonith_key_value_t *params = NULL;
527
528 params = stonith_key_value_add(params, PCMK_STONITH_HOST_MAP,
529 "false_1_node1=1,2");
530 params = stonith_key_value_add(params, "mode", "fail");
531 st->cmds->register_device(st, st_opts, "false_1", "stonith-ng", "fence_dummy", params);
532 stonith_key_value_freeall(params, 1, 1);
533
534 params = NULL;
535 params = stonith_key_value_add(params, PCMK_STONITH_HOST_MAP,
536 "true_1_node1=1,2");
537 params = stonith_key_value_add(params, "mode", "pass");
538 st->cmds->register_device(st, st_opts, "true_1", "stonith-ng", "fence_dummy", params);
539 stonith_key_value_freeall(params, 1, 1);
540
541 params = NULL;
542 params = stonith_key_value_add(params, PCMK_STONITH_HOST_MAP,
543 "custom_timeout_node1=1,2");
544 params = stonith_key_value_add(params, "mode", "fail");
545 params = stonith_key_value_add(params, "delay", "1000");
546 snprintf(buf, sizeof(buf) - 1, "%d", MAINLOOP_DEFAULT_TIMEOUT + CUSTOM_TIMEOUT_ADDITION);
547 params = stonith_key_value_add(params, "pcmk_off_timeout", buf);
548 st->cmds->register_device(st, st_opts, "false_custom_timeout", "stonith-ng", "fence_dummy",
549 params);
550 stonith_key_value_freeall(params, 1, 1);
551
552 mainloop_test_done(__func__, true);
553 }
554
555 static void
556 try_mainloop_connect(int check_event)
557 {
558 int rc = stonith_api_connect_retry(st, crm_system_name, 10);
559
560 if (rc == pcmk_ok) {
561 mainloop_test_done(__func__, true);
562 return;
563 }
564 crm_err("API CONNECTION FAILURE");
565 mainloop_test_done(__func__, false);
566 }
567
568 static void
569 iterate_mainloop_tests(gboolean event_ready)
570 {
571 static mainloop_test_iteration_cb callbacks[] = {
572 try_mainloop_connect,
573 test_register_async_devices,
574 test_async_monitor,
575 test_async_fence_pass,
576 test_async_fence_timeout,
577 test_async_fence_custom_timeout,
578 };
579
580 if (mainloop_iter == (sizeof(callbacks) / sizeof(mainloop_test_iteration_cb))) {
581
582 crm_info("ALL MAINLOOP TESTS PASSED!");
583 crm_exit(CRM_EX_OK);
584 }
585
586 callbacks[mainloop_iter] (event_ready);
587 }
588
589 static gboolean
590 trigger_iterate_mainloop_tests(gpointer user_data)
591 {
592 iterate_mainloop_tests(FALSE);
593 return TRUE;
594 }
595
596 static void
597 test_shutdown(int nsig)
598 {
599 int rc = 0;
600
601 if (st) {
602 rc = st->cmds->disconnect(st);
603 crm_info("Disconnect: %d", rc);
604
605 crm_debug("Destroy");
606 stonith_api_delete(st);
607 }
608
609 if (rc) {
610 crm_exit(CRM_EX_ERROR);
611 }
612 }
613
614 static void
615 mainloop_tests(void)
616 {
617 trig = mainloop_add_trigger(G_PRIORITY_HIGH, trigger_iterate_mainloop_tests, NULL);
618 mainloop_set_trigger(trig);
619 mainloop_add_signal(SIGTERM, test_shutdown);
620
621 crm_info("Starting");
622 mainloop = g_main_loop_new(NULL, FALSE);
623 g_main_loop_run(mainloop);
624 }
625
626 static GOptionContext *
627 build_arg_context(pcmk__common_args_t *args, GOptionGroup **group) {
628 GOptionContext *context = NULL;
629
630 context = pcmk__build_arg_context(args, NULL, group, NULL);
631 pcmk__add_main_args(context, entries);
632 return context;
633 }
634
635 int
636 main(int argc, char **argv)
637 {
638 GError *error = NULL;
639 crm_exit_t exit_code = CRM_EX_OK;
640
641 pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY);
642 gchar **processed_args = pcmk__cmdline_preproc(argv, NULL);
643 GOptionContext *context = build_arg_context(args, NULL);
644
645 if (!g_option_context_parse_strv(context, &processed_args, &error)) {
646 exit_code = CRM_EX_USAGE;
647 goto done;
648 }
649
650
651
652
653
654 crm_log_init(NULL, LOG_INFO, TRUE, (verbose? TRUE : FALSE), argc, argv,
655 FALSE);
656
657 for (int i = 0; i < args->verbosity; i++) {
658 crm_bump_log_level(argc, argv);
659 }
660
661 st = stonith_api_new();
662 if (st == NULL) {
663 exit_code = CRM_EX_DISCONNECT;
664 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
665 "Could not connect to fencer: API memory allocation failed");
666 goto done;
667 }
668
669 switch (options.mode) {
670 case test_standard:
671 standard_dev_test();
672 break;
673 case test_passive:
674 passive_test();
675 break;
676 case test_api_sanity:
677 sanity_tests();
678 break;
679 case test_api_mainloop:
680 mainloop_tests();
681 break;
682 }
683
684 test_shutdown(0);
685
686 done:
687 g_strfreev(processed_args);
688 pcmk__free_arg_context(context);
689
690 pcmk__output_and_clear_error(&error, NULL);
691 crm_exit(exit_code);
692 }