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