/* * webkernel_test.c * * Tests to stress the webkernel API. * * Author: Dario Rodriguez dario@softhome.net * This program is dual licensed: MIT and in "the public domain". */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include "sbuf.h" #include "socklib.h" #include "webkernel.h" #define STRING_OK "ok" #define STRING_FAIL "fail" typedef enum test_action { test_name=0, test_description, test_run } test_action; char *test1(test_action action); char *socklib_connect(test_action action); char *socklib_sselect(test_action action); char *sbuf_memory(test_action action); struct { char *(*test)(/* test_action action */); } tests[]={{test1}, {socklib_connect}, {socklib_sselect}, {sbuf_memory}, }; int main(int argc, char *argv[]) { int i; int flagall; char *resstr; int total,totalfail; if(argc==1 || strcmp(argv[argc-1],"--help")==0 || argc!=2) { printf("Syntax:\n\t%s { --help | --list | test_name | all }\nNOTE: test_name is one of the tests listed in --list\n",argv[0]); return(0); } if(strcmp(argv[argc-1],"--list")==0) { for(i=0;i<(sizeof(tests)/sizeof(tests[0]));i++) printf("%s\n\t%s\n",tests[i].test(test_name),tests[i].test(test_description)); return(0); } flagall=(strcmp(argv[argc-1],"all")==0)?1:0; for(total=totalfail=0,i=0;i<(sizeof(tests)/sizeof(tests[0]));i++) { if(!flagall && strcmp(tests[i].test(test_name),argv[argc-1])!=0) continue; printf("%20s...",tests[i].test(test_name)); fflush(stdout); resstr=tests[i].test(test_run); total++; totalfail+=((memcmp(resstr,STRING_OK,strlen(STRING_OK))==0)?0:1); printf("%s\n",resstr); } if(!flagall && i>=(sizeof(tests)/sizeof(tests[0]))) { printf("ERROR: test not found\n"); return(1); } if(totalfail!=0) printf("Failed %i of %i tests.\n",totalfail,total); return((totalfail!=0)?1:0); } char * test1(test_action action) { if(action==test_name) return("test1"); else if(action==test_description) return("test the testing framework"); /* run test */ return("ok"); } char * socklib_connect(test_action action) { int server,client; char *host; long hostsize; int port; int off; int timeout=100; if(action==test_name) return("socklib_connect"); if(action==test_description) return("listen and connect"); if((host=ipv4_genip("localhost",&hostsize))==NULL) return(STRING_FAIL ": couldn't resove localhost"); for(server=-1,off=0,port=19747;off<1024;off++,port++) { if((server=ipv4_serverbinded(host,hostsize,port))!=-1) break; } if(server==-1) { free(host),host=NULL; return(STRING_FAIL ": couldn't find empty port for server\n"); } sock_setunsafe(server); if((client=ipv4_preconnect(host,hostsize,port))==-1) { close(server),server=-1; free(host),host=NULL; return(STRING_FAIL ": couldn't connect to server\n"); } if(ipv4_connect(client,timeout)==-1) { close(client),client=-1; close(server),server=-1; free(host),host=NULL; return(STRING_FAIL ": timeout on connect\n"); } ipv4_postconnect(client); close(client),client=-1; close(server),server=-1; free(host),host=NULL; return(STRING_OK); } char * test_socketsinit(int *server, int *client, char **host, long *hostsize, int *port) { int timeout=100; int off; *server=*client=*port=-1; *hostsize=0; *host=NULL; *port=-1; if((*host=ipv4_genip("localhost",hostsize))==NULL) return(STRING_FAIL ": couldn't resove localhost"); for(*server=-1,off=0,*port=19747;off<1024;off++,(*port)++) { if((*server=ipv4_serverbinded(*host,*hostsize,*port))!=-1) break; } if(*server==-1) { free(*host),*host=NULL; return(STRING_FAIL ": couldn't find empty port for server\n"); } sock_setunsafe(*server); if((*client=ipv4_preconnect(*host,*hostsize,*port))==-1) { close(*server),*server=-1; free(*host),*host=NULL; return(STRING_FAIL ": couldn't connect to server\n"); } if(ipv4_connect(*client,timeout)==-1) { close(*client),*client=-1; close(*server),*server=-1; free(*host),*host=NULL; return(STRING_FAIL ": timeout on connect\n"); } ipv4_postconnect(*client); return(NULL); } void test_socketsfini(int *server, int *client, char **host, long *hostsize, int *port) { if(*server!=-1) close(*server),*server=-1; if(*client!=-1) close(*client),*client=-1; if(*host!=NULL) free(*host),*host=NULL; *hostsize=0; *port=-1; } char * socklib_sselect(test_action action) { int server,client; char *host; long hostsize; int port; char *result; char buf[128]; int readyfds[16]; sselect *ssel; int timeout=100; int workfd; if(action==test_name) return("socklib_sselect"); if(action==test_description) return("select over sockets"); if((result=test_socketsinit(&server,&client,&host,&hostsize,&port))!=NULL) { test_socketsfini(&server,&client,&host,&hostsize,&port); return(result); } if((ssel=sselect_init())==NULL) { test_socketsfini(&server,&client,&host,&hostsize,&port); return(STRING_FAIL ": couldn't init sselect struct"); } if(sselect_reset(ssel)!=0) { sselect_free(ssel),ssel=NULL; test_socketsfini(&server,&client,&host,&hostsize,&port); return(STRING_FAIL ": couldn't test the sselect reset function"); } if(sselect_wait(ssel,timeout)!=0) { sselect_free(ssel),ssel=NULL; test_socketsfini(&server,&client,&host,&hostsize,&port); return(STRING_FAIL ": (1) was expecting a timeout, something else happened"); } if(sselect_addread(ssel,server,buf)!=0) { sselect_free(ssel),ssel=NULL; test_socketsfini(&server,&client,&host,&hostsize,&port); return(STRING_FAIL ": couldn't add 'read serverfd' to the sselect"); } if(sselect_wait(ssel,timeout)!=1) { sselect_free(ssel),ssel=NULL; test_socketsfini(&server,&client,&host,&hostsize,&port); return(STRING_FAIL ": (2) was expecting a ready-to-read, something else happened"); } if((workfd=sock_accept(server))==-1) { sselect_free(ssel),ssel=NULL; test_socketsfini(&server,&client,&host,&hostsize,&port); return(STRING_FAIL ": couldn't accept connection"); } write(client,".",1); if(sselect_wait(ssel,timeout)!=0) { sselect_free(ssel),ssel=NULL; test_socketsfini(&server,&client,&host,&hostsize,&port); return(STRING_FAIL ": (2) was expecting a timeout, something else happened"); } if(sselect_addread(ssel,workfd,&workfd)!=0) { sselect_free(ssel),ssel=NULL; close(workfd),workfd=-1; test_socketsfini(&server,&client,&host,&hostsize,&port); return(STRING_FAIL ": couldn't add 'read workfd' to the sselect"); } if(sselect_wait(ssel,timeout)!=1) { sselect_free(ssel),ssel=NULL; close(workfd),workfd=-1; test_socketsfini(&server,&client,&host,&hostsize,&port); return(STRING_FAIL ": was expecting a something-to-read, something else happened"); } if((sselect_getread(ssel,readyfds,sizeof(readyfds)/sizeof(readyfds[0])))!=1 || *readyfds!=workfd) { sselect_free(ssel),ssel=NULL; close(workfd),workfd=-1; test_socketsfini(&server,&client,&host,&hostsize,&port); return(STRING_FAIL ": the list of ready-to-read fds is wrong"); } if(sselect_getuserptr(ssel,workfd)!=&workfd) { sselect_free(ssel),ssel=NULL; close(workfd),workfd=-1; test_socketsfini(&server,&client,&host,&hostsize,&port); return(STRING_FAIL ": Couldn't recover the userptr of workfd"); } read(workfd,buf,1); if(sselect_addwrite(ssel,client,buf)!=0) { sselect_free(ssel),ssel=NULL; close(workfd),workfd=-1; test_socketsfini(&server,&client,&host,&hostsize,&port); return(STRING_FAIL ": couldn't add 'write clientfd' to the sselect"); } if(sselect_wait(ssel,timeout)!=1) { sselect_free(ssel),ssel=NULL; close(workfd),workfd=-1; test_socketsfini(&server,&client,&host,&hostsize,&port); return(STRING_FAIL ": was expecting an ok-to-write, something else happened"); } sselect_free(ssel),ssel=NULL; close(workfd),workfd=-1; test_socketsfini(&server,&client,&host,&hostsize,&port); return(STRING_OK); } char * sbuf_memory(test_action action) { int bufsize=2048; const unsigned char data[]={0,2,4,1,2,4,1,76,91,147,135,253,121,56,5,9}; unsigned char moredata[16]; unsigned char *ptr; const char *line,lines[]={"one\nand two\nthree"}; int i; sbuf *buf; if(action==test_name) return("sbuf_memory"); else if(action==test_description) return("memory operations with sbuf"); if((buf=sbuf_init(bufsize))==NULL) return(STRING_FAIL ": couldn't alloc new sbuf"); if(sbuf_add(buf,(char *)data,sizeof(data))!=sizeof(data)) { sbuf_free(buf),buf=NULL; return(STRING_FAIL ": couldn't push data"); } for(i=0;i<sizeof(moredata);i++) moredata[i]=i; if(sbuf_add(buf,(char *)moredata,sizeof(moredata))!=sizeof(moredata)) { sbuf_free(buf),buf=NULL; return(STRING_FAIL ": (2) couldn't push data"); } if(sbuf_count(buf)!=(sizeof(data)+sizeof(moredata))) { sbuf_free(buf),buf=NULL; return(STRING_FAIL ": bad count"); } for(i=0;i<sizeof(data);i++) { if((ptr=(unsigned char *)sbuf_getbytes(buf,1))==NULL || *ptr!=data[i]) { sbuf_free(buf),buf=NULL; return(STRING_FAIL ": bad retrieval"); } } sbuf_discard(buf); if((ptr=(unsigned char *)sbuf_getbytes(buf,sizeof(moredata)))==NULL || memcmp(ptr,moredata,sizeof(moredata))!=0) { sbuf_free(buf),buf=NULL; return(STRING_FAIL ": (2) bad retrieval"); } if(sbuf_getbytes(buf,1)!=NULL) { sbuf_free(buf),buf=NULL; return(STRING_FAIL ": (3) bad retrieval"); } sbuf_discard(buf); if(sbuf_addstr(buf,lines)!=(sizeof(lines)-1)) { sbuf_free(buf),buf=NULL; return(STRING_FAIL ": (3) couldn't push data"); } if((line=sbuf_getline(buf))==NULL || strcmp(line,"one")!=0) { sbuf_free(buf),buf=NULL; return(STRING_FAIL ": bad line retrieval"); } if((line=sbuf_getline(buf))==NULL || strcmp(line,"and two")!=0) { sbuf_free(buf),buf=NULL; return(STRING_FAIL ": (2) bad line retrieval"); } if(sbuf_getline(buf)!=NULL) { sbuf_free(buf),buf=NULL; return(STRING_FAIL ": (3) bad line retrieval"); } sbuf_free(buf),buf=NULL; return(STRING_OK); }