/* * test_handlers.c * * Basic tests for POSIX OS handlers. * * Author: MontaVista Software, Inc. * Corey Minyard * source@mvista.com * * Copyright 2006 MontaVista Software Inc. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * Lesser General Public License (GPL) Version 2 or the modified BSD * license below. The following disclamer applies to both licenses: * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * GNU Lesser General Public Licence * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Modified BSD Licence * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior * written permission. */ #include #include #include #include #include #include os_handler_t *test_os_hnd; static void err_leave(int err, char *format, ...) { va_list ap; va_start(ap, format); vfprintf(stderr, format, ap); if (err) fprintf(stderr, "error: %s (%d)\n", strerror(err), err); va_end(ap); exit(1); } int expect_log = 0; static void my_vlog(os_handler_t *handler, const char *format, enum ipmi_log_type_e log_type, va_list ap) { if (expect_log == 0) { int ival; char *sval; expect_log++; if (strcmp(format, "This is a test: %d %s") != 0) err_leave(0, "Wrong format\n"); if (log_type != IPMI_LOG_FATAL) err_leave(0, "Invalid log type\n"); ival = va_arg(ap, int); if (ival != 47) err_leave(0, "Invalid log int val\n"); sval = va_arg(ap, char *); if (strcmp(sval, "Hello") != 0) err_leave(0, "Invalid log string val\n"); } else { vfprintf(stderr, format, ap); err_leave(0, "Unexpected log!\n"); } } static inline void diff_timeval(struct timeval *dest, struct timeval *left, struct timeval *right) { if ( (left->tv_sec < right->tv_sec) || ( (left->tv_sec == right->tv_sec) && (left->tv_usec < right->tv_usec))) { /* If left < right, just force to zero, don't allow negative numbers. */ dest->tv_sec = 0; dest->tv_usec = 0; return; } dest->tv_sec = left->tv_sec - right->tv_sec; dest->tv_usec = left->tv_usec - right->tv_usec; while (dest->tv_usec < 0) { dest->tv_usec += 1000000; dest->tv_sec--; } } os_handler_waiter_t *timer_waiter; int expect_timeout = 0; static void timeout_handler(void *cb_data, os_hnd_timer_id_t *id) { struct timeval *then = cb_data; struct timeval now; struct timeval diff; fprintf(stderr, "Timeout!\n"); test_os_hnd->get_monotonic_time(test_os_hnd, &now); diff_timeval(&diff, &now, then); if (expect_timeout == 0) { expect_timeout++; if (diff.tv_sec != 1) err_leave(0, "Invalid timeout diff 0: %ld %ld\n", diff.tv_sec, diff.tv_usec); diff.tv_sec = 0; diff.tv_usec = 500000; *then = now; test_os_hnd->start_timer(test_os_hnd, id, &diff, timeout_handler, then); } else if (expect_timeout == 1) { expect_timeout++; if (diff.tv_sec != 0) err_leave(0, "Invalid timeout diff 1: %ld %ld\n", diff.tv_sec, diff.tv_usec); os_handler_waiter_release(timer_waiter); } else { err_leave(0, "Unexpected timeout!\n"); } } static void test_os_handler(os_handler_t *os_hnd, os_handler_waiter_factory_t *factory) { os_hnd_timer_id_t *timer; struct timeval now; struct timeval tv; int rv; test_os_hnd = os_hnd; /* Override the default log handler (so I can catch them). */ os_hnd->set_log_handler(os_hnd, my_vlog); fprintf(stderr, "Log test\n"); os_hnd->log(os_hnd, IPMI_LOG_FATAL, "This is a test: %d %s", 47, "Hello"); fprintf(stderr, "Timer test\n"); timer_waiter = os_handler_alloc_waiter(factory); if (!timer_waiter) err_leave(0, "Unable to allocate waiter\n"); rv = os_hnd->alloc_timer(os_hnd, &timer); if (rv) err_leave(rv, "Unable to allocate timer"); os_hnd->get_monotonic_time(os_hnd, &now); tv.tv_sec = 1; tv.tv_usec = 500000; rv = os_hnd->start_timer(os_hnd, timer, &tv, timeout_handler, &now); tv.tv_sec = 3; tv.tv_usec = 0; os_handler_waiter_wait(timer_waiter, &tv); if (expect_timeout != 2) err_leave(0, "Error in timers: %d\n", expect_timeout); os_handler_free_waiter(timer_waiter); rv = os_handler_free_waiter_factory(factory); if (rv) err_leave(rv, "Error freeing factory\n"); os_handler_global_shutdown(); os_hnd->free_os_handler(os_hnd); } static void reset_tests(void) { expect_log = 0; expect_timeout = 0; } int ipmi_malloc_init(os_handler_t *os_hnd); int main(int argc, char *argv[]) { os_handler_waiter_factory_t *factory; os_handler_t *os_hnd; int rv; fprintf(stderr, "*** Testing POSIX OS handler\n"); reset_tests(); os_hnd = ipmi_posix_setup_os_handler(); if (!os_hnd) { fprintf(stderr, "ipmi_smi_setup_con: Unable to allocate os handler\n"); exit(1); } ipmi_malloc_init(os_hnd); rv = os_handler_alloc_waiter_factory(os_hnd, 2, 0, &factory); if (rv != ENOSYS) err_leave(rv, "Expected ENOSYS allocating threaded factory\n"); rv = os_handler_alloc_waiter_factory(os_hnd, 0, 0, &factory); if (rv) err_leave(rv, "Unable to allocate waiter factory\n"); test_os_handler(os_hnd, factory); fprintf(stderr, "*** Testing POSIX Threaded OS handler (singlethread)\n"); reset_tests(); os_hnd = ipmi_posix_thread_setup_os_handler(SIGUSR1); if (!os_hnd) { fprintf(stderr, "ipmi_smi_setup_con: Unable to allocate os handler\n"); exit(1); } ipmi_malloc_init(os_hnd); rv = os_handler_alloc_waiter_factory(os_hnd, 2, 0, &factory); if (rv) err_leave(rv, "Unable to allocate waiter factory\n"); test_os_handler(os_hnd, factory); fprintf(stderr, "*** Testing POSIX Threaded OS handler (multithread)\n"); reset_tests(); os_hnd = ipmi_posix_thread_setup_os_handler(SIGUSR1); if (!os_hnd) { fprintf(stderr, "ipmi_smi_setup_con: Unable to allocate os handler\n"); exit(1); } ipmi_malloc_init(os_hnd); rv = os_handler_alloc_waiter_factory(os_hnd, 0, 0, &factory); if (rv) err_leave(rv, "Unable to allocate waiter factory\n"); test_os_handler(os_hnd, factory); return 0; }