9699f6cae430c7d815bba6fcc1e7d7a37ef712de
[ric-app/mc.git] / sidecars / listener / unit_test.c
1 // vim: ts=4 sw=4 noet:
2 /*
3  --------------------------------------------------------------------------------
4         Copyright (c) 2018-2019 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         Mnemonic:       unit_test.c
22         Abstract:       Basic unit tests for the mc listener.
23         Date:           22 August 2019
24         Author:         E. Scott Daniels
25 */
26
27 #define FOREVER 0                       // allows forever loops in mcl code to escape after one loop
28
29 #include <unistd.h>
30 #include <errno.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <time.h>
34 #include <string.h>
35 #include <fcntl.h>
36 #include <signal.h>
37 #include <sys/stat.h>
38 #include <sys/types.h>
39
40 #include "test_rmr_em.c"                // emulated rmr functions (for receives)
41
42 // this/these are what we are testing; include them directly (must be after forever def)
43 #include "mcl.c"
44 #include "rdc.c"
45
46 /*
47         Set up env things for the rdc setup call.
48 */
49 static void set_env() {
50         setenv( "MCL_RDC_ENABLE", "1", 1 );                                                                     // cause 'raw' capture to be setup
51         setenv( "MCL_RDC_STAGE", "/tmp/mc_listener_test/stage", 1 );            // unit test script should create and will purge after
52         setenv( "MCL_RDC_FINAL", "/tmp/mc_listener_test/final", 1 );
53         setenv( "MCL_RDC_SUFFIX", ".xxx", 1 );
54         setenv( "MCL_RDC_DONE", ".done", 1 );
55         setenv( "MCL_RDC_FREQ", "10", 1 );
56 }
57
58 /*
59         Parms:  [fifo-dir-name]
60 */
61 int main( int argc,  char** argv ) {
62         void*   ctx;
63         void*   bad_ctx;                                // context with a bad directory path for coverage/error testing
64         int             errors = 0;
65         char*   dname = "/tmp/fifos";
66         char*   port = "4560";
67         int             fd;
68         int             fd2;
69         int             rfd;                                    // a reader file des so we can read what we write
70         fifo_t* fref = NULL;                    // fifo type reference; we just verify that suss sets it
71         char    wbuf[2048];
72         char    payload[1024];
73         char*   bp;
74         void*   buf;
75         int state;
76         char    timestamp[1024];                // read will put a timestamp here
77
78         if( argc > 1 ) {
79                 dname = argv[1];
80         }
81         
82         set_env();                                                      // set env that setup_rdc() looks for
83
84         ctx = mcl_mk_context( dname );                  // allocate the context
85         if( ctx == NULL ) {
86                 fprintf( stderr, "[FAIL] couldn't make context\n" );
87                 exit( 1 );
88         }
89
90         mcl_set_sigh();                                                                         // prevent colobber from broken pipe
91
92         open_fifo( ctx, 100, WRITER );                                          // open dummy to prevent blocking reader
93         rfd = open_fifo( ctx, 100, READER );                            // open a reader to check fanout output
94         if( rfd < 0 ) {
95                 fprintf( stderr, "[FAIL] unable to open a pipe reader for type == 100\n" );
96                 errors++;
97         }
98
99         fd = suss_fifo( ctx, 100, 1, &fref );                           // should open the file for writing and return the fdes
100         if( fd < 0 ) {
101                 fprintf( stderr, "[FAIL] suss_fifo did not return a valid fd\n" );
102                 errors++;
103         }
104
105         if( fref == NULL ) {
106                 fprintf( stderr, "[FAIL] suss_fifo did not set the fifo reference pointer\n" );
107                 errors++;
108         } else {
109                 chalk_ok( fref );
110                 chalk_error( fref );
111         }
112
113         fd2= suss_fifo( ctx, 100, 0, NULL );                            // should open the file file for reading and return a different fd
114         if( fd < 0 ) {
115                 fprintf( stderr, "[FAIL] suss_fifo did not return a valid fd\n" );
116                 errors++;
117         }
118         if( fd == fd2 ) {
119                 fprintf( stderr, "[FAIL] reading and writing fifo file descriptors expected to differ; both were %d\n", fd );
120                 errors++;
121         }
122
123         mcl_start_listening( ctx, port, 0 );                    // start the listener
124
125                                                                                                         // under test, the forever keeps fanout from blocking; drive for each of two cases:
126         mcl_fifo_fanout( ctx, 5, 1 );                                   // first rmr receive call will simulate a timeout
127         mcl_fifo_fanout( ctx, 5, 1 );                                   // second receive call simualtes a message arriving
128         mcl_fifo_fanout( ctx, 5, 1 );                                   // another round so there are two to read
129         mcl_fifo_fanout( ctx, 5, 1 );
130
131         *timestamp = 0;
132         state = mcl_fifo_read1( ctx, 100, payload, sizeof( payload ), TRUE );
133         if( state < 1 ) {
134                 fprintf( stderr, "[FAIL] fifo_read return positive value when expected to\n" );
135                 errors++;
136         }
137         state = mcl_fifo_tsread1( ctx, 100, payload, sizeof( payload ), TRUE, timestamp );
138         if( state < 1 ) {
139                 fprintf( stderr, "[FAIL] fifo_read with timestamp return positive value when expected to\n" );
140                 errors++;
141         }
142
143         state = fifo_read1( NULL, 100, payload, sizeof( payload ), 1, timestamp );              // coverage error check
144         if( state != 0 ) {
145                 fprintf( stderr, "[FAIL] fifo_read didn't return 0 when given a nil context to\n" );
146                 errors++;
147         }
148
149         mcl_fifo_fanout( ctx, 5, 0 );                                   // test with writing short header
150         mcl_fifo_fanout( ctx, 5, 0 );
151
152         // ------ some error/coverage testing ---------------------------
153         logit( LOG_CRIT, "critical message" );
154         logit( LOG_ERR, "error message" );
155         logit( LOG_WARN, "warning message" );
156         logit( LOG_STAT, "stats message" );
157
158         bad_ctx = mcl_mk_context( "/nosuchdirectoryinthesystem" );              // create a context where fifo opens should fail
159         if( bad_ctx == NULL ) {
160                 fprintf( stderr, "[FAIL] couldn't make 'bad' context" );
161                 exit( 1 );
162         }
163
164         fref = NULL;
165         fd = suss_fifo( bad_ctx, 100, 1, &fref );                               // should fail to open the file for writing beacuse directory is bad
166         if( fd >= 0 ) {
167                 fprintf( stderr, "[FAIL] suss_fifo returned a valid fd when given a context with a bad directory path\n" );
168                 errors++;
169         }
170         if( fref != NULL ) {
171                 fprintf( stderr, "[FAIL] suss_fifo returned an fref pointer when given a bad context\n" );
172                 errors++;
173         }
174
175         fd = suss_fifo( NULL, 100, 1, &fref );                          // coverage nil pointer check
176         if( fd >= 0 ) {
177                 fprintf( stderr, "[FAIL] suss_fifo returned a valid fd when given a nil context a bad directory path\n" );
178                 errors++;
179         }
180
181         fd = suss_fifo( ctx, -1, 1, &fref );                            // mad message type check
182         if( fd >= 0 ) {
183                 fprintf( stderr, "[FAIL] suss_fifo returned a valid fd when given a bad message type\n" );
184                 errors++;
185         }
186
187         // -- buffer testing ------------------------------------------------------
188         bp = build_hdr( 1024, wbuf, 0 );
189         bp = build_hdr( 1024, NULL, 0 );
190         if( bp == NULL ) {
191                 fprintf( stderr, "[FAIL] build_hdr didn't return a buffer pointer when given a nil buffer\n" );
192                 errors++;
193         }
194         free( bp );
195
196         bp = build_hdr( 1024, wbuf, sizeof( wbuf ) );
197         if( bp == NULL ) {
198                 fprintf( stderr, "[FAIL] build_hdr didn't return a buffer pointer\n" );
199                 errors++;
200         }
201
202
203         // ----- msg receive testing ----------------------------------------------------
204         buf = mcl_get_msg( NULL, NULL, 1 );                     // drive nil pointer checks
205         if( buf != NULL ) {
206                 errors++;
207                 fprintf( stderr, "[FAIL], get_msg call with nil context returned a buffer pointer\n" );
208         }
209
210         buf = mcl_get_msg( ctx, NULL, 1 );                      // drive to force coverage; nothing is sent, so we can't validate buffer
211
212
213         mcl_fifo_one( NULL, NULL, 1, 1 );
214         mcl_fifo_one( ctx, NULL, 1, 1 );
215         mcl_fifo_one( ctx, wbuf, 0, 1 );
216         mcl_fifo_one( ctx, wbuf, 10, 100 );
217
218
219         // --- some rdc testing as best as we can without message generators --------
220         rdc_init( NULL, NULL, ".foo", ".bar" ); // coverage testing
221
222         ctx = setup_rdc();                                              // coverage test to ensure that it generates a context
223         if( ctx == NULL ) {
224                 fprintf( stderr, "[FAIL] setup_rdc did not return a context pointer\n" );
225                 errors++;
226         }
227
228         rdc_set_freq( NULL, 0 );                                        // error/nil test
229         rdc_set_freq( ctx, 0 );                                 // error/nil test
230         rdc_set_freq( ctx, 10 );                                // roll after 10seconds to test that
231
232         build_hdr( 1024, wbuf, sizeof( wbuf ) );
233         bp = NULL;
234         bp = rdc_init_buf( 100, wbuf, 10, bp );                                 // set up for write
235         rdc_write( ctx, bp, payload, sizeof( payload ) );                               // write the raw data
236
237         fprintf( stderr, "[INFO] pausing to test rdc file rolling\n" );
238         sleep( 15 );
239         build_hdr( 1024, wbuf, sizeof( wbuf ) );
240         bp = NULL;
241         bp = rdc_init_buf( 100, wbuf, 10, bp );
242         rdc_write( ctx, bp, payload, sizeof( payload ) );
243
244
245         // CAUTION:  filenames need to match those expected in the run script as it creates src, and will validate, destination files
246         state = copy_unlink( "/tmp/mc_listener_test/no-such-copy_src", "/tmp/mc_listener_test/copy_dest", 0664 );  // first couple drive for error and coverage
247         if( state >= 0 ) {
248                 fprintf( stderr, "[FAIL] copy-unlink of bad file didn't return bad state\n" );
249                 errors++;
250         }
251         state = copy_unlink( "/tmp/mc_listener_test/copy_src", "/tmp/mc_listener_test-nodir/copy_dest", 0664 );
252         if( state >= 0 ) {
253                 fprintf( stderr, "[FAIL] copy-unlink of bad target didn't return bad state\n" );
254                 errors++;
255         }
256         state = copy_unlink( "/tmp/mc_listener_test/copy_src", "/tmp/mc_listener_test/copy_dest", 0664 );  // drive for coverage; setup script can check contents
257         if( state < 0 ) {
258                 fprintf( stderr, "[FAIL] copy-unlink expected success but failed\n" );
259                 errors++;
260         }
261         state = mvocp( "/tmp/mc_listener_test/bad-src-mv_src", "/tmp/mc_listener_test/mv_dest" );
262         if( state >= 0 ) {
263                 fprintf( stderr, "[FAIL] mv or copy expected failure didn't set bad state\n" );
264                 errors++;
265         }
266         state = mvocp( "/tmp/mc_listener_test/mv_src", "/tmp/mc_listener_test/mv_dest" );
267         if( state < 0 ) {
268                 fprintf( stderr, "[FAIL] mv or copy expected to succeed  didn't set good state\n" );
269                 errors++;
270         }
271
272
273         // ---- finally, check error count, write nice cheerful message and exit ----
274         if( ! errors ) {
275                 fprintf( stderr, "[PASS] unit_test: everything looks peachy\n" );
276         } else {
277                 fprintf( stderr, "[FAIL] unit_test: there were %d errors\n", errors );
278         }
279
280         return errors != 0;
281 }
282