/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following functions.
- acc_ip
- init_test_server
- wrap_AC_commit
- api_test_function_sanity
- api_test_credit_commit
- check_ban
- api_test_ban
- get_access_table
- api_test_persistence
- do_api_tests
- do_concurrency_persistence_tests
- do_concurrency_decay_tests
- do_concurrency_tests
- init_ac
- main
- UT_timeget
- UT_timediff
- UT_time_getvalue
- 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 }