Code for testing the filters now works
[trust_router.git] / common / tests / filt_test.c
1 /*
2  * Copyright (c) 2017, JANET(UK)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * 3. Neither the name of JANET(UK) nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31  * OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  */
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <assert.h>
38 #include <string.h>
39 #include <jansson.h>
40
41 #include <trp_internal.h>
42 #include <tid_internal.h>
43 #include <tr_filter.h>
44 #include <tr_config.h>
45
46 #define FILTER_PATH "./test-filters/"
47
48 /**
49  * Load a JSON file containing filters and return the filters from the first rp_client.
50  *
51  * @param fname File to read
52  * @param filt_out Will point to the loaded filter on success
53  * @return Return value from tr_cfg_parse_one_config_file()
54  */
55 int load_filter(const char *fname, TR_FILTER_SET **filts_out)
56 {
57   TR_CFG *cfg=tr_cfg_new(NULL);
58   TR_CFG_RC rc=TR_CFG_ERROR;
59
60   assert(fname);
61   assert(filts_out);
62
63   rc=tr_cfg_parse_one_config_file(cfg, fname);
64   if (rc!=TR_CFG_SUCCESS)
65     goto cleanup;
66
67   /* Steal the filter from the first rp_client */
68   assert(cfg);
69   assert(cfg->rp_clients);
70   assert(cfg->rp_clients->filters);
71   *filts_out=cfg->rp_clients->filters;
72   cfg->rp_clients->filters=NULL; /* can't use the _set_filter() because that will free the filter */
73   talloc_steal(NULL, *filts_out);
74
75 cleanup:
76   tr_cfg_free(cfg);
77   return rc;
78 }
79
80 /**
81  * Test that filters load / fail to load as expected.
82  *
83  * @return 1 if all tests pass
84  */
85 int test_load_filter(void)
86 {
87   TR_FILTER_SET *filts=NULL;
88
89   assert(TR_CFG_SUCCESS==load_filter(FILTER_PATH "valid-filt.json", &filts));
90   if (filts) tr_filter_set_free(filts);
91   filts=NULL;
92   assert(TR_CFG_NOPARSE==load_filter(FILTER_PATH "invalid-filt-repeated-key.json", &filts));
93   if (filts) tr_filter_set_free(filts);
94   filts=NULL;
95   assert(TR_CFG_ERROR==load_filter(FILTER_PATH "invalid-filt-unknown-field.json", &filts));
96   if (filts) tr_filter_set_free(filts);
97   filts=NULL;
98   return 1;
99 }
100
101 /**
102  * Read the first inforec from the TR_MSG encoded in JSON file named fname.
103  *
104  * @param fname Filename with path for TR_MSG JSON
105  * @return Pointer to the decoded inforec, or NULL on failure
106  */
107 TRP_INFOREC *load_inforec(const char *fname)
108 {
109   TR_MSG *msg=NULL;
110   TRP_UPD *upd=NULL;
111   TRP_INFOREC *inforec=NULL;
112   json_t *decoded=json_load_file(fname, JSON_REJECT_DUPLICATES|JSON_DISABLE_EOF_CHECK, NULL);
113   char *encoded=json_dumps(decoded, 0); /* silly way to read the file without mucking around */
114
115   assert(decoded);
116   json_decref(decoded);
117
118   assert(encoded);
119   assert(msg=tr_msg_decode(encoded, strlen(encoded)));
120   assert(upd=tr_msg_get_trp_upd(msg));
121   assert(inforec=trp_upd_get_inforec(upd));
122   /* now remove the inforec from the update context */
123   talloc_steal(NULL, inforec);
124   tr_msg_free_decoded(msg);
125   tr_msg_free_encoded(encoded);
126   return inforec;
127 }
128
129 /* make this bigger than your message file */
130 #define MAX_FILE_SIZE 20000
131 TID_REQ *load_tid_req(const char *fname)
132 {
133   TID_REQ *out=NULL;
134   TR_MSG *msg=NULL;
135   FILE *f=NULL;
136   char *msgbuf=NULL;
137   size_t msglen=0;
138
139   msgbuf=malloc(MAX_FILE_SIZE);
140   assert(msgbuf);
141   f=fopen(fname, "r");
142   assert(f);
143   msglen=fread(msgbuf, 1, MAX_FILE_SIZE, f);
144   assert(msglen);
145   assert(feof(f));
146   msg=tr_msg_decode(msgbuf, msglen);
147   free(msgbuf);
148   msgbuf=NULL;
149
150   assert(msg);
151   assert(tr_msg_get_msg_type(msg)==TID_REQUEST);
152
153   /* take the tid req out of the msg */
154   out=tr_msg_get_req(msg);
155   tr_msg_set_req(msg, NULL);
156   assert(out);
157
158   tr_msg_free_decoded(msg);
159   return out;
160 }
161
162 /**
163  * Read a set of filters from a config JSON in filt_fname and test against the tid_req or inforec in target_fname.
164  * If expect==1, succeed if the target is accepted by the filter, otherwise succeed if it is rejected.
165  * Takes filters from the first rp_realm defined in the filter file and the first inforec or tid req from
166  * the target file.
167  *
168  * @param filt_fname Name of JSON file containing filters
169  * @param ftype Which type of filter to test
170  * @param target_fname  Name of JSON file containing inforec
171  * @param expected_match 1 if we expect a match, 0 otherwise
172  * @param expected_action Expected action if the filter matches
173  * @return 1 if expected result is obtained, 0 or does not return otherwise
174  */
175 int test_one_filter(const char *filt_fname,
176                     TR_FILTER_TYPE ftype,
177                     const char *target_fname,
178                     int expected_match,
179                     TR_FILTER_ACTION expected_action)
180 {
181   void *target=NULL;
182   TR_FILTER_SET *filts=NULL;
183   TR_FILTER_ACTION action=TR_FILTER_ACTION_UNKNOWN;
184
185   /* load filter for first test */
186   assert(TR_CFG_SUCCESS==load_filter(filt_fname, &filts));
187
188   /* load the target req or inforec */
189   switch(ftype) {
190     case TR_FILTER_TYPE_TID_INBOUND:
191       target=load_tid_req(target_fname);
192       break;
193
194     case TR_FILTER_TYPE_TRP_INBOUND:
195     case TR_FILTER_TYPE_TRP_OUTBOUND:
196       target=load_inforec(target_fname);
197       break;
198
199     default:
200       printf("Unknown filter type.\n");
201   }
202   assert(target);
203
204   assert(expected_match==tr_filter_apply(target, tr_filter_set_get(filts, ftype), NULL, &action));
205   if (expected_match==TR_FILTER_MATCH)
206     assert(action==expected_action);
207
208   tr_filter_set_free(filts);
209   switch(ftype) {
210     case TR_FILTER_TYPE_TID_INBOUND:
211       tid_req_free((TID_REQ *)target);
212       break;
213
214     case TR_FILTER_TYPE_TRP_INBOUND:
215     case TR_FILTER_TYPE_TRP_OUTBOUND:
216       trp_inforec_free((TRP_INFOREC *)target);
217       break;
218
219     default:
220       printf("Unknown filter type.\n");
221   }
222   return 1;
223 }
224
225 int test_filter(void)
226 {
227   json_t *test_list=json_load_file(FILTER_PATH "filter-tests.json", JSON_DISABLE_EOF_CHECK, NULL);
228   json_t *this;
229   size_t ii;
230   const char *filt_file, *target_file;
231   TR_FILTER_TYPE ftype;
232   int expect_match;
233   TR_FILTER_ACTION action;
234
235   json_array_foreach(test_list, ii, this) {
236     printf("Running filter test case: %s\n", json_string_value(json_object_get(this, "test label")));
237     fflush(stdout);
238
239     filt_file=json_string_value(json_object_get(this, "filter file"));
240     ftype=tr_filter_type_from_string(json_string_value(json_object_get(this, "filter type")));
241     target_file=json_string_value(json_object_get(this, "target file"));
242     if (0==strcmp("yes", json_string_value(json_object_get(this, "expect match"))))
243       expect_match=TR_FILTER_MATCH;
244     else
245       expect_match=TR_FILTER_NO_MATCH;
246
247     if (0==strcmp("accept", json_string_value(json_object_get(this, "action"))))
248       action=TR_FILTER_ACTION_ACCEPT;
249     else
250       action=TR_FILTER_ACTION_REJECT;
251
252     assert(test_one_filter(filt_file, ftype, target_file, expect_match, action));
253   }
254
255   return 1;
256 }
257
258
259
260 int main(void)
261 {
262   assert(test_load_filter());
263   assert(test_filter());
264   printf("Success\n");
265   return 0;
266 }