More changes of 'free software' to 'open source' made for the express purpose of...
[citadel.git] / libcitadel / tests / stringbuf_IO_test.c
1 /*
2  *  CUnit - A Unit testing framework library for C.
3  *  Copyright (C) 2001  Anil Kumar
4  *  
5  *  This library is open source software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Library General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2 of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Library General Public License for more details.
14  */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18
19 #include <sys/select.h>
20
21 #include <ctype.h>
22 #include <unistd.h>
23 #include <fcntl.h>
24 #include <signal.h>
25 #include <sys/types.h>
26 #include <sys/wait.h>
27 #include <sys/socket.h>
28 #include <sys/time.h>
29 #include <sys/stat.h>
30 #include <limits.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
33 #include <sys/un.h>
34 #include <netdb.h>
35 #include <sys/poll.h>
36 #include <string.h>
37 #include <pwd.h>
38 #include <errno.h>
39 #include <stdarg.h>
40 #include <pthread.h>
41 #include <signal.h>
42 #include <sys/utsname.h>
43 #include <string.h>
44
45
46 typedef void testfunc(int Sock);
47
48 #define LISTEN_QUEUE_LENGTH 100
49 #include <string.h>
50
51 #include "stringbuf_test.h"
52 #include "../lib/libcitadel.h"
53
54 int msock;                      /* master listening socket */
55 int BindPort;
56 int time_to_die=0;
57 int listen_port=6666;
58 int n_Lines_to_read = 0;
59 int blobsize = 0;
60 int timeout = 5;
61 int selres = 1;
62 char ip_addr[256]="0.0.0.0";
63
64
65 static void TestRevalidateStrBuf(StrBuf *Buf)
66 {
67         CU_ASSERT(strlen(ChrPtr(Buf)) == StrLength(Buf));
68 }
69
70 /* 
71  * This is a generic function to set up a master socket for listening on
72  * a TCP port.  The server shuts down if the bind fails.
73  *
74  * ip_addr      IP address to bind
75  * port_number  port number to bind
76  * queue_len    number of incoming connections to allow in the queue
77  */
78 static int ig_tcp_server(char *ip_addr, int port_number, int queue_len)
79 {
80         struct protoent *p;
81         struct sockaddr_in sin;
82         int s, i;
83
84         memset(&sin, 0, sizeof(sin));
85         sin.sin_family = AF_INET;
86         if (ip_addr == NULL) {
87                 sin.sin_addr.s_addr = INADDR_ANY;
88         } else {
89                 sin.sin_addr.s_addr = inet_addr(ip_addr);
90         }
91
92         if (sin.sin_addr.s_addr == INADDR_NONE) {
93                 sin.sin_addr.s_addr = INADDR_ANY;
94         }
95
96         if (port_number == 0) {
97                 printf("Cannot start: no port number specified.\n");
98                 return (-1);
99         }
100         sin.sin_port = htons((u_short) port_number);
101
102         p = getprotobyname("tcp");
103
104         s = socket(PF_INET, SOCK_STREAM, (p->p_proto));
105         if (s < 0) {
106                 printf("Can't create a socket: %s\n", strerror(errno));
107                 return (-2);
108         }
109         /* Set some socket options that make sense. */
110         i = 1;
111         setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
112
113         #ifndef __APPLE__
114         fcntl(s, F_SETFL, O_NONBLOCK); /* maide: this statement is incorrect
115                                           there should be a preceding F_GETFL
116                                           and a bitwise OR with the previous
117                                           fd flags */
118         #endif
119         
120         if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
121                 printf("Can't bind: %s\n", strerror(errno));
122                 return (-3);
123         }
124         if (listen(s, queue_len) < 0) {
125                 printf("Can't listen: %s\n", strerror(errno));
126                 return (-4);
127         }
128         return (s);
129 }
130
131
132
133 /*
134  * Entry point for worker threads
135  */
136 static void worker_entry(testfunc F)
137 {
138         int ssock;
139         int i = 0;
140         int fail_this_transaction = 0;
141         int ret;
142         struct timeval tv;
143         fd_set readset, tempset;
144
145         
146         tv.tv_sec = 0;
147         tv.tv_usec = 10000;
148         FD_ZERO(&readset);
149         FD_SET(msock, &readset);
150
151         do {
152                 /* Only one thread can accept at a time */
153                 fail_this_transaction = 0;
154                 ssock = -1; 
155                 errno = EAGAIN;
156                 do {
157                         ret = -1; /* just one at once should select... */
158                         
159                         FD_ZERO(&tempset);
160                         if (msock > 0) FD_SET(msock, &tempset);
161                         tv.tv_sec = 0;
162                         tv.tv_usec = 10000;
163                         if (msock > 0)  
164                                 ret = select(msock+1, &tempset, NULL, NULL,  &tv);
165                         if ((ret < 0) && (errno != EINTR) && (errno != EAGAIN))
166                         {/* EINTR and EAGAIN are thrown but not of interest. */
167                                 printf("accept() failed:%d %s\n",
168                                         errno, strerror(errno));
169                         }
170                         else if ((ret > 0) && (msock > 0) && FD_ISSET(msock, &tempset))
171                         {/* Successfully selected, and still not shutting down? Accept! */
172                                 ssock = accept(msock, NULL, 0);
173                         }
174                         
175                 } while ((msock > 0) && (ssock < 0)  && (time_to_die == 0));
176
177                 if ((msock == -1)||(time_to_die))
178                 {/* ok, we're going down. */
179                         return;
180                 }
181                 if (ssock < 0 ) continue;
182
183                 if (msock < 0) {
184                         if (ssock > 0) close (ssock);
185                         printf( "inbetween.");
186                         return;
187                 } else { /* Got it? do some real work! */
188                         /* Set the SO_REUSEADDR socket option */
189                         int fdflags; 
190                         i = 1;
191                         setsockopt(ssock, SOL_SOCKET, SO_REUSEADDR,
192                                    &i, sizeof(i));
193
194                         fdflags = fcntl(ssock, F_GETFL);
195                         if (fdflags < 0)
196                                 printf("unable to get server socket flags! %s \n",
197                                         strerror(errno));
198                         fdflags = fdflags | O_NONBLOCK;
199                         if (fcntl(ssock, F_SETFL, fdflags) < 0)
200                                 printf("unable to set server socket nonblocking flags! %s \n",
201                                         strerror(errno));
202
203
204                         F(ssock);
205                 }
206
207         } while (!time_to_die);
208         printf ("bye\n");
209 }
210
211
212 static void SimpleLineBufTestFunc(int sock)
213 {
214         StrBuf *ReadBuffer;
215         StrBuf *Line;
216         const char *Pos = NULL;
217         const char *err = NULL;
218         int i;
219
220         ReadBuffer = NewStrBuf();
221         Line = NewStrBuf();
222
223         for (i = 0; i < n_Lines_to_read; i++) {
224                 StrBufTCP_read_buffered_line_fast(Line, 
225                                                   ReadBuffer, 
226                                                   &Pos,
227                                                   &sock,
228                                                   timeout,
229                                                   selres,
230                                                   &err);
231                 TestRevalidateStrBuf(Line);
232                 if (err != NULL)
233                         printf("%s", err);
234                 CU_ASSERT_PTR_NULL(err);
235                 CU_ASSERT_NOT_EQUAL(sock, -1);
236                 if (sock == -1)
237                         break;
238                 printf("LINE: >%s<\n", ChrPtr(Line));
239         }
240         FreeStrBuf(&ReadBuffer);
241         FreeStrBuf(&Line);
242         time_to_die = 1;
243 }
244
245 static void SimpleLinebufferTest(void)
246 {
247         msock = ig_tcp_server(ip_addr, listen_port, LISTEN_QUEUE_LENGTH);
248
249         worker_entry(SimpleLineBufTestFunc);
250         close (msock);
251 }
252
253
254 static void SimpleBlobTestFunc(int sock)
255 {
256         StrBuf *ReadBuffer;
257         StrBuf *Blob;
258         const char *Pos = NULL;
259         const char *err = NULL;
260         
261         ReadBuffer = NewStrBuf();
262         Blob = NewStrBuf();
263
264         StrBufReadBLOBBuffered(Blob, 
265                                ReadBuffer, 
266                                &Pos,
267                                &sock,
268                                0,
269                                blobsize,
270                                0,
271                                &err);
272         TestRevalidateStrBuf(Blob);
273         if (err != NULL)
274                 printf("%s", err);
275         CU_ASSERT(blobsize == StrLength(Blob));
276         CU_ASSERT_PTR_NULL(err);
277         CU_ASSERT_NOT_EQUAL(sock, -1);
278         if (sock == -1)
279         printf("BLOB: >%s<\n", ChrPtr(Blob));
280         
281         FreeStrBuf(&ReadBuffer);
282         FreeStrBuf(&Blob);
283         time_to_die = 1;
284 }
285
286
287 static void SimpleHttpPostTestFunc(int sock)
288 {
289         StrBuf *ReadBuffer;
290         StrBuf *Blob;
291         StrBuf *Line;
292         const char *Pos = NULL;
293         const char *err = NULL;
294         int blobsize = 0;
295         int i;
296         const char *pch;
297         
298         ReadBuffer = NewStrBuf();
299         Blob = NewStrBuf();
300         Line = NewStrBuf();
301
302         for (i = 0; 1; i++) {
303                 StrBufTCP_read_buffered_line_fast(Line, 
304                                                   ReadBuffer, 
305                                                   &Pos,
306                                                   &sock,
307                                                   timeout,
308                                                   selres,
309                                                   &err);
310                 TestRevalidateStrBuf(Line);
311                 if (err != NULL)
312                         printf("%s", err);
313                 CU_ASSERT_PTR_NULL(err);
314                 CU_ASSERT_NOT_EQUAL(sock, -1);
315                 if (sock == -1)
316                         break;
317                 printf("LINE: >%s<\n", ChrPtr(Line));
318                 pch = strstr(ChrPtr(Line), "Content-Length");
319                 if (pch != NULL) {
320                         blobsize = atol(ChrPtr(Line) + 
321                                         sizeof("Content-Length:"));
322
323                 }
324                 if (StrLength(Line) == 0)
325                         break;
326                 FlushStrBuf(Line);
327         }
328
329         StrBufReadBLOBBuffered(Blob, 
330                                ReadBuffer, 
331                                &Pos,
332                                &sock,
333                                0,
334                                blobsize,
335                                0,
336                                &err);
337         TestRevalidateStrBuf(Blob);
338         if (err != NULL)
339                 printf("%s", err);
340         printf("Blob said/read: %d / %d\n", blobsize, StrLength(Blob));
341         CU_ASSERT(blobsize != 0);
342         CU_ASSERT(blobsize == StrLength(Blob));
343         CU_ASSERT_PTR_NULL(err);
344         CU_ASSERT_NOT_EQUAL(sock, -1);
345         if (sock == -1)
346         printf("BLOB: >%s<\n", ChrPtr(Blob));
347         
348         FreeStrBuf(&ReadBuffer);
349         FreeStrBuf(&Blob);
350         FreeStrBuf(&Line);
351         time_to_die = 1;
352 }
353
354
355 static void SimpleBLOBbufferTest(void)
356 {
357         msock = ig_tcp_server(ip_addr, listen_port, LISTEN_QUEUE_LENGTH);
358
359         worker_entry(SimpleBlobTestFunc);
360         close (msock);
361 }
362
363 static void SimpleMixedLineBlob(void)
364 {
365         msock = ig_tcp_server(ip_addr, listen_port, LISTEN_QUEUE_LENGTH);
366
367         worker_entry(SimpleHttpPostTestFunc);
368         close (msock);
369 }
370
371
372
373
374
375 /*
376 Some samples from the original...
377         CU_ASSERT_EQUAL(10, 10);
378         CU_ASSERT_EQUAL(0, -0);
379         CU_ASSERT_EQUAL(-12, -12);
380         CU_ASSERT_NOT_EQUAL(10, 11);
381         CU_ASSERT_NOT_EQUAL(0, -1);
382         CU_ASSERT_NOT_EQUAL(-12, -11);
383         CU_ASSERT_PTR_EQUAL((void*)0x100, (void*)0x100);
384         CU_ASSERT_PTR_NOT_EQUAL((void*)0x100, (void*)0x101);
385         CU_ASSERT_PTR_NULL(NULL);
386         CU_ASSERT_PTR_NULL(0x0);
387         CU_ASSERT_PTR_NOT_NULL((void*)0x23);
388         CU_ASSERT_STRING_EQUAL(str1, str2);
389         CU_ASSERT_STRING_NOT_EQUAL(str1, str2);
390         CU_ASSERT_NSTRING_EQUAL(str1, str2, strlen(str1));
391         CU_ASSERT_NSTRING_EQUAL(str1, str1, strlen(str1));
392         CU_ASSERT_NSTRING_EQUAL(str1, str1, strlen(str1) + 1);
393         CU_ASSERT_NSTRING_NOT_EQUAL(str1, str2, 3);
394         CU_ASSERT_NSTRING_NOT_EQUAL(str1, str3, strlen(str1) + 1);
395         CU_ASSERT_DOUBLE_EQUAL(10, 10.0001, 0.0001);
396         CU_ASSERT_DOUBLE_EQUAL(10, 10.0001, -0.0001);
397         CU_ASSERT_DOUBLE_EQUAL(-10, -10.0001, 0.0001);
398         CU_ASSERT_DOUBLE_EQUAL(-10, -10.0001, -0.0001);
399         CU_ASSERT_DOUBLE_NOT_EQUAL(10, 10.001, 0.0001);
400         CU_ASSERT_DOUBLE_NOT_EQUAL(10, 10.001, -0.0001);
401         CU_ASSERT_DOUBLE_NOT_EQUAL(-10, -10.001, 0.0001);
402         CU_ASSERT_DOUBLE_NOT_EQUAL(-10, -10.001, -0.0001);
403 */
404
405
406
407
408
409 static void AddStrBufSimlpeTests(void)
410 {
411         CU_pSuite pGroup = NULL;
412         CU_pTest pTest = NULL;
413
414         pGroup = CU_add_suite("TestStringBufSimpleAppenders", NULL, NULL);
415         if (n_Lines_to_read > 0)
416                 pTest = CU_add_test(pGroup, "testSimpleLinebufferTest", SimpleLinebufferTest);
417         else if (blobsize > 0)
418                 pTest = CU_add_test(pGroup, "testSimpleBLOBbufferTest", SimpleBLOBbufferTest);
419         else 
420                 pTest = CU_add_test(pGroup,"testSimpleMixedLineBlob", SimpleMixedLineBlob);
421
422 }
423
424
425 int main(int argc, char* argv[])
426 {
427         char a;
428         setvbuf(stdout, NULL, _IONBF, 0);
429
430
431         while ((a = getopt(argc, argv, "p:i:n:b:t:s")) != EOF)
432         {
433                 switch (a) {
434
435                 case 'p':
436                         listen_port = atoi(optarg);
437                         break;
438                 case 'i':
439                         safestrncpy(ip_addr, optarg, sizeof ip_addr);
440                         break;
441                 case 'n':
442                         // do linetest?
443                         n_Lines_to_read = atoi(optarg);
444                         break;
445                 case 'b':
446                         // or blobtest?
447                         blobsize = atoi(optarg);
448                         // else run the simple http test
449                         break;
450                 case 't':
451                         if (optarg != NULL)
452                                 timeout = atoi(optarg);
453                         break;
454                 case 's':
455                         if (optarg != NULL)
456                                 selres = atoi(optarg);
457                         break;
458                 }
459         }
460
461
462         StartLibCitadel(8);
463         CU_BOOL Run = CU_FALSE ;
464         
465         CU_set_output_filename("TestAutomated");
466         if (CU_initialize_registry()) {
467                 printf("\nInitialize of test Registry failed.");
468         }
469         
470         Run = CU_TRUE ;
471         AddStrBufSimlpeTests();
472         
473         if (CU_TRUE == Run) {
474                 //CU_console_run_tests();
475     printf("\nTests completed with return value %d.\n", CU_basic_run_tests());
476     
477     ///CU_automated_run_tests();
478         }
479         
480         CU_cleanup_registry();
481
482         return 0;
483 }