2 ==================================================================================
3 Copyright (c) 2019 Nokia
4 Copyright (c) 2018-2019 AT&T Intellectual Property.
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
10 http://www.apache.org/licenses/LICENSE-2.0
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 ==================================================================================
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
27 Author: E. Scott Daniels
32 #define NO_DUMMY_RMR 1 // no dummy rmr functions; we don't pull in rmr.h or agnostic.h
34 #define NO_PRIVATE_HEADERS
37 #include <rmr_agnostic.h>
38 #include "test_support.c"
39 #include "rmr_symtab.h"
41 #include "symtab.c" // module under test
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
50 static int fetch( void* st, char* key, int class, int expected ) {
54 val = rmr_sym_get( st, key, class );
56 fprintf( stderr, "[%s] get returns key=%s val=%s\n", !expected ? "FAIL" : "OK", key, val );
63 fprintf( stderr, "[%s] string key fetch return nil\n", expected ? "FAIL" : "OK" );
73 static int nfetch( void* st, int key, int expected ) {
77 val = rmr_sym_pull( st, key );
79 fprintf( stderr, "[%s] get returns key=%d val=%s\n", !expected ? "FAIL" : "OK", key, val );
85 fprintf( stderr, "[%s] get return nil for key=%d\n", expected ? "FAIL" : "OK", key );
95 // ----------------- thread based tests -------------------------------------------------------------------
96 #define NUM_KEYS 512 // number of unique keys
97 #define NUM_ATTEMPTS 1000000
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.
103 static void* reader( void* st ) {
106 int ncount = 0; // number not found
107 int fcount = 0; // number found
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 ) {
118 fprintf( stderr, "<info> reader finished: n=%d f=%d\n", ncount, fcount ); // there is no right answer
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.
127 static void* writer( void* st ) {
130 int ncount = 0; // number first inserts
131 int rcount = 0; // number replacements
135 fprintf( stderr, "<INFO> writer now turning\n" );
136 for( i = 0; i < NUM_ATTEMPTS; i++ ) {
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 ) ) {
147 if( ncount != NUM_ATTEMPTS ) {
148 fprintf( stderr, "<FAIL> writer finished: n=%d r=%d\n", ncount, rcount ); // there is no right answer
151 fprintf( stderr, "<INFO> writer finished: n=%d r=%d\n", ncount, rcount ); // there is no right answer
158 Drive a concurrent read/write test to ensure no race issues.
160 static int thread_test( ) {
166 st = rmr_sym_alloc( 128 ); // should force collisions
168 fprintf( stderr, "<INFO> starting writer\n" );
169 pthread_create( &tids[0], NULL, writer, st );
171 for( i = 1; i <= n2start; i++ ) {
172 fprintf( stderr, "<INFO> starting reader %d\n", i );
173 pthread_create( &tids[i], NULL, reader, st );
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 );
183 rmr_sym_stats( st, 1 );
187 // ---------------------------------------------------------------------------------------------------------
190 Driven by foreach class -- just incr the counter.
192 static void each_counter( void* a, void* b, const char* c, void* d, void* e ) {
200 char* goo = "goo"; // name not in symtab
207 st = rmr_sym_alloc( 10 ); // alloc with small value to force adjustment inside
208 errors += fail_if_nil( st, "symtab pointer" );
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" );
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" );
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" );
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
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
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
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" );
237 rmr_sym_foreach_class( st, 0, each_counter, NULL );
238 errors += fail_if_false( counter, "expected counter after foreach to be non-zero" );
240 errors += nfetch( st, 1234, 1 );
241 errors += nfetch( st, 2345, 1 );
243 rmr_sym_del( st, foo, 0 );
245 rmr_sym_stats( st, 0 );
247 rmr_sym_free( NULL ); // ensure it doesn't barf when given a nil pointer
250 test_summary( errors, "symtab tests" );
251 if( state + errors == 0 ) {
252 fprintf( stderr, "<PASS> all symtab tests were OK\n\n" );
254 fprintf( stderr, "<FAIL> %d errors in symtab code\n\n", errors );
257 errors += thread_test();
259 return !!(state + errors);