## 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] */