Fixing memory leak in python support function
[ric-plt/lib/rmr.git] / test / symtab_test.c
1 /*
2 ==================================================================================
3             Copyright (c) 2019-2021 Nokia
4             Copyright (c) 2018-2021 AT&T Intellectual Property.
5
6    Licensed under the Apache License, Version 2.0 (the "License");
7    you may not use this file except in compliance with the License.
8    You may obtain a copy of the License at
9
10            http://www.apache.org/licenses/LICENSE-2.0
11
12    Unless required by applicable law or agreed to in writing, software
13    distributed under the License is distributed on an "AS IS" BASIS,
14    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15    See the License for the specific language governing permissions and
16    limitations under the License.
17 ==================================================================================
18 */
19
20
21 /*
22         Mnemonic:       symtab_test.c
23         Abstract:       This is the unit test module that will drive tests against
24                                 the symbol table portion of RMr.  Run with:
25                                         ksh unit_test.ksh symtab_test.c
26         Date:           1 April 2019
27         Author:         E. Scott Daniels
28 */
29
30 #include <pthread.h>
31
32 #define NO_DUMMY_RMR 1                  // no dummy rmr functions; we don't pull in rmr.h or agnostic.h
33 #define NO_EMULATION
34 #define NO_PRIVATE_HEADERS
35
36 #include <rmr.h>
37 #include <rmr_agnostic.h>
38 #include "test_support.c"
39 #include "rmr_symtab.h"
40
41 #include "symtab.c"                                                     // module under test
42
43
44 int terrors = 0;                                                        // thread errors
45 int state = GOOD;                                                       // overall pass/fail state 0==fail
46 int counter;                                                            // global counter for for-each tests
47
48
49
50 static int fetch( void* st, char* key, int class, int expected ) {
51         char* val;
52         int error = 0;
53
54         val = rmr_sym_get( st, key, class );
55         if( val ) {
56                 fprintf( stderr, "[%s] get returns key=%s val=%s\n",  !expected ? "FAIL" : "OK", key, val );
57                 if( !expected ) {
58                         state = BAD;
59                         error = 1;
60                 }
61
62         } else {
63                 fprintf( stderr, "[%s] string key fetch return nil\n", expected ? "FAIL" : "OK" );
64                 if( expected ) {
65                         state = BAD;
66                         error = 1;
67                 }
68         }
69
70         return error;
71 }
72
73 static int nfetch( void* st, int key, int expected ) {
74         char* val;
75         int             error = 0;
76
77         val = rmr_sym_pull( st, key );
78         if( val ) {
79                 fprintf( stderr, "[%s] get returns key=%d val=%s\n", !expected ? "FAIL" : "OK", key, val );
80                 if( !expected )  {
81                         state = BAD;
82                         error = 1;
83                 }
84         } else {
85                 fprintf( stderr, "[%s] get return nil for key=%d\n", expected ? "FAIL" : "OK", key );
86                 if( expected )  {
87                         state = BAD;
88                         error = 1;
89                 }
90         }
91
92         return error;
93 }
94
95 // ----------------- thread based tests -------------------------------------------------------------------
96 #define NUM_KEYS        512                                     // number of unique keys
97 #define NUM_ATTEMPTS    1000000
98
99 /*
100         This is started in a thread and will attempt 10,000 reads on the symtable
101         in an attempt to ensure that there are no concurrent read/write issues.
102 */
103 static void* reader( void* st ) {
104         char    key[1024];
105         int             i;
106         int             ncount = 0;                     // number not found
107         int             fcount = 0;                     // number found
108
109         for( i = 0; i < NUM_ATTEMPTS; i++ ) {
110                 snprintf( key, sizeof( key ), "key_%d", i % NUM_KEYS );
111                 if( rmr_sym_get( st, key, 1 ) == NULL ) {
112                         ncount++;
113                 } else {
114                         fcount++;
115                 }
116         }
117
118         fprintf( stderr, "<info> reader finished: n=%d f=%d\n", ncount, fcount );       // there is no right answer
119         return NULL;
120 }
121
122 /*
123         This is started in a thread and will attempt 10,000 writes on the symtable
124         in an attempt to ensure that there are no concurrent read/write issues. Keys are
125         written as key_n where n is an integer between 0 and 999 inclusive.
126 */
127 static void* writer( void* st ) {
128         char    key[1024];
129         int             i;
130         int             ncount = 0;                     // number first inserts
131         int             rcount = 0;                     // number replacements
132         char*   value = NULL;
133         int             num_keys = 256;
134
135         fprintf( stderr, "<INFO> writer now turning\n" );
136         for( i = 0; i < NUM_ATTEMPTS; i++ ) {
137                 value++;
138                 snprintf( key, sizeof( key ), "key_%d", i % NUM_KEYS );
139                 rmr_sym_del( st, key, 1 );
140                 if( rmr_sym_put( st, key, 1, value )  ) {
141                         ncount++;
142                 } else {
143                         rcount++;
144                 }
145         }
146
147         if( ncount != NUM_ATTEMPTS ) {
148                 fprintf( stderr, "<FAIL> writer finished: n=%d r=%d\n", ncount, rcount );       // there is no right answer
149                 terrors++;
150         } else {
151                 fprintf( stderr, "<INFO> writer finished: n=%d r=%d\n", ncount, rcount );       // there is no right answer
152         }
153
154         return NULL;
155 }
156
157 /*
158         Drive a concurrent read/write test to ensure no race issues.
159 */
160 static int thread_test( ) {
161         pthread_t       tids[10];
162         int                     n2start = 3;
163         int                     i;
164         void*           st;
165
166         st = rmr_sym_alloc( 128 );                      // should force collisions
167
168         fprintf( stderr, "<INFO> starting writer\n" );
169         pthread_create( &tids[0], NULL, writer, st );
170
171         for( i = 1; i <= n2start; i++ ) {
172                 fprintf( stderr, "<INFO> starting reader %d\n", i );
173                 pthread_create( &tids[i], NULL, reader, st );
174         }
175
176         fprintf( stderr, "<INFO> thread controller is waiting\n" );
177         for( i = 0; i <= n2start; i++ ) {
178                 pthread_join( tids[i], NULL );                          // status is unimportant, just hold until all are done
179                 fprintf( stderr, "<INFO> thread %d  has reported complete\n", i );
180         }
181
182
183         rmr_sym_stats( st, 1 );
184         return terrors;
185 }
186
187 // ---------------------------------------------------------------------------------------------------------
188
189 /*
190         Driven by foreach class -- just incr the counter.
191 */
192 static void each_counter( void* a, void* b, const char* c, void* d, void* e ) {
193         counter++;
194 }
195
196 int main( ) {
197         void*   st;
198         char*   foo = "foo";
199         char*   bar = "bar";
200         char*   goo = "goo";                            // name not in symtab
201         int             i;
202         int             class = 1;
203         int             s;
204         void*   p;
205         int             errors = 0;
206
207         st = rmr_sym_alloc( 10 );                                               // alloc with small value to force adjustment inside
208         errors += fail_if_nil( st, "symtab pointer" );
209
210         s = rmr_sym_put( st, foo, class, bar );                 // add entry with string key; returns 1 if it was inserted
211         errors += fail_if_false( s, "insert foo existed" );
212
213         s = rmr_sym_put( st, foo, class+1, bar );               // add to table with a different class
214         errors += fail_if_false( s, "insert foo existed" );
215
216         s = rmr_sym_put( st, foo, class, bar );                 // inserted above, should return not inserted (0)
217         errors += fail_if_true( s, "insert foo existed" );
218
219         errors += fetch( st, foo, class, 1 );
220         errors += fetch( st, goo, class, 0 );                   // fetch non existant
221         rmr_sym_stats( st, 4 );                                                 // early stats at verbose level 4 so chatter is minimised
222         rmr_sym_dump( st );
223
224         for( i = 2000; i < 3000; i++ ) {                                // bunch of dummy things to force chains in the table
225                 rmr_sym_map( st, i, foo );                                      // add entry with unsigned integer key
226         }
227         rmr_sym_stats( st, 0 );                                                 // just the small facts to verify the 1000 we stuffed in
228         rmr_sym_ndel( st, 2001 );                                               // force a numeric key delete
229         rmr_sym_ndel( st, 12001 );                                              // delete numeric key not there
230
231         s = rmr_sym_map( st, 1234, foo );                                       // add known entries with unsigned integer key
232         errors += fail_if_false( s, "numeric add of key 1234 should not have existed" );
233         s = rmr_sym_map( st, 2345, bar );
234         fail_if_true( s, "numeric add of key 2345 should have existed" );
235
236         counter = 0;
237         rmr_sym_foreach_class( st, 0, each_counter, NULL );
238         errors += fail_if_false( counter, "expected counter after foreach to be non-zero" );
239
240         errors += nfetch( st, 1234, 1 );
241         errors += nfetch( st, 2345, 1 );
242
243         rmr_sym_del( st, foo, 0 );
244
245         rmr_sym_stats( st, 0 );
246
247         rmr_sym_free( NULL );                   // ensure it doesn't barf when given a nil pointer
248         rmr_sym_free( st );
249
250         errors += thread_test();                // test as best we can for race issues
251
252         test_summary( errors, "symtab tests" );
253         if( state + errors == 0 ) {
254                 fprintf( stderr, "<PASS> all symtab tests were OK\n\n" );
255         } else {
256                 fprintf( stderr, "<FAIL> %d errors in symtab code\n\n", errors );
257         }
258
259
260         return !!(state + errors);
261 }
262