From 273a7d557d80b85ebfac3a316de57d857fc9a8d7 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Wilfried=20G=C3=B6esgens?= Date: Sat, 3 Oct 2009 11:45:22 +0000 Subject: [PATCH] * start out a unit test for our buffered I/O; copy bind/accept/select stuff from webcit and strip it down to the bare minimum. --- libcitadel/tests/Makefile.in | 8 +- libcitadel/tests/stringbuf_IO_test.c | 355 +++++++++++++++++++++++++++ 2 files changed, 362 insertions(+), 1 deletion(-) create mode 100644 libcitadel/tests/stringbuf_IO_test.c diff --git a/libcitadel/tests/Makefile.in b/libcitadel/tests/Makefile.in index e222bd0b3..7d24aaa93 100644 --- a/libcitadel/tests/Makefile.in +++ b/libcitadel/tests/Makefile.in @@ -16,7 +16,7 @@ top_builddir=`pwd` # End of configuration section -TARGETS=stringbuf_test +TARGETS=stringbuf_test stringbuf_IO_test all: $(TARGETS) @@ -36,6 +36,12 @@ stringbuf_test: $(LIBOBJS) stringbuf_test.o -o stringbuf_test \ $(LIBS) +stringbuf_IO_test: $(LIBOBJS) stringbuf_IO_test.o + $(CC) $(LDFLAGS) $(LIBOBJS) $(LIBS) \ + stringbuf_IO_test.o \ + -o stringbuf_io_test \ + $(LIBS) + .c.o: $(CC) $(CFLAGS) $(DEFS) -c $< diff --git a/libcitadel/tests/stringbuf_IO_test.c b/libcitadel/tests/stringbuf_IO_test.c new file mode 100644 index 000000000..1097b960d --- /dev/null +++ b/libcitadel/tests/stringbuf_IO_test.c @@ -0,0 +1,355 @@ + +/* + * CUnit - A Unit testing framework library for C. + * Copyright (C) 2001 Anil Kumar + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#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 + + +typedef void testfunc(int Sock); + +#define LISTEN_QUEUE_LENGTH 100 +#include + +#include "stringbuf_test.h" +#include "../lib/libcitadel.h" + +int msock; /* master listening socket */ +int BindPort; +int time_to_die=0; +int listen_port=6666; +int n_Lines_to_read = 0; +int blobsize = 0; +int timeout = 5; +int selres = 1; +char ip_addr[256]="0.0.0.0"; + + +static void TestRevalidateStrBuf(StrBuf *Buf) +{ + CU_ASSERT(strlen(ChrPtr(Buf)) == StrLength(Buf)); +} + +/* + * This is a generic function to set up a master socket for listening on + * a TCP port. The server shuts down if the bind fails. + * + * ip_addr IP address to bind + * port_number port number to bind + * queue_len number of incoming connections to allow in the queue + */ +static int ig_tcp_server(char *ip_addr, int port_number, int queue_len) +{ + struct protoent *p; + struct sockaddr_in sin; + int s, i; + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + if (ip_addr == NULL) { + sin.sin_addr.s_addr = INADDR_ANY; + } else { + sin.sin_addr.s_addr = inet_addr(ip_addr); + } + + if (sin.sin_addr.s_addr == INADDR_NONE) { + sin.sin_addr.s_addr = INADDR_ANY; + } + + if (port_number == 0) { + printf("Cannot start: no port number specified.\n"); + return (-1); + } + sin.sin_port = htons((u_short) port_number); + + p = getprotobyname("tcp"); + + s = socket(PF_INET, SOCK_STREAM, (p->p_proto)); + if (s < 0) { + printf("Can't create a socket: %s\n", strerror(errno)); + return (-2); + } + /* Set some socket options that make sense. */ + i = 1; + setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)); + + #ifndef __APPLE__ + fcntl(s, F_SETFL, O_NONBLOCK); /* maide: this statement is incorrect + there should be a preceding F_GETFL + and a bitwise OR with the previous + fd flags */ + #endif + + if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) { + printf("Can't bind: %s\n", strerror(errno)); + return (-3); + } + if (listen(s, queue_len) < 0) { + printf("Can't listen: %s\n", strerror(errno)); + return (-4); + } + return (s); +} + + + +/* + * Entry point for worker threads + */ +static void worker_entry(testfunc F) +{ + int ssock; + int i = 0; + int fail_this_transaction = 0; + int ret; + struct timeval tv; + fd_set readset, tempset; + + + tv.tv_sec = 0; + tv.tv_usec = 10000; + FD_ZERO(&readset); + FD_SET(msock, &readset); + + do { + /* Only one thread can accept at a time */ + fail_this_transaction = 0; + ssock = -1; + errno = EAGAIN; + do { + ret = -1; /* just one at once should select... */ + + FD_ZERO(&tempset); + if (msock > 0) FD_SET(msock, &tempset); + tv.tv_sec = 0; + tv.tv_usec = 10000; + if (msock > 0) + ret = select(msock+1, &tempset, NULL, NULL, &tv); + if ((ret < 0) && (errno != EINTR) && (errno != EAGAIN)) + {/* EINTR and EAGAIN are thrown but not of interest. */ + printf("accept() failed:%d %s\n", + errno, strerror(errno)); + } + else if ((ret > 0) && (msock > 0) && FD_ISSET(msock, &tempset)) + {/* Successfully selected, and still not shutting down? Accept! */ + ssock = accept(msock, NULL, 0); + } + + } while ((msock > 0) && (ssock < 0) && (time_to_die == 0)); + + if ((msock == -1)||(time_to_die)) + {/* ok, we're going down. */ + exit(0); + } + if (ssock < 0 ) continue; + + if (msock < 0) { + if (ssock > 0) close (ssock); + printf( "inbetween."); + return; + } else { /* Got it? do some real work! */ + /* Set the SO_REUSEADDR socket option */ + int fdflags; + i = 1; + setsockopt(ssock, SOL_SOCKET, SO_REUSEADDR, + &i, sizeof(i)); + + fdflags = fcntl(ssock, F_GETFL); + if (fdflags < 0) + printf("unable to get server socket flags! %s \n", + strerror(errno)); + fdflags = fdflags | O_NONBLOCK; + if (fcntl(ssock, F_SETFL, fdflags) < 0) + printf("unable to set server socket nonblocking flags! %s \n", + strerror(errno)); + + + F(ssock); + } + + } while (!time_to_die); + printf ("bye\n"); +} + + +static void SimpleLineBufTestFunc(int sock) +{ + StrBuf *ReadBuffer; + StrBuf *Line; + const char *Pos = NULL; + const char *err; + int i; + + ReadBuffer = NewStrBuf(); + Line = NewStrBuf(); + + for (i = 0; i < n_Lines_to_read; i++) { + StrBufTCP_read_buffered_line_fast(Line, + ReadBuffer, + &Pos, + &sock, + timeout, + selres, + &err); + if (err != NULL) + printf("%s", err); + CU_ASSERT_PTR_NOT_NULL(err); + CU_ASSERT_NOT_EQUAL(sock, -1); + if (sock == -1) + break; + printf("LINE: >%s<\n", ChrPtr(Line)); + } + FreeStrBuf(&ReadBuffer); + FreeStrBuf(&Line); + time_to_die = 1; +} + + +static void SimpleLinebufferTest(void) +{ + msock = ig_tcp_server(ip_addr, listen_port, LISTEN_QUEUE_LENGTH); + + worker_entry(SimpleLineBufTestFunc); +} + +/* +Some samples from the original... + CU_ASSERT_EQUAL(10, 10); + CU_ASSERT_EQUAL(0, -0); + CU_ASSERT_EQUAL(-12, -12); + CU_ASSERT_NOT_EQUAL(10, 11); + CU_ASSERT_NOT_EQUAL(0, -1); + CU_ASSERT_NOT_EQUAL(-12, -11); + CU_ASSERT_PTR_EQUAL((void*)0x100, (void*)0x100); + CU_ASSERT_PTR_NOT_EQUAL((void*)0x100, (void*)0x101); + CU_ASSERT_PTR_NULL(NULL); + CU_ASSERT_PTR_NULL(0x0); + CU_ASSERT_PTR_NOT_NULL((void*)0x23); + CU_ASSERT_STRING_EQUAL(str1, str2); + CU_ASSERT_STRING_NOT_EQUAL(str1, str2); + CU_ASSERT_NSTRING_EQUAL(str1, str2, strlen(str1)); + CU_ASSERT_NSTRING_EQUAL(str1, str1, strlen(str1)); + CU_ASSERT_NSTRING_EQUAL(str1, str1, strlen(str1) + 1); + CU_ASSERT_NSTRING_NOT_EQUAL(str1, str2, 3); + CU_ASSERT_NSTRING_NOT_EQUAL(str1, str3, strlen(str1) + 1); + CU_ASSERT_DOUBLE_EQUAL(10, 10.0001, 0.0001); + CU_ASSERT_DOUBLE_EQUAL(10, 10.0001, -0.0001); + CU_ASSERT_DOUBLE_EQUAL(-10, -10.0001, 0.0001); + CU_ASSERT_DOUBLE_EQUAL(-10, -10.0001, -0.0001); + CU_ASSERT_DOUBLE_NOT_EQUAL(10, 10.001, 0.0001); + CU_ASSERT_DOUBLE_NOT_EQUAL(10, 10.001, -0.0001); + CU_ASSERT_DOUBLE_NOT_EQUAL(-10, -10.001, 0.0001); + CU_ASSERT_DOUBLE_NOT_EQUAL(-10, -10.001, -0.0001); +*/ + + + + + +static void AddStrBufSimlpeTests(void) +{ + CU_pSuite pGroup = NULL; + CU_pTest pTest = NULL; + + pGroup = CU_add_suite("TestStringBufSimpleAppenders", NULL, NULL); + pTest = CU_add_test(pGroup, "testSimpleLinebufferTest", SimpleLinebufferTest); + + +} + + +int main(int argc, char* argv[]) +{ + char a; + setvbuf(stdout, NULL, _IONBF, 0); + + + while ((a = getopt(argc, argv, "p:i:n:b:t:s")) != EOF) + { + switch (a) { + + case 'p': + listen_port = atoi(optarg); + break; + case 'i': + safestrncpy(ip_addr, optarg, sizeof ip_addr); + break; + case 'n': + n_Lines_to_read = atoi(optarg); + break; + case 'b': + blobsize = atoi(optarg); + break; + case 't': + timeout = atoi(optarg); + break; + case 's': + selres = atoi(optarg); + break; + } + } + + + StartLibCitadel(8); + CU_BOOL Run = CU_FALSE ; + + CU_set_output_filename("TestAutomated"); + if (CU_initialize_registry()) { + printf("\nInitialize of test Registry failed."); + } + + Run = CU_TRUE ; + AddStrBufSimlpeTests(); + + if (CU_TRUE == Run) { + //CU_console_run_tests(); + printf("\nTests completed with return value %d.\n", CU_basic_run_tests()); + + ///CU_automated_run_tests(); + } + + CU_cleanup_registry(); + + return 0; +} -- 2.30.2