X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=blobdiff_plain;ds=sidebyside;f=test%2Fsi95_test.c;h=fb6e7fdaaa8de94651a3c2d145f44f6c2931a018;hb=e2c0690497a2db5659b3e138e4e106d70fee4aab;hp=26b1b21a38d12cc2ec34918abefed32f6a9bfbd0;hpb=0a58458afe875798f0ac3f367bd05e4ba523e115;p=ric-plt%2Flib%2Frmr.git diff --git a/test/si95_test.c b/test/si95_test.c index 26b1b21..fb6e7fd 100644 --- a/test/si95_test.c +++ b/test/si95_test.c @@ -1,8 +1,8 @@ // :vi sw=4 ts=4 noet: /* ================================================================================== - Copyright (c) 2020 Nokia - Copyright (c) 2020 AT&T Intellectual Property. + Copyright (c) 2020-2021 Nokia + Copyright (c) 2020-2021 AT&T Intellectual Property. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ /* Mmemonic: si95_test.c Abstract: This is the main driver to test the si95 core functions - (within rmr/src/si/src/si95). + (within rmr/src/si/src/si95). Author: E. Scott Daniels Date: 6 March 2018 @@ -32,69 +32,88 @@ #include #include #include -#include #include #include - -#include // these four needed for si address tests -#include -#include -#include - - - #include -#include -#include #include -#include -#include #include -#include #include -#include #include + +#include // these four needed for si address tests +#include +#include +#include + #define DEBUG 1 // specific test tools in this directory -#undef NNG_UNDER_TEST // NNG is NOT under test so undefine if set +#undef NNG_UNDER_TEST // NNG is NOT under test so undefine if set #define NO_EMULATION 1 // no emulation of transport functions #define NO_PRIVATE_HEADERS 1 // no rmr_si or rmr_nng headers #define NO_DUMMY_RMR 1 // no msg things + #include "test_support.c" // things like fail_if() +#include "test_transport_em.c" // system/transport emulation (open, close, connect, etc) + +#include +#include + +// ------------- dummy functions to force edge cases when we can --------------------------------------- + +#define SYSTEM_UNDER_TEST 1 // for conditional code /* -#include "rmr.h" // things the users see -#include "rmr_symtab.h" -#include "rmr_agnostic.h" // transport agnostic header + These are global so they can be reset for individual tests. */ -#include -#include +static int good_mallocs = 0; // number of initial good malocs before failurs +static int bad_mallocs = 1; // number of failed mallocs (consecutive) + +static void* test_malloc( size_t n ) { + + fprintf( stderr, ">>>> test malloc: %d %d\n", good_mallocs, bad_mallocs ); + if( good_mallocs ) { + good_mallocs--; + return malloc( n ); + } + + if( bad_mallocs ) { + bad_mallocs--; + errno = ENOMEM; + return NULL; + } + + return malloc( n ); +} + +// ----------------------------------------------------------------------------------------------------- #include //#include -//#include -//#include -//#include -//#include +#include +#include +#include +#include #include #include -//#include -//#include +#include +#include #include -//#include +#include #include -//#include -//#include +#include +#include //#include -//#include -//#include +#include +#include #include #include #include -//#include +#define malloc test_malloc +#include +#undef malloc // --------------------------------------------------------------------- @@ -102,6 +121,20 @@ void* si_ctx = NULL; // a global context might be useful // --------------------------------------------------------------------- +/* + Fake callback to register. +*/ +static int test_cb( void* data ) { + return 0; +} + +/* + Returns error for coverage testing of CB calls +*/ +static int test_cb_err( void* data ) { + return -1; +} + /* Memory allocation/free related tests */ @@ -126,16 +159,16 @@ static int memory( ) { ((struct tp_blk *)ptr)->squeue = iptr; SItrash( TP_BLK, ptr ); } - + ptr = SInew( GI_BLK ); errors += fail_if_nil( ptr, "memory: sinew returned nil when given giblk request" ); SItrash( GI_BLK, ptr ); // GI block cannot be trashed, ensure this (valgind will complain about a leak) + free( ptr ); // we can free GI block only in tests - + fprintf( stderr, " memory module finished with %d errors\n", errors ); return errors; } - /* Test initialisation related things */ @@ -148,19 +181,38 @@ static int init() { SIclr_tflags( si_ctx, 0x00 ); // drive for coverage; no return value from these SIset_tflags( si_ctx, 0x03 ); + fprintf( stderr, " init module finished with %d errors\n", errors ); return errors; } static int cleanup() { int errors = 0; - + if( ! si_ctx ) { + fprintf( stderr, " cleanup has no context to use\n" ); return 0; } - SIconnect( si_ctx, "localhost:43086" ); // ensure context has a tp block to free on shutdown - SIshutdown( si_ctx ); + fprintf( stderr, " cleanup running\n" ); + SIcbstat( si_ctx, SI_RET_UNREG, SI_CB_SECURITY ); + SIcbstat( si_ctx, SI_RET_QUIT, SI_CB_SECURITY ); + + SItp_stats( si_ctx ); // drive for coverage only + SItp_stats( NULL ); + + SIconnect( si_ctx, "127.0.0.1:43086" ); // ensure context has a tp block to free on shutdown + SIshutdown( NULL ); + SIabort( si_ctx ); + + // cleaning up the remaining global resources + struct ginfo_blk *gptr = (struct ginfo_blk*)si_ctx; + SItrash( TP_BLK, gptr->tplist ); + free( gptr->tp_map ); + free( gptr->rbuf ); + free( gptr->cbtab ); + free( si_ctx ); + fprintf( stderr, " cleanup module finished with %d errors\n", errors ); return errors; } @@ -170,39 +222,299 @@ static int cleanup() { static int addr() { int errors = 0; int l; - struct sockaddr* addr; - char buf1[4096]; - char buf2[4096]; - char* dest; + char buf1[4096]; // space to build buffers for xlation + char* hr_addr; // human readable address returned + void* net_addr; // a network address block of some type - addr = (struct sockaddr *) malloc( sizeof( struct sockaddr ) ); /* + struct sockaddr* addr; + addr = (struct sockaddr *) malloc( sizeof( struct sockaddr ) ); + l = SIgenaddr( " [ff02::4]:4567", PF_INET6, IPPROTO_TCP, SOCK_STREAM, &addr ); SIgenaddr( " [ff02::4]:4567", PF_INET6, IPPROTO_TCP, SOCK_STREAM, &addr ); */ - dest = NULL; + l = SIaddress( NULL, NULL, 0 ); + errors += fail_if_true( l != 0, "SIaddress given two null pointers didn't return 0 len" ); + l = SIaddress( buf1, NULL, 0 ); + errors += fail_if_true( l != 0, "SIaddress given null dest pointer didn't return 0 len" ); + l = SIaddress( NULL, (void *) &buf1, 0 ); + errors += fail_if_true( l != 0, "SIaddress given null src pointer didn't return 0 len" ); + + net_addr = NULL; snprintf( buf1, sizeof( buf1 ), " [ff02::5:4001" ); // invalid address, drive leading space eater too - l = SIaddress( buf1, &dest, AC_TOADDR6 ); + l = SIaddress( buf1, (void **) &net_addr, AC_TOADDR6 ); errors += fail_if_true( l > 0, "to addr6 with bad addr convdersion returned valid len" ); - - snprintf( buf1, sizeof( buf1 ), "[ff02::5]:4002" ); // v6 might not be supported so failure is OK here - l=SIaddress( buf1, &dest, AC_TOADDR6 ); - errors += fail_if_true( l < 1, "to addr convdersion failed" ); + free( net_addr ); + + snprintf( buf1, sizeof( buf1 ), "[ff02::5]:4002" ); // v6 might not be supported so failure is OK here; driving for coverage + l = SIaddress( buf1, &net_addr, AC_TOADDR6 ); + if( l > 0 ) { + l = SIaddress( net_addr, (void *) &hr_addr, AC_TODOT ); // convert the address back to hr string + errors += fail_if_true( l < 1, "v6 to dot conversion failed" ); + errors += fail_if_nil( hr_addr, "v6 to dot conversion yields a nil pointer" ); + free( net_addr ); + free( hr_addr ); + } snprintf( buf1, sizeof( buf1 ), "localhost:43086" ); - l = SIaddress( buf1, (void **) &dest, AC_TOADDR ); - errors += fail_if_true( l < 1, "to addr convdersion failed" ); + l = SIaddress( buf1, (void **) &net_addr, AC_TOADDR ); + errors += fail_if_true( l < 1, "v4 to addr conversion failed" ); - snprintf( buf1, sizeof( buf1 ), "localhost:4004" ); - l = SIaddress( buf1, &dest, AC_TODOT ); + l = SIaddress( net_addr, (void *) &hr_addr, AC_TODOT ); // convert the address back to hr string errors += fail_if_true( l < 1, "to dot convdersion failed" ); + errors += fail_if_nil( hr_addr, "v4 to dot conversion yields a nil pointer" ); + free( net_addr ); + free( hr_addr ); + fprintf( stderr, " addr module finished with %d errors\n", errors ); return errors; +} +/* + Prep related tests. These mostly drive cases that aren't driven by "normal" + connect, send, receive tests (e.g. UDP branches). +*/ +static int prep() { + int errors = 0; + void* thing; // the thing that should be returned + + thing = SIlisten_prep( UDP_DEVICE, "localhost:1234", AF_INET ); + errors += fail_if_nil( thing, "listen prep udp returned nil block" ); + SItrash( TP_BLK, thing ); + + thing = SIlisten_prep( UDP_DEVICE, "localhost:1234", 84306 ); // this should fail + errors += fail_not_nil( thing, "listen prep udp returned valid block ptr for bogus family" ); + + thing = SIconn_prep( si_ctx, UDP_DEVICE, "localhost:1234", 84306 ); // again, expect to fail; bogus family + errors += fail_not_nil( thing, "conn prep udp returned valid block ptr for bogus family" ); + + return errors; +} + +/* + Polling/waiting tests. These are difficult at best because of the blocking + nature of things, not to mention needing to have real ports open etc. +*/ +static int poll() { + int errors = 0; + int status; + struct ginfo_blk* dummy; + + + dummy = SIinitialise( 0 ); // get one to fiddle to drive edge cases + dummy->flags |= GIF_SHUTDOWN; // shutdown edge condition + SIpoll( dummy, 1 ); + + free( dummy->tp_map ); + free( dummy->rbuf ); + free( dummy->cbtab ); + + memset( dummy, 0, sizeof( *dummy ) ); // force bad cookie check code to drive + SIpoll( dummy, 1 ); + + free (dummy ); + + status = SIpoll( si_ctx, 1 ); + errors += fail_if_true( status != 0, "poll failed" ); + + return errors; } + +/* + Connection oriented tests. +*/ +static int conn( ) { + int errors = 0; + int state; + int cfd = 3; // fd for close + char* buf; + + state = SIconnect( si_ctx, "localhost:4567" ); // driver regular connect + errors += fail_if_true( state < 0, "connect to low port failed" ); + + state = SIconnect( si_ctx, "localhost:43086" ); // drive save connect with good return code + errors += fail_if_true( state < 0, "connect to high port failed" ); + + tpem_set_addr_dup_state( 1 ); // force get sockket name emulation to return a duplicate address + state = SIconnect( si_ctx, "localhost:43086" ); // drive save connect with good return code + errors += fail_if_true( state >= 0, "forced dup connect did not return error" ); + + tpem_set_addr_dup_state( 0 ); // back to normal + tpem_set_conn_state( -1 ); + state = SIconnect( si_ctx, "localhost:4567" ); // driver regular connect + errors += fail_if_true( state >= 0, "connect to low port successful when failure expected" ); + tpem_set_conn_state( 3 ); + + tpem_set_sock_state( 1 ); // make scoket calls fail + state = SIconnect( si_ctx, "localhost:4567" ); // driver regular connect + errors += fail_if_true( state >= 0, "connect to low port successful when socket based failure expected" ); + + tpem_set_sock_state( 0 ); + + state = SIlistener( si_ctx, TCP_DEVICE, "0.0.0.0:4567" ); + errors += fail_if_true( state < 0, "listen failed" ); + + tpem_set_bind_state( 1 ); + state = SIlistener( si_ctx, TCP_DEVICE, "0.0.0.0:4567" ); + errors += fail_if_true( state >= 0, "listen successful when bind error set" ); + tpem_set_bind_state( 0 ); + + SIbldpoll( si_ctx ); // for coverage. no return value and nothing we can check + + state = SIclose( NULL, 0 ); //coverage + errors += fail_if_true( state != SI_ERROR, "close given nil context returned success" ); + + state = SIclose( si_ctx, cfd ); + errors += fail_if_true( state == SI_ERROR, "close given good context and good fd returned error" ); + + state = SIclose( si_ctx, 5000 ); // out of range fd + errors += fail_if_true( state != SI_ERROR, "close given good context and bad fd returned success" ); + + state = SIclose( si_ctx, TCP_LISTEN_PORT ); // close listener + errors += fail_if_true( state == SI_ERROR, "close given good context and listener fd returned error" ); + + state = SIclose( si_ctx, UDP_PORT ); // close first open udp port (should not be there) + errors += fail_if_true( state != SI_ERROR, "close given good context and udp generic fd returned error" ); + + buf = SIgetname( 3 ); + if( fail_if_true( buf == NULL, "get name failed to return a buffer" ) ) { + errors++; + } else { + errors += fail_if_true( buf[0] == 0, "get name returned buf with emtpy string" ); + free( buf ); + } + + buf = SIgetname( -1 ); // invalid fd + errors += fail_not_nil( buf, "get name returned buf with non-emtpy string when given bad fd" ); + + fprintf( stderr, " conn module finished with %d errors\n", errors ); + return errors; +} + +/* + Misc tests that just don't fit in another bucket. +*/ +static int misc( ) { + int errors = 0; + char buf[1024]; + + SIcbreg( NULL, SI_CB_SECURITY, test_cb, NULL ); // coverage only, no return value no verification + SIcbreg( si_ctx, SI_CB_SECURITY, test_cb, NULL ); + + buf[0] = 0; + SIgetaddr( si_ctx, buf ); + errors += fail_if_true( buf[0] == 0, "get address failed" ); + fprintf( stderr, " get address returns (%s)\n", buf ); + + fprintf( stderr, " misc module finished with %d errors\n", errors ); + return errors; +} + + +/* + New session (accept) testing. +*/ +static int new_sess( ) { + int errors = 0; + char buf[1024]; + struct tp_blk *tpptr; + int status; + + tpptr = SInew( TP_BLK ); + tpptr->fd = 3; + tpptr->flags |= TPF_LISTENFD; + + tpem_set_accept_fd( -1 ); // accept will "fail" for coverage + status = SInewsession( si_ctx, tpptr ); + errors += fail_if_true( status != SI_ERROR, "newsession did not fail when accept fails" ); + + tpem_set_accept_fd( 5 ); // accept will return a good fd + SIcbreg( si_ctx, SI_CB_SECURITY, test_cb_err, NULL ); // register error and drive new session for error coverage + status = SInewsession( si_ctx, tpptr ); + errors += fail_if_true( status >= 0, "newsession did failed when accept was good" ); + + tpem_set_accept_fd( 6 ); // accept will return a good fd + SIset_tflags( si_ctx, SI_TF_NODELAY | SI_TF_FASTACK ); // flip options for coverage in new sess + SIcbreg( si_ctx, SI_CB_CONN, test_cb, NULL ); // drive connection for coverage + SIcbreg( si_ctx, SI_CB_SECURITY, test_cb, NULL ); + status = SInewsession( si_ctx, tpptr ); + errors += fail_if_true( status < 0, "newsession did failed when accept was good" ); + + free( tpptr ); + + fprintf( stderr, " new_sess module finished with %d errors\n", errors ); + return errors; +} + +/* + Send tests +*/ +static int send_tests( ) { + int errors = 0; + char buf[1024]; + int len; + int state; + + len = snprintf( buf, 100, "Heaven knows I'm miserable now!" ); + + state = SIsendt( si_ctx, 9999, buf, len ); + errors += fail_if_true( state >= 0, "send given fd out of range did not fail" ); + + state = SIsendt( si_ctx, -1, buf, len ); + errors += fail_if_true( state >= 0, "send given neg fd did not fail" ); + + SIsendt( si_ctx, 6, buf, len ); + + tpem_set_send_err( 99 ); + SIsendt( si_ctx, 6, buf, len ); + + tpem_set_send_err( 0 ); + tpem_set_sel_blk( 1 ); + SIsendt( si_ctx, 6, buf, len ); + + tpem_set_sel_blk( 0 ); + tpem_set_selef_fd( 6 ); // will cause send to fail and fd6 to close + SIsendt( si_ctx, 6, buf, len ); + + return errors; +} + + +/* + Wait testing. This is tricky because we don't have any sessions and thus it's difficult + to drive much of SIwait(). +*/ +static int wait_tests() { + int errors = 0; + struct ginfo_blk* dummy; + + + dummy = SIinitialise( 0 ); // get one to fiddle to drive edge cases + SIwait( dummy ); // malloc should "fail" + + dummy->flags |= GIF_SHUTDOWN; + SIwait( dummy ); + + free( dummy->tp_map ); + free( dummy->rbuf ); + free( dummy->cbtab ); + + memset( dummy, 0, sizeof( *dummy ) ); // force bad cookie check code to drive + SIwait( dummy ); + + free( dummy ); + + + SIwait( si_ctx ); // should drive once through the loop + + return errors; +} + +// ---------------------------------------------------------------------------------------- + /* Drive tests... */ @@ -216,10 +528,19 @@ int main() { errors += init(); errors += memory(); errors += addr(); -fprintf( stderr, ">>> cleaning\n" ); + errors += prep(); + errors += conn(); + errors += misc(); + + errors += new_sess(); // should leave a "connected" session at fd == 6 + errors += send_tests(); + + errors += poll(); + errors += wait_tests(); + errors += cleanup(); - fprintf( stderr, " testing finished\n" ); + test_summary( errors, "SI95 tests" ); if( errors == 0 ) { fprintf( stderr, " all tests were OK\n\n" ); } else {