tests/ac/test_ac.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following functions.
  1. acc_ip
  2. init_test_server
  3. wrap_AC_commit
  4. api_test_function_sanity
  5. api_test_credit_commit
  6. check_ban
  7. api_test_ban
  8. get_access_table
  9. api_test_persistence
  10. do_api_tests
  11. do_concurrency_persistence_tests
  12. do_concurrency_decay_tests
  13. do_concurrency_tests
  14. init_ac
  15. main
  16. UT_timeget
  17. UT_timediff
  18. UT_time_getvalue
  19. UT_time_set

   1 ***************************************
   2   $Revision: 1.1 $
   3 
   4   AC test code - Test code for AC module.
   5 
   6   Status: NOT REVIEWED, NOT TESTED
   7 
   8   ******************/ /******************
   9   Copyright (c) 2002                          RIPE NCC
  10  
  11   All Rights Reserved
  12   
  13   Permission to use, copy, modify, and distribute this software and its
  14   documentation for any purpose and without fee is hereby granted,
  15   provided that the above copyright notice appear in all copies and that
  16   both that copyright notice and this permission notice appear in
  17   supporting documentation, and that the name of the author not be
  18   used in advertising or publicity pertaining to distribution of the
  19   software without specific, written prior permission.
  20   
  21   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  22   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
  23   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
  24   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  25   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  26   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  27   ***************************************/
  28 
  29 #include "rip.h"
  30 
  31 #define PRIV_OBJECTS 21
  32 #define PRIV_OBJECTS_2 15
  33 static int current_time = 1;
  34 static char first_ip[] = "10.12.13.14";
  35 static char second_ip[] = "11.12.13.14"; /* This IP has to be bigger than
  36                                             the previous one */
  37 
  38 typedef struct {
  39   acc_st acc;
  40   ip_prefix_t ip;
  41 } acc_ip;
     /* [<][>][^][v][top][bottom][index][help] */
  42 
  43 /*
  44   init_test_server:
  45 
  46   Initiates the server code
  47 
  48   Initiates global variables (co)
  49   Loads configuration file (ca)
  50   Initiates sockets
  51 */
  52 void init_test_server(char *conf_file) {
     /* [<][>][^][v][top][bottom][index][help] */
  53   CO_set();
  54 
  55   //we depend on sensible defaults on the config file
  56   ca_init(conf_file);
  57   *(int *)(confVars[CA_AC_DECAY_HALFLIFE].valPtr) = 2000;
  58   *(int *)(confVars[CA_AC_SAVE_INTERVAL].valPtr) = 2;
  59   *(int *)(confVars[CA_AC_DECAY_INTERVAL].valPtr) = 2;
  60   SK_init();
  61 }
  62 
  63 /*
  64   wrap_AC_commit:
  65 
  66   A wrapper to make AC_commit code easiear to write/read.
  67 */
  68 er_ret_t wrap_AC_commit(ip_addr_t *addr, acc_st *acc_conn,
     /* [<][>][^][v][top][bottom][index][help] */
  69   acl_st *acl_copy, char* id) {
  70   er_ret_t ret_err;
  71 
  72   ret_err = AC_commit(addr, acc_conn, acl_copy);
  73   if (ret_err != RX_OK && ret_err != AC_OK) {
  74     printf("**** AC_commit %s failed\n", id);
  75     exit(-1);
  76   }
  77 }
  78 
  79 void api_test_function_sanity() {
     /* [<][>][^][v][top][bottom][index][help] */
  80 }
  81 
  82 void api_test_credit_commit() {
     /* [<][>][^][v][top][bottom][index][help] */
  83   acc_st credit;
  84   acl_st acl;
  85   ip_addr_t ip;
  86   ip_prefix_t pref;
  87   acc_st *ret_credit;
  88 
  89 
  90   printf("Testing Credit commit\n");
  91   /* First commit some credit burn */
  92   IP_addr_t2b(&ip, first_ip, IP_PLAIN);
  93   memset(&credit, 0, sizeof(acc_st));
  94   credit.private_objects = PRIV_OBJECTS;
  95   wrap_AC_commit(&ip, &credit, &acl, "1st on api_test_credit_commit");
  96 
  97   /* Lets see what is in the tree about this node... */
  98   pref.ip = ip;
  99   pref.bits = IP_sizebits(ip.space);
 100   AC_findcreate_account_l(act_runtime, &pref, &ret_credit);
 101   if (ret_credit->private_objects != PRIV_OBJECTS) {
 102     printf("**** AC_commit/AC_findcreate_account_l failed!\n");
 103     exit(-1);
 104   }
 105   else {
 106     printf("     AC_commit/AC_findcreate_account_l OK!\n");
 107   }
 108 }
 109 
 110 acl_st check_ban(ip_addr_t ip) {
     /* [<][>][^][v][top][bottom][index][help] */
 111   acl_st acl;
 112   er_ret_t err;
 113 
 114   if (err = AC_check_acl(&ip, NULL, &acl) != AC_OK) {
 115     printf("**** AC_check_acl failed with error %d\n", err);
 116     exit(-1);
 117   }
 118   return acl;
 119 }
 120 
 121 /*
 122   api_test_ban:
 123 
 124   
 125   Pseudo-code:
 126 
 127   using first_ip:
 128   there should be no ban
 129   a ban is set
 130   there should be a ban
 131   the ban is removed
 132   there should be no ban
 133   a ban is induced via a lot of denials accounted
 134   there should be a ban
 135   a ban is removed and denials removed
 136   there should be no ban
 137 */
 138 void api_test_ban() {
     /* [<][>][^][v][top][bottom][index][help] */
 139   acc_st      credit;
 140   acc_st*     acc;
 141   acl_st      acl;
 142   ip_addr_t   ip;
 143   er_ret_t    err;
 144   ip_prefix_t pref;
 145 
 146   printf("Testing ban\n");
 147   IP_addr_t2b(&ip, first_ip, IP_PLAIN);
 148 
 149   // We should start with no ban
 150   acl = check_ban(ip);  
 151   if (acl.deny > 0) {
 152     printf("**** (1)There is a ban on a node that shouldn't have one.\n");
 153     exit(-1);
 154   }
 155 
 156   // Let's set a ban
 157   pref.ip = ip;
 158   pref.bits = IP_sizebits(ip.space);
 159   if (err = AC_ban_set(&pref, "Test", 1) != AC_OK) {
 160     printf("**** AC_check_acl failed with error %d\n", err);
 161     exit(-1);
 162   }
 163 
 164   // We should have a ban now
 165   acl = check_ban(ip);  
 166   if (acl.deny == 0) {
 167     printf("**** (2)There isn't a ban on a node that should have one.\n");
 168     exit(-1);
 169   }
 170 
 171   // Let's remove it
 172   if (err = AC_ban_set(&pref, "Test", 0) != AC_OK) {
 173     printf("**** AC_check_acl failed with error %d\n", err);
 174     exit(-1);
 175   }
 176 
 177   // We should have no ban
 178   acl = check_ban(ip);  
 179   if (acl.deny > 0) {
 180     printf("**** (3)There is a ban on a node that shouldn't have one.\n");
 181     exit(-1);
 182   }
 183 
 184   //Let's induce a ban via a commit of lots of denials
 185   memset(&credit, 0, sizeof(acc_st));
 186   credit.denials = 99999;
 187   wrap_AC_commit(&ip, &credit, &acl, "Ban via induction");
 188 
 189   // We should have a ban now
 190   acl = check_ban(ip);  
 191   if (acl.deny == 0) {
 192     printf("**** (4)There isn't a ban on a node that should have one.\n");
 193     exit(-1);
 194   }
 195 
 196   // Let's remove it and do some clean up
 197   if (err = AC_ban_set(&pref, "Test", 0) != AC_OK) {
 198     printf("**** AC_check_acl failed with error %d\n", err);
 199     exit(-1);
 200   }
 201   memset(&credit, 0, sizeof(acc_st));
 202   credit.denials = -99999;
 203   wrap_AC_commit(&ip, &credit, &acl, "After induction");
 204 
 205   // We should have no ban
 206   acl = check_ban(ip);  
 207   if (acl.deny > 0) {
 208     printf("**** (5)There is a ban on a node that shouldn't have one.\n");
 209     exit(-1);
 210   }
 211 
 212   //Lets check the runtime node...
 213   if (AC_findcreate_account_l(act_runtime, &pref, &acc) != RX_OK) {
 214     printf("**** AC_findcreate_account_l failed at the end of ban\n");
 215     exit(-1);
 216   }
 217   if (acc->denials != 0 || acc->private_objects != PRIV_OBJECTS) {
 218     printf("**** The status of act_runtime node is incorrect: denials = "
 219            "%d (should be 0)  private_objects = %d (should be %d)\n",
 220            acc->denials, acc->private_objects, PRIV_OBJECTS);
 221     
 222   }
 223 
 224   printf("Ban tests succeded!\n");
 225 }
 226 
 227 /* INCOMPLETE */
 228 void get_access_table(SQ_connection_t *conn, int *rows, acc_ip **acc) {
     /* [<][>][^][v][top][bottom][index][help] */
 229   SQ_result_set_t* rs;
 230   SQ_row_t*        row;
 231   int              cont;
 232 
 233   SQ_execute_query(conn, "SELECT prefix, private_objects, denials, "
 234                        "         private_bonus, prefix_length "
 235                        "    FROM access "
 236                        "ORDER BY prefix ", &rs);
 237   *rows  = SQ_num_rows(rs);
 238   *acc   = UT_malloc(sizeof(acc_ip) * *rows);
 239 
 240   for (cont=0; cont<*rows; cont++){
 241     row = SQ_row_next(rs);
 242     IP_pref_f2b_v4(&(*acc)[cont].ip, 
 243                    SQ_get_column_string_nocopy(rs, row, 0),
 244                    SQ_get_column_string_nocopy(rs, row, 4));
 245     SQ_get_column_int(rs, row, 1, (long*)&(*acc)[cont].acc.private_objects);
 246     SQ_get_column_int(rs, row, 2, (long*)&(*acc)[cont].acc.denials);
 247     (*acc)[cont].acc.private_bonus =
 248       atof(SQ_get_column_string_nocopy(rs, row, 3));
 249   }
 250   SQ_free_result(rs);
 251 }
 252 
 253 
 254 /*
 255   api_test_pesistence:
 256 
 257   Tests persistence.
 258 
 259   Pseudo-code:
 260 
 261   saves the current tree
 262   gets SQL connection
 263   checks it state via SQL
 264   changes one node
 265   saves
 266   checks via SQL
 267   adds a new node (second_ip)
 268   saves
 269   check first_ip node is the same // IMPLEMENT
 270   changes simulated time (to check for decay on load)
 271   loads with AC_persistence_load
 272   checks from the in-memory tree the private bonus
 273   close SQL connection
 274 */
 275 void api_test_persistence() {
     /* [<][>][^][v][top][bottom][index][help] */
 276   SQ_connection_t* conn;
 277   int              cont;
 278   acc_st           credit;
 279   acc_st           *acc;
 280   acc_ip*          credit_list;
 281   acl_st           acl;
 282   ip_addr_t        ip;
 283   ip_prefix_t      pref;
 284   
 285   printf("Persistence tests\n");
 286 
 287   // Lets save the current tree (1 node)
 288   AC_persistence_save();
 289 
 290   //Let's SQL query it and see...
 291   conn = AC_dbopen_admin();
 292 
 293   get_access_table(conn, &cont, &credit_list);
 294   if (cont != 1) {
 295     printf("**** (1) The number of rows should be 1, it is %d\n", cont);
 296     exit(-1);
 297   }
 298   //should test IP
 299   if ( credit_list[0].acc.private_objects != PRIV_OBJECTS &&
 300        credit_list[0].acc.denials != 0) {
 301     printf("**** First SQL save failed, as the saved data is not "
 302                  " correct, check the table\n");
 303     exit(-1);
 304   }
 305   UT_free(credit_list);
 306 
 307   //Lets change the node and try yo save it
 308 
 309   IP_addr_t2b(&ip, first_ip, IP_PLAIN);
 310   memset(&credit, 0, sizeof(acc_st));
 311   credit.denials = 11;
 312   wrap_AC_commit(&ip, &credit, &acl, "First in persistence API");
 313   AC_persistence_save();
 314 
 315   //Let's check the state of the saved data
 316 
 317 
 318   get_access_table(conn, &cont, &credit_list);
 319   if (cont != 1) {
 320     printf("**** (2) The number of rows should be 1, it is %d\n", cont);
 321     exit(-1);
 322   }
 323   if ( credit_list[0].acc.private_objects != PRIV_OBJECTS &&
 324        credit_list[0].acc.denials != 11) {
 325     printf("**** Second SQL save failed, as the saved data is not "
 326                  " correct, check the table\n");
 327     exit(-1);
 328   }
 329   UT_free(credit_list);
 330 
 331   //Lets add a new node (bigger IP) & save
 332   current_time = 2000; //this time should be here!
 333   IP_addr_t2b(&ip, second_ip, IP_PLAIN);
 334   memset(&credit, 0, sizeof(acc_st));
 335   credit.denials = 0;
 336   credit.private_objects = PRIV_OBJECTS_2;
 337   wrap_AC_commit(&ip, &credit, &acl, "Adding 2nd IP in persistence");
 338   AC_persistence_save();
 339 
 340   //Lets load & see, this time with AC_persistence_load...
 341   AC_build(); // This is leaking, but it is OK
 342   AC_acc_load();
 343   AC_persistence_load();
 344   IP_addr_t2b(&ip, first_ip, IP_PLAIN);
 345   pref.ip = ip; // This is the 2nd IP
 346   pref.bits = IP_sizebits(ip.space);
 347   if (AC_findcreate_account_l(act_runtime, &pref, &acc) != RX_OK) {
 348     printf("**** AC_findcreate_account_l failed at persistence\n");
 349     exit(-1);
 350   }
 351   if (acc->private_bonus<14 || acc->private_bonus>15) {
 352     printf("Private bonus of %f is wrong expected arround 14.8\n",
 353            acc->private_bonus);
 354     exit(-1);
 355   }
 356   SQ_close_connection(conn);
 357   printf("Persistence tests OK!\n");
 358 }
 359 
 360 /*
 361   do_api_tests:
 362 
 363   Code is self-documenting.
 364 */
 365 void do_api_tests() {
     /* [<][>][^][v][top][bottom][index][help] */
 366   // the order of the tests is relevant!
 367 
 368   api_test_function_sanity(); // check!
 369 
 370   
 371   api_test_credit_commit();
 372   api_test_ban();
 373   api_test_persistence();
 374 }
 375 
 376 /*
 377   do_concurrency_persistence_tests:
 378 
 379   Does concurrency tests
 380 
 381   Pseudo-code:
 382 
 383   get SQL connection
 384   make some changes to act_runtime
 385   lock act_runtime
 386   spawn persistence thread
 387   wait some time // This shouldn't be used as a MT thechnique,
 388                  // but in this case it should be is OK
 389   check SQL table, it should NOT have changed
 390   unlock
 391   wait some time
 392   check SQL table, it should have changed.
 393   free SQL connection
 394 */
 395 void do_concurrency_persistence_tests() {
     /* [<][>][^][v][top][bottom][index][help] */
 396   ip_addr_t        ip;
 397   acc_st           credit;
 398   acl_st           acl;
 399   SQ_connection_t* conn;
 400   int              rows;
 401   acc_ip*          acc;
 402   
 403 
 404   printf("Starting concurrency persistence tests\n");
 405 
 406   conn = AC_dbopen_admin();
 407   
 408   // change first_ip
 409   IP_addr_t2b(&ip, first_ip, IP_PLAIN);
 410   memset(&credit, 0, sizeof(acc_st));
 411   credit.private_objects = 2; //current = PRIV_OBJECTS + 2
 412   wrap_AC_commit(&ip, &credit, &acl, "First in concurrency");
 413 
 414   // lock act_runtime
 415   TH_acquire_read_lock(&act_runtime->rwlock);
 416 
 417   // launch persistence thread & sleep a bit
 418   TH_create((void*(*)(void*))AC_persistence_daemon, NULL);
 419   sleep(5);
 420 
 421   // check SQL status
 422   get_access_table(conn, &rows, &acc);
 423   if (rows != 2) {
 424     printf("Expecting 2 rows, got %d\n", rows);
 425     exit(-1);
 426   }
 427   // it is pos 0
 428   if (acc[0].acc.private_objects != PRIV_OBJECTS) {
 429     printf("Expected %d private objects got %d\n",
 430             PRIV_OBJECTS, acc[0].acc.private_objects);
 431   }get_access_table(conn, &rows, &acc);
 432   if (rows != 2) {
 433     printf("Expecting 2 rows, got %d\n", rows);
 434     exit(-1);
 435   }
 436   // it is pos 0
 437   if (acc[0].acc.private_objects != PRIV_OBJECTS) {
 438     printf("Expected %d private objects got %d\n",
 439             PRIV_OBJECTS, acc[0].acc.private_objects);
 440   }
 441 
 442   //unlock
 443   printf("     Will release lock\n");
 444   TH_release_read_lock(&act_runtime->rwlock);
 445   sleep(5);
 446   get_access_table(conn, &rows, &acc);
 447   if (rows != 2) {
 448     printf("Expecting 2 rows, got %d\n", rows);
 449     exit(-1);
 450   }
 451   // it is pos 0
 452   if (acc[0].acc.private_objects != PRIV_OBJECTS + 2) {
 453     printf("Expected %d private objects got %d\n",
 454             PRIV_OBJECTS + 2, acc[0].acc.private_objects);
 455   }
 456 
 457   SQ_close_connection(conn);
 458   printf("Concurrency persistence tests OK!\n");
 459 }
 460 
 461 /*
 462   do_concurrency_decay_tests:
 463 
 464   Pseudo-code:
 465 
 466   using second_ip:
 467   check that private_bonus is constant (PRIV_OBJECTS_2)
 468   lock act_runtime
 469   advance time a lot
 470   spawn decay thread
 471   sleep
 472   check that private_bonus is still constant
 473   unlock
 474   sleep
 475   check that private_bonus & private_objects are 0 (ie was decayed)
 476 */
 477 void do_concurrency_decay_tests(){
     /* [<][>][^][v][top][bottom][index][help] */
 478   ip_prefix_t pref;
 479   acc_st      *acc;
 480   ip_addr_t   ip;
 481 
 482   printf("Starting concurrency decay tests\n");
 483 
 484   IP_addr_t2b(&ip, second_ip, IP_PLAIN);
 485   pref.ip = ip;
 486   pref.bits = IP_sizebits(ip.space);
 487 
 488   //check bonus
 489   if (AC_findcreate_account_l(act_runtime, &pref, &acc) != RX_OK) {
 490     printf("**** AC_findcreate_account_l failed at start of decay\n");
 491     exit(-1);
 492   }
 493   if (acc->private_bonus != PRIV_OBJECTS_2) {
 494     printf("**** The status of act_runtime node is incorrect: "
 495            "private_bonus = %f (should be %d)\n",
 496            acc->private_bonus, PRIV_OBJECTS_2);
 497   }
 498 
 499   // lock act_runtime & advance time
 500   TH_acquire_read_lock(&act_runtime->rwlock);
 501   current_time = 1000000; /* way into the future */
 502 
 503   // launch decay thread & sleep a bit
 504   TH_create((void*(*)(void*))AC_decay, NULL);
 505   sleep(5);
 506 
 507   //check that decay did not change private bonus
 508   if (AC_findcreate_account_l(act_runtime, &pref, &acc) != RX_OK) {
 509     printf("**** AC_findcreate_account_l failed at start of decay\n");
 510     exit(-1);
 511   }
 512   if (acc->private_bonus != PRIV_OBJECTS_2) {
 513     printf("**** The status of act_runtime node is incorrect: "
 514            "private_bonus = %f (should be %d)\n",
 515            acc->private_bonus, PRIV_OBJECTS_2);
 516   }
 517 
 518   // release act_runtime & sleep
 519   TH_release_read_lock(&act_runtime->rwlock);
 520   sleep(5);
 521 
 522   //check that decay decayed the node
 523   if (AC_findcreate_account_l(act_runtime, &pref, &acc) != RX_OK) {
 524     printf("**** AC_findcreate_account_l failed at start of decay\n");
 525     exit(-1);
 526   }
 527   if (acc->private_bonus != 0) {  // priv_objects
 528     printf("**** The status of act_runtime node is incorrect: "
 529            "private_bonus = %f (should be %d)\n",
 530            acc->private_bonus);
 531   }
 532 
 533   printf("Concurrency decay tests OK!\n");
 534 }
 535 
 536 /*
 537   do_concurrency_tests:
 538 
 539   Self-documenting
 540 */
 541 void do_concurrency_tests() {
     /* [<][>][^][v][top][bottom][index][help] */
 542   do_concurrency_persistence_tests();
 543   do_concurrency_decay_tests();
 544 }
 545 
 546 /*
 547   init_ac:
 548 
 549   Clears/inits RIPADMIN databases (access & acl)
 550   Calls AC_build (create in-memory trees)
 551   Calls AC_acc_load (loads acl)
 552   Calls AC_persistence_init (inits persistence)
 553 */
 554 void init_ac() {
     /* [<][>][^][v][top][bottom][index][help] */
 555   SQ_connection_t* sq;
 556 
 557   sq = AC_dbopen_admin();
 558   printf("Initializing SQL tables\n"); /* check errs! */
 559   SQ_execute_query(sq, "DELETE FROM access", NULL);
 560   SQ_execute_query(sq, "DELETE FROM acl", NULL);
 561   SQ_execute_query(sq, "INSERT INTO acl VALUES (0,0,2000,-1,10,0,0,'Default access')", NULL);
 562   SQ_close_connection(sq);
 563 
 564   AC_build();
 565   AC_acc_load();
 566   AC_persistence_init();
 567 }
 568 
 569 /*
 570   main:
 571 
 572   The code should be self-documenting
 573 */
 574 int main(int argv, char** argc) {
     /* [<][>][^][v][top][bottom][index][help] */
 575   current_time = 1000;
 576 
 577   if (argv != 2) {
 578     printf("Usage: %s <config_file>\n", argc[0]);
 579     exit(-1);
 580   }
 581 
 582   init_test_server(argc[1]);
 583   init_ac();
 584 
 585   do_api_tests();
 586   do_concurrency_tests();
 587 }
 588 
 589 /*
 590   The following code replaces ut/timediff.c.
 591 
 592   The only changed function is UT_timeget.
 593 */
 594 
 595 void
 596 UT_timeget(ut_timer_t *timer)
     /* [<][>][^][v][top][bottom][index][help] */
 597 {
 598   //  printf("t %d\n", current_time);
 599   if (current_time>0) {
 600     UT_time_set(timer, current_time, 0);
 601     return;
 602   }
 603   gettimeofday( timer, NULL );
 604 }
 605 
 606 
 607 float UT_timediff( ut_timer_t *begintime, ut_timer_t *endtime )
     /* [<][>][^][v][top][bottom][index][help] */
 608 {
 609   return ( endtime->tv_sec - begintime->tv_sec ) +
 610     1e-6 * ( endtime->tv_usec - begintime->tv_usec ) ;
 611 }
 612 
 613 float UT_time_getvalue(ut_timer_t *timer){
     /* [<][>][^][v][top][bottom][index][help] */
 614   return timer->tv_sec + timer->tv_usec * 1e-6;
 615 }
 616 
 617 void UT_time_set(ut_timer_t *timer, long seconds, long useconds){
     /* [<][>][^][v][top][bottom][index][help] */
 618   timer->tv_sec = seconds;
 619   timer->tv_usec = useconds;
 620 }

/* [<][>][^][v][top][bottom][index][help] */