blob: 9beae8d58e320ebf3d2303786a66cc8e41563a3b [file] [log] [blame]
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -04001/*
2==================================================================================
E. Scott Daniels11838bc2021-04-22 16:34:08 -04003 Copyright (c) 2019-2021 Nokia
4 Copyright (c) 2018-2021 AT&T Intellectual Property.
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -04005
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
E. Scott Daniels8790bf02019-04-23 12:59:28 +000010 http://www.apache.org/licenses/LICENSE-2.0
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -040011
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
E. Scott Daniels8790bf02019-04-23 12:59:28 +000024 the symbol table portion of RMr. Run with:
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -040025 ksh unit_test.ksh symtab_test.c
26 Date: 1 April 2019
E. Scott Daniels5ec64c52020-11-05 09:11:04 -050027 Author: E. Scott Daniels
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -040028*/
29
E. Scott Daniels5ec64c52020-11-05 09:11:04 -050030#include <pthread.h>
31
E. Scott Danielsd7109572019-04-18 14:01:16 +000032#define NO_DUMMY_RMR 1 // no dummy rmr functions; we don't pull in rmr.h or agnostic.h
E. Scott Danielsfc5c77b2020-02-21 13:24:29 -050033#define NO_EMULATION
34#define NO_PRIVATE_HEADERS
E. Scott Danielsd7109572019-04-18 14:01:16 +000035
E. Scott Danielsfc5c77b2020-02-21 13:24:29 -050036#include <rmr.h>
37#include <rmr_agnostic.h>
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -040038#include "test_support.c"
E. Scott Danielsfc5c77b2020-02-21 13:24:29 -050039#include "rmr_symtab.h"
40
41#include "symtab.c" // module under test
42
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -040043
E. Scott Daniels5ec64c52020-11-05 09:11:04 -050044int terrors = 0; // thread errors
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -040045int state = GOOD; // overall pass/fail state 0==fail
46int counter; // global counter for for-each tests
47
48
49
E. Scott Daniels77526eb2020-09-17 16:39:31 -040050static int fetch( void* st, char* key, int class, int expected ) {
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -040051 char* val;
E. Scott Daniels77526eb2020-09-17 16:39:31 -040052 int error = 0;
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -040053
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;
E. Scott Daniels77526eb2020-09-17 16:39:31 -040059 error = 1;
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -040060 }
E. Scott Daniels8790bf02019-04-23 12:59:28 +000061
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -040062 } else {
63 fprintf( stderr, "[%s] string key fetch return nil\n", expected ? "FAIL" : "OK" );
64 if( expected ) {
65 state = BAD;
E. Scott Daniels77526eb2020-09-17 16:39:31 -040066 error = 1;
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -040067 }
68 }
E. Scott Daniels77526eb2020-09-17 16:39:31 -040069
70 return error;
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -040071}
72
E. Scott Daniels77526eb2020-09-17 16:39:31 -040073static int nfetch( void* st, int key, int expected ) {
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -040074 char* val;
E. Scott Daniels77526eb2020-09-17 16:39:31 -040075 int error = 0;
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -040076
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;
E. Scott Daniels77526eb2020-09-17 16:39:31 -040082 error = 1;
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -040083 }
84 } else {
85 fprintf( stderr, "[%s] get return nil for key=%d\n", expected ? "FAIL" : "OK", key );
86 if( expected ) {
87 state = BAD;
E. Scott Daniels77526eb2020-09-17 16:39:31 -040088 error = 1;
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -040089 }
90 }
E. Scott Daniels77526eb2020-09-17 16:39:31 -040091
92 return error;
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -040093}
94
E. Scott Daniels5ec64c52020-11-05 09:11:04 -050095// ----------------- 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*/
103static 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*/
127static 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*/
160static 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// ---------------------------------------------------------------------------------------------------------
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -0400188
189/*
190 Driven by foreach class -- just incr the counter.
191*/
192static void each_counter( void* a, void* b, const char* c, void* d, void* e ) {
193 counter++;
194}
195
196int main( ) {
E. Scott Daniels8790bf02019-04-23 12:59:28 +0000197 void* st;
198 char* foo = "foo";
199 char* bar = "bar";
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -0400200 char* goo = "goo"; // name not in symtab
201 int i;
202 int class = 1;
203 int s;
204 void* p;
E. Scott Daniels77526eb2020-09-17 16:39:31 -0400205 int errors = 0;
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -0400206
E. Scott Daniels8790bf02019-04-23 12:59:28 +0000207 st = rmr_sym_alloc( 10 ); // alloc with small value to force adjustment inside
E. Scott Daniels77526eb2020-09-17 16:39:31 -0400208 errors += fail_if_nil( st, "symtab pointer" );
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -0400209
E. Scott Daniels8790bf02019-04-23 12:59:28 +0000210 s = rmr_sym_put( st, foo, class, bar ); // add entry with string key; returns 1 if it was inserted
E. Scott Daniels77526eb2020-09-17 16:39:31 -0400211 errors += fail_if_false( s, "insert foo existed" );
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -0400212
E. Scott Daniels8790bf02019-04-23 12:59:28 +0000213 s = rmr_sym_put( st, foo, class+1, bar ); // add to table with a different class
E. Scott Daniels77526eb2020-09-17 16:39:31 -0400214 errors += fail_if_false( s, "insert foo existed" );
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -0400215
E. Scott Daniels8790bf02019-04-23 12:59:28 +0000216 s = rmr_sym_put( st, foo, class, bar ); // inserted above, should return not inserted (0)
E. Scott Daniels77526eb2020-09-17 16:39:31 -0400217 errors += fail_if_true( s, "insert foo existed" );
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -0400218
E. Scott Daniels77526eb2020-09-17 16:39:31 -0400219 errors += fetch( st, foo, class, 1 );
220 errors += fetch( st, goo, class, 0 ); // fetch non existant
E. Scott Daniels8790bf02019-04-23 12:59:28 +0000221 rmr_sym_stats( st, 4 ); // early stats at verbose level 4 so chatter is minimised
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -0400222 rmr_sym_dump( st );
223
E. Scott Daniels77526eb2020-09-17 16:39:31 -0400224 for( i = 2000; i < 3000; i++ ) { // bunch of dummy things to force chains in the table
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -0400225 rmr_sym_map( st, i, foo ); // add entry with unsigned integer key
226 }
E. Scott Daniels8790bf02019-04-23 12:59:28 +0000227 rmr_sym_stats( st, 0 ); // just the small facts to verify the 1000 we stuffed in
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -0400228 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
E. Scott Daniels77526eb2020-09-17 16:39:31 -0400232 errors += fail_if_false( s, "numeric add of key 1234 should not have existed" );
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -0400233 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 );
E. Scott Daniels77526eb2020-09-17 16:39:31 -0400238 errors += fail_if_false( counter, "expected counter after foreach to be non-zero" );
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -0400239
E. Scott Daniels77526eb2020-09-17 16:39:31 -0400240 errors += nfetch( st, 1234, 1 );
241 errors += nfetch( st, 2345, 1 );
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -0400242
E. Scott Daniels8790bf02019-04-23 12:59:28 +0000243 rmr_sym_del( st, foo, 0 );
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -0400244
E. Scott Daniels8790bf02019-04-23 12:59:28 +0000245 rmr_sym_stats( st, 0 );
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -0400246
247 rmr_sym_free( NULL ); // ensure it doesn't barf when given a nil pointer
248 rmr_sym_free( st );
249
E. Scott Daniels11838bc2021-04-22 16:34:08 -0400250 errors += thread_test(); // test as best we can for race issues
251
E. Scott Daniels77526eb2020-09-17 16:39:31 -0400252 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
E. Scott Daniels5ec64c52020-11-05 09:11:04 -0500259
E. Scott Daniels77526eb2020-09-17 16:39:31 -0400260 return !!(state + errors);
Ashwin Sridharanfd9cc7a2019-04-03 16:47:02 -0400261}
262