76aa72c25dc429d5d4231f741180dd12cdb5824d
[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         close_fifo( ctx, TEST_MTYPE, WRITER );                  // close one we know is there
128         close_fifo( ctx, 84306, WRITER );                               // coverage on error case
129
130         mcl_start_listening( ctx, port, 0 );                    // start the listener
131
132         // under test, the FOREVER = 0 keeps fanout from blocking; drive several times to cover all cases
133         mcl_fifo_fanout( ctx, 5, 1 );                                   // first rmr receive call will simulate a timeout
134         mcl_fifo_fanout( ctx, 5, 1 );                                   // second receive simulates a health check
135         mcl_fifo_fanout( ctx, 5, 1 );                                   // 3-n return alternating timeout messages; drive so that
136         mcl_fifo_fanout( ctx, 5, 1 );                                   // we will have several land in the FIFO
137         mcl_fifo_fanout( ctx, 5, 1 );
138         mcl_fifo_fanout( ctx, 5, 1 );
139         mcl_fifo_fanout( ctx, 5, 1 );
140
141         *timestamp = 0;
142         state = mcl_fifo_read1( ctx, TEST_MTYPE, payload, sizeof( payload ), TRUE );
143         if( state < 1 ) {
144                 fprintf( stderr, "[FAIL] fifo_read return positive value when expected to\n" );
145                 errors++;
146         }
147         state = mcl_fifo_tsread1( ctx, TEST_MTYPE, payload, sizeof( payload ), TRUE, timestamp );
148         if( state < 1 ) {
149                 fprintf( stderr, "[FAIL] fifo_read with timestamp return positive value when expected to\n" );
150                 errors++;
151         }
152
153         state = fifo_read1( NULL, TEST_MTYPE, payload, sizeof( payload ), 1, timestamp );               // coverage error check
154         if( state != 0 ) {
155                 fprintf( stderr, "[FAIL] fifo_read didn't return 0 when given a nil context to\n" );
156                 errors++;
157         }
158
159         mcl_fifo_fanout( ctx, 5, 0 );                                   // test with writing short header
160         mcl_fifo_fanout( ctx, 5, 0 );
161
162         // ------ some error/coverage testing ---------------------------
163         logit( LOG_CRIT, "critical message" );
164         logit( LOG_ERR, "error message" );
165         logit( LOG_WARN, "warning message" );
166         logit( LOG_STAT, "stats message" );
167
168         fprintf( stderr, "[INFO] expected create fail message should follow\n" );
169         bad_ctx = mcl_mk_context( "/nosuchdirectoryinthesystem" );              // create a context where fifo opens should fail
170         if( bad_ctx == NULL ) {
171                 fprintf( stderr, "[FAIL] couldn't make 'bad' context" );
172                 exit( 1 );
173         }
174
175         fref = NULL;
176         fd = suss_fifo( bad_ctx, TEST_MTYPE, 1, &fref );                                // should fail to open the file for writing beacuse directory is bad
177         if( fd >= 0 ) {
178                 fprintf( stderr, "[FAIL] suss_fifo returned a valid fd when given a context with a bad directory path\n" );
179                 errors++;
180         }
181         if( fref != NULL ) {
182                 fprintf( stderr, "[FAIL] suss_fifo returned an fref pointer when given a bad context\n" );
183                 errors++;
184         }
185
186         fd = suss_fifo( NULL, TEST_MTYPE, 1, &fref );                           // coverage nil pointer check
187         if( fd >= 0 ) {
188                 fprintf( stderr, "[FAIL] suss_fifo returned a valid fd when given a nil context a bad directory path\n" );
189                 errors++;
190         }
191
192         fd = suss_fifo( ctx, -1, 1, &fref );                            // mad message type check
193         if( fd >= 0 ) {
194                 fprintf( stderr, "[FAIL] suss_fifo returned a valid fd when given a bad message type\n" );
195                 errors++;
196         }
197
198         // -- buffer testing ------------------------------------------------------
199         bp = build_hdr( 1024, wbuf, 0 );
200         bp = build_hdr( 1024, NULL, 0 );
201         if( bp == NULL ) {
202                 fprintf( stderr, "[FAIL] build_hdr didn't return a buffer pointer when given a nil buffer\n" );
203                 errors++;
204         }
205         free( bp );
206
207         bp = build_hdr( 1024, wbuf, sizeof( wbuf ) );
208         if( bp == NULL ) {
209                 fprintf( stderr, "[FAIL] build_hdr didn't return a buffer pointer\n" );
210                 errors++;
211         }
212
213
214         // ----- msg receive testing ----------------------------------------------------
215         buf = mcl_get_msg( NULL, NULL, 1 );                     // drive nil pointer checks
216         if( buf != NULL ) {
217                 errors++;
218                 fprintf( stderr, "[FAIL], get_msg call with nil context returned a buffer pointer\n" );
219         }
220
221         buf = mcl_get_msg( ctx, NULL, 1 );                      // drive to force coverage; nothing is sent, so we can't validate buffer
222
223
224         mcl_fifo_one( NULL, NULL, 1, 1 );
225         mcl_fifo_one( ctx, NULL, 1, 1 );
226         mcl_fifo_one( ctx, wbuf, 0, 1 );
227         mcl_fifo_one( ctx, wbuf, 10, 100 );
228
229
230         // --- some rdc testing as best as we can without message generators --------
231         rdc_init( NULL, NULL, ".foo", ".bar" ); // coverage testing
232
233         ctx = setup_rdc();                                              // coverage test to ensure that it generates a context
234         if( ctx == NULL ) {
235                 fprintf( stderr, "[FAIL] setup_rdc did not return a context pointer\n" );
236                 errors++;
237         }
238
239         rdc_set_freq( NULL, 0 );                                        // error/nil test
240         rdc_set_freq( ctx, 0 );                                 // error/nil test
241         rdc_set_freq( ctx, 10 );                                // roll after 10seconds to test that
242
243         build_hdr( 1024, wbuf, sizeof( wbuf ) );
244         bp = NULL;
245         bp = rdc_init_buf( TEST_MTYPE, wbuf, 10, bp );                                  // set up for write
246         rdc_write( ctx, bp, payload, sizeof( payload ) );                               // write the raw data
247
248         fprintf( stderr, "[INFO] pausing to test rdc file rolling\n" );
249         sleep( 15 );
250         build_hdr( 1024, wbuf, sizeof( wbuf ) );
251         bp = NULL;
252         bp = rdc_init_buf( TEST_MTYPE, wbuf, 10, bp );
253         rdc_write( ctx, bp, payload, sizeof( payload ) );
254
255
256         // CAUTION:  filenames need to match those expected in the run script as it creates src, and will validate, destination files
257         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
258         if( state >= 0 ) {
259                 fprintf( stderr, "[FAIL] copy-unlink of bad file didn't return bad state\n" );
260                 errors++;
261         }
262         state = copy_unlink( "/tmp/mc_listener_test/copy_src", "/tmp/mc_listener_test-nodir/copy_dest", 0664 );
263         if( state >= 0 ) {
264                 fprintf( stderr, "[FAIL] copy-unlink of bad target didn't return bad state\n" );
265                 errors++;
266         }
267         state = copy_unlink( "/tmp/mc_listener_test/copy_src", "/tmp/mc_listener_test/copy_dest", 0664 );  // drive for coverage; setup script can check contents
268         if( state < 0 ) {
269                 fprintf( stderr, "[FAIL] copy-unlink expected success but failed\n" );
270                 errors++;
271         }
272         state = mvocp( "/tmp/mc_listener_test/bad-src-mv_src", "/tmp/mc_listener_test/mv_dest" );
273         if( state >= 0 ) {
274                 fprintf( stderr, "[FAIL] mv or copy expected failure didn't set bad state\n" );
275                 errors++;
276         }
277         state = mvocp( "/tmp/mc_listener_test/mv_src", "/tmp/mc_listener_test/mv_dest" );
278         if( state < 0 ) {
279                 fprintf( stderr, "[FAIL] mv or copy expected to succeed  didn't set good state\n" );
280                 errors++;
281         }
282
283
284         // ---- finally, check error count, write nice cheerful message and exit ----
285         if( ! errors ) {
286                 fprintf( stderr, "[PASS] unit_test: everything looks peachy\n" );
287         } else {
288                 fprintf( stderr, "[FAIL] unit_test: there were %d errors\n", errors );
289         }
290
291         return errors != 0;
292 }
293