/* ARISA - Test Suites * Copyright (C) 2003, 2004 Carl Ritson * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "arisa.h" #include #include #include /* nickhash test suite */ #define MAX_CHANS 16 #define MAX_ACTORS 8192 typedef struct actor_t { char *name; channel_t *chans[MAX_CHANS]; int no_chans; } actor_t; typedef struct nht_state_t { channel_t *chans[MAX_CHANS]; int no_chans; actor_t *actors[MAX_ACTORS]; int no_actors; nickhash_t *nh; int cno; int signons; int quits; int joins; int parts; int renames; int chanc; int chand; } nht_state_t; static actor_t *find_actor(nht_state_t *state, char *name) { int i; for(i = 0; i < state->no_actors; ++i) { if(irc_strcasecmp(state->actors[i]->name,name) == 0) return state->actors[i]; } return NULL; } static actor_t *gen_actor(nht_state_t *state) { actor_t *a = xalloc(sizeof(actor_t)); int i,nlen = lrand(18)+2; if(state->no_actors >= MAX_ACTORS) { xfree(a); return NULL; } a->name = xalloc(nlen + 1); do { for(i = 0; i < nlen; ++i) a->name[i] = (char) (lrand(60)+65); a->name[nlen] = '\0'; // FIXME: possible infinite loop } while(find_actor(state,a->name) != NULL); a->no_chans = 0; printf("+++ %s Signon\n",a->name); state->actors[state->no_actors++] = a; state->signons++; return a; } static void del_actor(nht_state_t *state, actor_t *a) { int i,j; nickhash_del(state->nh,NULL,a->name); for(i = 0; i < state->no_actors; ++i) { if(state->actors[i] == a) break; } if(i < state->no_actors) { for(j = i+1; j < state->no_actors; ++i,++j) state->actors[i] = state->actors[j]; state->no_actors--; } printf("+++ %s Quit\n",a->name); xfree(a->name); xfree(a); state->quits++; } static void join_actor(nht_state_t *state, actor_t *a) { channel_t *c; int i,j = 0,add; if(state->no_chans == 0) return; c = state->chans[lrand(state->no_chans)]; do { add = 1; for(i = 0; i < a->no_chans && add; ++i) { if(a->chans[i] == c) add = 0; } if(add) { a->chans[a->no_chans++] = c; nickhash_add(state->nh,c,a->name); printf("+++ %s Joined %s\n",a->name,c->name); state->joins++; } else { if(j < state->no_chans) c = state->chans[j]; j++; } } while(add == 0 && j <= state->no_chans); } static void part_actor(nht_state_t *state, actor_t *a) { channel_t *c; int i,j; if(a->no_chans == 0) return; i = lrand(a->no_chans); c = a->chans[i]; nickhash_del(state->nh,c,a->name); for(j = i+1; j < a->no_chans; ++i,++j) a->chans[i] = a->chans[j]; a->no_chans--; printf("+++ %s Parted %s\n",a->name,c->name); state->parts++; } static void rename_actor(nht_state_t *state, actor_t *a) { char *nname; int i,nlen = lrand(18)+2; nname = xalloc(nlen + 1); do { for(i = 0; i < nlen; ++i) nname[i] = (char) (lrand(60)+65); nname[nlen] = '\0'; // FIXME: possible infinite loop } while(find_actor(state,nname) != NULL); nickhash_rename(state->nh,a->name,nname); printf("+++ %s Change Nick to: %s\n",a->name,nname); xfree(a->name); a->name = nname; state->renames++; } static channel_t *gen_chan(nht_state_t *state) { if(state->no_chans < MAX_CHANS) { state->chans[state->no_chans++] = alloc_channel(); state->chans[state->no_chans-1]->name = xalloc(16); snprintf( state->chans[state->no_chans-1]->name, 16,"#%d",state->cno++ ); printf("+++ Formed Channel: %s\n", state->chans[state->no_chans-1]->name); state->chanc++; return state->chans[state->no_chans-1]; } else return NULL; } static void del_channel(nht_state_t *state, channel_t *c) { int i,j,k; nickhash_flush_channel(state->nh,c); for(i = 0; i < state->no_chans; ++i) { if(state->chans[i] == c) break; } if(i < state->no_chans) { for(j = i+1; j < state->no_chans; ++i,++j) state->chans[i] = state->chans[j]; state->no_chans--; state->chand++; } printf("+++ Dispanded Channel: %s\n",c->name); free_channel(c); for(i = 0; i < state->no_actors; ++i) { for(j = 0; j < state->actors[i]->no_chans; ++j) { if(state->actors[i]->chans[j] == c) break; } if(j < state->actors[i]->no_chans) { for(k = j+1; k < state->actors[i]->no_chans; ++j,++k) state->actors[i]->chans[j] = state->actors[i]->chans[k]; state->actors[i]->no_chans--; } } } static void gen_event(nht_state_t *state) { int ev = lrand(100); if(ev < 2) { printf("--- Generating Channel\n"); gen_chan(state); } else if(ev < 3) { printf("--- Deleting Channel\n"); if(state->no_chans > 0) del_channel(state,state->chans[lrand(state->no_chans)]); } else if(ev < 25) { printf("--- Generating Actor\n"); gen_actor(state); } else if(ev < 35) { printf("--- Deleting Actor\n"); if(state->no_actors > 0) del_actor(state,state->actors[lrand(state->no_actors)]); } else if(ev < 60) { printf("--- Joining Actor\n"); if(state->no_actors > 0 && state->no_chans > 0) join_actor(state,state->actors[lrand(state->no_actors)]); } else if(ev < 80) { printf("--- Parting Actor\n"); if(state->no_actors > 0 && state->no_chans > 0) part_actor(state,state->actors[lrand(state->no_actors)]); } else if(ev < 100) { printf("--- Renaming Actor\n"); if(state->no_actors > 0) rename_actor(state,state->actors[lrand(state->no_actors)]); } } static void check_state(nht_state_t *state) { nh_bucket_t *b; actor_t *a; int i,j,k; for(i = 0; i > state->no_actors; ++i) { for(j = 0; j < state->actors[i]->no_chans; ++i) { if(!nickhash_present(state->nh,state->actors[i]->chans[j],state->actors[i]->name)) fprintf(stderr,"!!! Nickhash function doesn't think %s is on %s\n",state->actors[i]->name,state->actors[i]->chans[j]->name); } } for(i = 0; i < state->nh->size; ++i) { b = state->nh->table[i]; while(b != NULL) { a = find_actor(state,b->nick); if(a->no_chans != b->no_cms) fprintf(stderr,"!!! Nickhash channel count mismatch for %s: %d,%d \n",a->name,a->no_chans,b->no_cms); if(a != NULL) { for(j = 0; j < a->no_chans; ++j) { k = 0; while(k < b->no_cms && b->cms[k].channel != a->chans[j]) k++; if(k >= b->no_cms) fprintf(stderr,"!!! Nickhash doesn't know %s is on %s\n",a->name,a->chans[j]->name); } } else fprintf(stderr,"!!! Unknown nick in nickhash: %s\n",b->nick); b = b->next; } } return; } static int test_nickhash(unsigned int seed, int loops, int ichan, int iact, int ijoin, int it, int epi) { nht_state_t *state = xalloc(sizeof(nht_state_t)); int i,j,l; fprintf(stderr, "Executing nickhash tests.\n" "seed: %u, loops: %d, iterations per loop: %d, check interval: %d\n" "initial channels: %d, initial actors: %d, initial joins: %d\n", seed,loops,it,epi,ichan,iact,ijoin); srand(seed); state->nh = nickhash_init(); state->signons = 0; state->quits = 0; state->joins = 0; state->parts = 0; state->renames = 0; state->chanc = 0; state->chand = 0; for(l = 0; l < loops; ++l) { fprintf(stderr,"Loop %d...\n",l); state->no_chans = 0; state->no_actors = 0; state->cno = 0; for(i = 0; i < ichan; ++i) gen_chan(state); for(i = 0; i < iact; ++i) gen_actor(state); if(iact > 0 && ichan > 0) { for(i = 0; i < ijoin; ++i) join_actor(state,state->actors[lrand(state->no_actors)]); } for(i = 0; i < it; ++i) { for(j = 0; j < epi; ++j) gen_event(state); check_state(state); } for(i = 0; i < state->no_chans; ++i) free_channel(state->chans[i]); for(i = 0; i < state->no_actors; ++i) { xfree(state->actors[i]->name); xfree(state->actors[i]); } nickhash_flush(state->nh); fprintf(stderr,"...complete\n"); } nickhash_free(state->nh); fprintf(stderr, "Completed nickhash tests.\n" "signons: %d, quits: %d, joins: %d, parts: %d\n" "renames: %d, chanc: %d, chand: %d\n", state->signons,state->quits,state->joins,state->parts, state->renames,state->chanc,state->chand ); xfree(state); return 0; } static int test_lrand(unsigned int seed, int range, int it) { int i,*cnt; fprintf(stderr, "Executing lrand test. seed: %u, range: %d, iterations: %d\n", seed,range,it ); srand(seed); cnt = xalloc(sizeof(int)*(range+1)); for(i = 0; i < (range+1); ++i) cnt[i] = 0; for(i = 0; i < it; ++i) cnt[lrand(range)]++; for(i = 0; i < (range+1); ++i) fprintf(stderr,"value: %d, count: %d\n",i,cnt[i]); xfree(cnt); fprintf(stderr,"Completed lrand test.\n"); return 0; } static struct { char *host; char *mask; int expect; } hostmask_tests[] = { {"test.domain", "test.domain", 1}, {"test.domain", "*.domain", 1}, {"test.domain", "test.*", 1}, {"test.domain", "*.*", 1}, {"test.domain", "*", 1}, {"test.domain", "test1.*", 0}, {"", "*", 1}, {"a", "*", 1}, {"", "*.*", 0}, {"1.2.3.4", "1.2.*.4", 1}, {NULL} }; static int test_hostmask_match(void) { int i; for(i = 0; hostmask_tests[i].host != NULL; ++i) { if(irc_hostmask_match(hostmask_tests[i].host,hostmask_tests[i].mask) != hostmask_tests[i].expect) { fprintf(stderr, "Failure, host: \"%s\", mask: \"%s\", expect: %d\n", hostmask_tests[i].host, hostmask_tests[i].mask, hostmask_tests[i].expect); } } return 0; } static void print_opts(char **opts, int no_opts) { int i; for(i = 0; i < no_opts; ++i) printf("%d '%s'\n",i,opts[i]); } static int test_split_opt(void) { char *str,**opts; int no_opts; fprintf(stderr,"Executing split_opt test.\n"); no_opts = 0; str = xstrdup("Test"); opts = split_opt(str,str,&no_opts); print_opts(opts,no_opts); if(no_opts != 1 || strcmp(opts[0],"Test") != 0) fprintf(stderr,"Failure for '%s'\n","Test"); xfree(opts); xfree(str); no_opts = 0; str = xstrdup("Test1 Test2"); opts = split_opt(str,str,&no_opts); print_opts(opts,no_opts); if(no_opts != 2 || strcmp(opts[0],"Test1") != 0 || strcmp(opts[1],"Test2") != 0) fprintf(stderr,"Failure for '%s'\n","Test1 Test2"); xfree(opts); xfree(str); no_opts = 0; str = xstrdup("Test1 Test2 "); opts = split_opt(str,str,&no_opts); print_opts(opts,no_opts); if(no_opts != 2 || strcmp(opts[0],"Test1") != 0 || strcmp(opts[1],"Test2") != 0) fprintf(stderr,"Failure for '%s',0 opt\n","Test1 Test2 "); xfree(opts); xfree(str); no_opts = 2; str = xstrdup("Test1 Test2 "); opts = split_opt(str,str,&no_opts); print_opts(opts,no_opts); if(no_opts != 2 || strcmp(opts[0],"Test1") != 0 || strcmp(opts[1],"Test2 ") != 0) fprintf(stderr,"Failure for '%s',2 opt\n","Test1 Test2 "); xfree(opts); xfree(str); no_opts = 0; str = xstrdup("Test1 Test2"); opts = split_opt(str,str,&no_opts); print_opts(opts,no_opts); if(no_opts != 2 || strcmp(opts[0],"Test1") != 0 || strcmp(opts[1],"Test2") != 0) fprintf(stderr,"Failure for '%s'\n","Test1 Test2"); xfree(opts); xfree(str); no_opts = 0; str = xstrdup(" Test1 Test2"); opts = split_opt(str,str,&no_opts); print_opts(opts,no_opts); if(no_opts != 2 || strcmp(opts[0],"Test1") != 0 || strcmp(opts[1],"Test2") != 0) fprintf(stderr,"Failure for '%s'\n"," Test1 Test2"); xfree(opts); xfree(str); no_opts = 0; str = xstrdup("Test1 \"Test2 Test3\""); opts = split_opt(str,str,&no_opts); print_opts(opts,no_opts); if(no_opts != 2 || strcmp(opts[0],"Test1") != 0 || strcmp(opts[1],"Test2 Test3") != 0) fprintf(stderr,"Failure for '%s'\n","Test1 \"Test2 Test3\""); xfree(opts); xfree(str); no_opts = 0; str = xstrdup("Test1 \"Test2 Test3\" "); opts = split_opt(str,str,&no_opts); print_opts(opts,no_opts); if(no_opts != 2 || strcmp(opts[0],"Test1") != 0 || strcmp(opts[1],"Test2 Test3") != 0) fprintf(stderr,"Failure for '%s'\n","Test1 \"Test2 Test3\" "); xfree(opts); xfree(str); no_opts = 0; str = xstrdup("\"Test1 Test2\" Test3"); opts = split_opt(str,str,&no_opts); print_opts(opts,no_opts); if(no_opts != 2 || strcmp(opts[0],"Test1 Test2") != 0 || strcmp(opts[1],"Test3") != 0) fprintf(stderr,"Failure for '%s'\n","\"Test1 Test2\" Test3"); xfree(opts); xfree(str); no_opts = 0; str = xstrdup(" \"Test1 Test2\" Test3"); opts = split_opt(str,str,&no_opts); print_opts(opts,no_opts); if(no_opts != 2 || strcmp(opts[0],"Test1 Test2") != 0 || strcmp(opts[1],"Test3") != 0) fprintf(stderr,"Failure for '%s'\n"," \"Test1 Test2\" Test3"); xfree(opts); xfree(str); no_opts = 0; str = xstrdup("\"Test1 Test2\""); opts = split_opt(str,str,&no_opts); print_opts(opts,no_opts); if(no_opts != 1 || strcmp(opts[0],"Test1 Test2") != 0) fprintf(stderr,"Failure for '%s'\n","\"Test1 Test2\""); xfree(opts); xfree(str); fprintf(stderr,"split_opt test complete.\n"); return 0; } #define TEST_HOST1 "www.google.com" #define TEST_HOST2 "www.microsoft.com" #define TEST_HOST3 "origin2.microsoft.com" #define LOCAL_HOST "localhost.localdomain" #define FAIL_HOST "cause.failure" // unless someone adds a failure TLD static void pf_addrs(struct in_addr *addrs, int no_addr) { char buffer[64]; int i; for(i = 0; i < no_addr; ++i) { inet_ntop(AF_INET,&(addrs[i]),buffer,sizeof(buffer)); printf("addrs[%d] = %s\n",i,buffer); } xfree(addrs); } static int test_aresolv(void) { aresolv_t *res = aresolv_init(); struct timeval t1,t2; long elapsed; char host[128]; struct in_addr *addr; int ret; fprintf(stderr,"Executing aresolv tests.\n"); gettimeofday(&t1,NULL); ret = aresolv_nametoaddrs(res,AF_INET,TEST_HOST1,&addr); gettimeofday(&t2,NULL); if(ret > 0) pf_addrs(addr,ret); else fprintf(stderr,"Error resolving: %s\n",TEST_HOST1); elapsed = diff_tv_usec(&t1,&t2); printf("Query 1 Elapsed: %ldus\n",elapsed); gettimeofday(&t1,NULL); ret = aresolv_nametoaddrs(res,AF_INET,TEST_HOST1,&addr); gettimeofday(&t2,NULL); if(ret > 0) pf_addrs(addr,ret); else fprintf(stderr,"Error resolving: %s\n",TEST_HOST1); printf("Query 2 Elapsed: %ldus\n",(long)diff_tv_usec(&t1,&t2)); if(diff_tv_usec(&t1,&t2) > elapsed) fprintf(stderr,"Second query took longer than first.\n"); ret = aresolv_nametoaddrs(res,AF_INET,FAIL_HOST,&addr); if(ret != -1) { fprintf(stderr,"We were able to query %s, shouldn't work...\n",FAIL_HOST); xfree(addr); } else printf("Failed to query %s, as expected.\n",FAIL_HOST); ret = aresolv_nametoaddrs(res,AF_INET,TEST_HOST2,&addr); if(ret > 0) pf_addrs(addr,ret); else fprintf(stderr,"Error resolving: %s\n",TEST_HOST2); ret = aresolv_nametoaddrs(res,AF_INET,TEST_HOST3,&addr); if(ret > 0) { char addrstr[32]; int i,no = ret; for(i = 0; i < no; ++i) { inet_ntop(AF_INET,&(addr[i]),addrstr,sizeof(addrstr)); ret = aresolv_addrtoname(res,AF_INET,&(addr[i]),host,sizeof(host)); if(ret == -1) fprintf(stderr,"Failed to resolv: %s\n",addrstr); else if(strcasecmp(host,TEST_HOST3) != 0) fprintf(stderr,"error: %s -> %s -> %s\n",TEST_HOST3,addrstr,host); else printf("%s -> %s\n",addrstr,host); } pf_addrs(addr,no); } else fprintf(stderr,"Error resolving: %s\n",TEST_HOST3); ret = aresolv_nametoaddrs(res,AF_INET,LOCAL_HOST,&addr); if(ret > 0) { char addrstr[32]; pf_addrs(addr,ret); ret = aresolv_nametoaddrs(res,AF_INET,LOCAL_HOST,&addr); inet_ntop(AF_INET,&(addr[0]),addrstr,sizeof(addrstr)); ret = aresolv_addrtoname(res,AF_INET,&(addr[0]),host,sizeof(host)); if(ret == -1) fprintf(stderr,"Failed to resolv: %s\n",addrstr); else printf("%s -> %s\n",addrstr,host); } else fprintf(stderr,"Error resolving: %s\n",LOCAL_HOST); fprintf(stderr,"aresolv tests complete.\n"); aresolv_free(res); return 0; } static int do_lrand_test(int argc, char *argv[]) { return test_lrand(777,16,100); } static int do_nickhash_test(int argc, char *argv[]) { int ret = 0; ret += test_nickhash(666,3,4,200,500,1000,1); ret += test_nickhash(666,3,4,200,500,1000,5); ret += test_nickhash(777,3,4,200,500,1000,5); ret += test_nickhash(31337,3,4,200,500,1000,5); return ret; } static int do_hostmask_match_test(int argc, char *argv[]) { return test_hostmask_match(); } static int do_split_opt_test(int argc, char *argv[]) { return test_split_opt(); } static int do_aresolv_test(int argc, char *argv[]) { return test_aresolv(); } #define CYCLE 5000 #define CYCLE_LOW 1 #define CYCLE_HIGH 100 static double get_per_cycle(struct timeval *start, struct timeval *end, int count) { double ret = (double) diff_tv_usec(start,end); return ret / (double) count; } static int do_pq_v_dq(int argc, char *argv[]) { struct timeval start, end; char *data = "wibble"; pqueue_t *pq = pqueue_init(NULL,0); dq_t *dq = dq_alloc_simple(); double t1,t2; int limit; int i,j; for(limit = CYCLE_LOW; limit <= CYCLE_HIGH; ++limit) { gettimeofday(&start,NULL); for(i = 0; i < CYCLE; ++i) { for(j = 0; j < limit; ++j) pqueue_push_back(pq,data); for(j = 0; pqueue_pop_front(pq) != NULL; ++j) ; assert(j == limit); } gettimeofday(&end,NULL); t1 = get_per_cycle(&start,&end,CYCLE); gettimeofday(&start,NULL); for(i = 0; i < CYCLE; ++i) { for(j = 0; j < limit; ++j) dq_push_back(dq,data); for(j = 0; dq_pop_front(dq) != NULL; ++j) ; assert(j == limit); } gettimeofday(&end,NULL); t2 = get_per_cycle(&start,&end,CYCLE); fprintf(stderr,"pushb+popf %d for %d: pqueue = %.2fus, dq = %.2fus, improvement = %.2f%%\n", limit,CYCLE,t1,t2, ((t1 / t2) * 100.0) - 100.0); } return 0; } static struct { const char *name; const char *desc; int (*func)(int, char **); } tests[] = { { .name = "lrand", .desc = "local random function test", .func = do_lrand_test }, { .name = "nickhash", .desc = "nick hash simulation", .func = do_nickhash_test }, { .name = "hostmask_match", .desc = "hostmasking function test", .func = do_hostmask_match_test }, { .name = "split_opt", .desc = "argument / option spliting test", .func = do_split_opt_test }, { .name = "aresolv", .desc = "asynchronous dns test", .func = do_aresolv_test }, { .name = "pq_v_dq", .desc = "pqueue versus dq benchmark", .func = do_pq_v_dq }, { .name = NULL, .desc = NULL, .func = NULL } }; static void list_tests(void) { int i; fprintf(stderr,"Known tests:\n"); fprintf(stderr,"\tall (\"run all tests\")\n"); for(i = 0; tests[i].name != NULL; ++i) fprintf(stderr,"\t%s (\"%s\")\n",tests[i].name,tests[i].desc); } static void do_test(const char *name, int argc, char *argv[]) { int i, found; for(i = 0, found = 0; tests[i].name != NULL; ++i) { if(strcasecmp(name,tests[i].name) == 0 || strcasecmp(name,"all") == 0) { int ret = tests[i].func(argc,argv); fprintf(stderr,"Test %s (\"%s\") = %d\n", tests[i].name,tests[i].desc,ret); found++; } } if(found == 0) { fprintf(stderr,"Unknown test \"%s\"\n",name); list_tests(); exit(1); } } /* test suite entry point */ #ifdef USE_TESTSUITE void testsuite(int argc, char *argv[]) { int i, run; setvbuf(stderr,NULL,_IONBF,0); setvbuf(stdout,NULL,_IONBF,0); for(i = 1, run = 0; i < argc; ++i) { if(argv[i][0] != '-') { do_test(argv[i],argc,argv); run++; } } if(run == 0) list_tests(); } #else void testsuite(int argc, char *argv[]) { fprintf(stderr, "Testsuite not compiled in, recompile --with-testsuite\n"); } #endif /* USE_TESTSUITE */