d7dfe064ccc66f3eba9d65227372c1dce9c2f17e
[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 #if JANSSON_VERSION_HEX < 0x020500
41 #include "../jansson_iterators.h"
42 #endif
43 #include <trp_internal.h>
44 #include <tid_internal.h>
45 #include <tr_filter.h>
46 #include <tr_config.h>
47
48 #define FILTER_PATH "./test-filters/"
49
50 /**
51  * Load a JSON file containing filters and return the filters from the first rp_client.
52  *
53  * @param fname File to read
54  * @param filt_out Will point to the loaded filter on success
55  * @return Return value from tr_cfg_parse_one_config_file()
56  */
57 int load_filter(char *fname, TR_FILTER_SET **filts_out)
58 {
59   TR_CFG_MGR *cfg_mgr=tr_cfg_mgr_new(NULL);
60   TR_CFG_RC rc=TR_CFG_ERROR;
61
62   assert(cfg_mgr);
63   assert(fname);
64   assert(filts_out);
65
66   rc=tr_parse_config(cfg_mgr, 1, &fname);
67   if (rc!=TR_CFG_SUCCESS)
68     goto cleanup;
69
70   /* Steal the filter from the first rp_client */
71   assert(cfg_mgr->new);
72   assert(cfg_mgr->new->rp_clients);
73   assert(cfg_mgr->new->rp_clients->filters);
74   *filts_out=cfg_mgr->new->rp_clients->filters;
75   cfg_mgr->new->rp_clients->filters=NULL; /* can't use the _set_filter() because that will free the filter */
76   talloc_steal(NULL, *filts_out);
77
78 cleanup:
79   tr_cfg_mgr_free(cfg_mgr);
80   return rc;
81 }
82
83 /**
84  * Test that filters load / fail to load as expected.
85  *
86  * @return 1 if all tests pass
87  */
88 int test_load_filter(void)
89 {
90   TR_FILTER_SET *filts=NULL;
91
92   assert(TR_CFG_SUCCESS==load_filter(FILTER_PATH "valid-filt.json", &filts));
93   if (filts) tr_filter_set_free(filts);
94   filts=NULL;
95   assert(TR_CFG_NOPARSE==load_filter(FILTER_PATH "invalid-filt-repeated-key.json", &filts));
96   if (filts) tr_filter_set_free(filts);
97   filts=NULL;
98   assert(TR_CFG_NOPARSE==load_filter(FILTER_PATH "invalid-filt-unknown-field.json", &filts));
99   if (filts) tr_filter_set_free(filts);
100   filts=NULL;
101   return 1;
102 }
103
104 /**
105  * Read the first inforec from the TR_MSG encoded in JSON file named fname.
106  *
107  * @param fname Filename with path for TR_MSG JSON
108  * @return Pointer to the decoded inforec, or NULL on failure
109  */
110 TRP_INFOREC *load_inforec(const char *fname)
111 {
112   TR_MSG *msg=NULL;
113   TRP_UPD *upd=NULL;
114   TRP_INFOREC *inforec=NULL;
115   json_t *decoded=json_load_file(fname, JSON_REJECT_DUPLICATES|JSON_DISABLE_EOF_CHECK, NULL);
116   char *encoded=json_dumps(decoded, 0); /* silly way to read the file without mucking around */
117
118   assert(decoded);
119   json_decref(decoded);
120
121   assert(encoded);
122   assert(msg=tr_msg_decode(encoded, strlen(encoded)));
123   assert(upd=tr_msg_get_trp_upd(msg));
124   assert(inforec=trp_upd_get_inforec(upd));
125   /* now remove the inforec from the update context */
126   talloc_steal(NULL, inforec);
127   tr_msg_free_decoded(msg);
128   tr_msg_free_encoded(encoded);
129   return inforec;
130 }
131
132 /* make this bigger than your message file */
133 #define MAX_FILE_SIZE 20000
134 TID_REQ *load_tid_req(const char *fname)
135 {
136   TID_REQ *out=NULL;
137   TR_MSG *msg=NULL;
138   FILE *f=NULL;
139   char *msgbuf=NULL;
140   size_t msglen=0;
141
142   msgbuf=malloc(MAX_FILE_SIZE);
143   assert(msgbuf);
144   f=fopen(fname, "r");
145   assert(f);
146   msglen=fread(msgbuf, 1, MAX_FILE_SIZE, f);
147   assert(msglen);
148   assert(feof(f));
149   msg=tr_msg_decode(msgbuf, msglen);
150   free(msgbuf);
151   msgbuf=NULL;
152
153   assert(msg);
154   assert(tr_msg_get_msg_type(msg)==TID_REQUEST);
155
156   /* take the tid req out of the msg */
157   out=tr_msg_get_req(msg);
158   tr_msg_set_req(msg, NULL);
159   assert(out);
160
161   tr_msg_free_decoded(msg);
162   return out;
163 }
164
165 /**
166  * Read a set of filters from a config JSON in filt_fname and test against the tid_req or inforec in target_fname.
167  * If expect==1, succeed if the target is accepted by the filter, otherwise succeed if it is rejected.
168  * Takes filters from the first rp_realm defined in the filter file and the first inforec or tid req from
169  * the target file.
170  *
171  * @param filt_fname Name of JSON file containing filters
172  * @param ftype Which type of filter to test
173  * @param target_fname  Name of JSON file containing inforec
174  * @param expected_match 1 if we expect a match, 0 otherwise
175  * @param expected_action Expected action if the filter matches
176  * @return 1 if expected result is obtained, 0 or does not return otherwise
177  */
178 int test_one_filter(char *filt_fname,
179                     TR_FILTER_TYPE ftype,
180                     const char *target_fname,
181                     int expected_match,
182                     TR_FILTER_ACTION expected_action)
183 {
184   TR_FILTER_TARGET *target=NULL;
185   TR_FILTER_SET *filts=NULL;
186   TR_FILTER_ACTION action=TR_FILTER_ACTION_UNKNOWN;
187
188   /* load filter for first test */
189   assert(TR_CFG_SUCCESS==load_filter(filt_fname, &filts));
190
191   /* load the target req or inforec */
192   switch(ftype) {
193     case TR_FILTER_TYPE_TID_INBOUND:
194       target=tr_filter_target_tid_req(NULL, load_tid_req(target_fname));
195       break;
196
197     case TR_FILTER_TYPE_TRP_INBOUND:
198     case TR_FILTER_TYPE_TRP_OUTBOUND:
199       /* TODO: read realm and community */
200       target= tr_filter_target_trp_inforec(NULL, NULL, load_inforec(target_fname));
201       break;
202
203     default:
204       printf("Unknown filter type.\n");
205   }
206   assert(target);
207
208   assert(expected_match==tr_filter_apply(target, tr_filter_set_get(filts, ftype), NULL, &action));
209   if (expected_match==TR_FILTER_MATCH)
210     assert(action==expected_action);
211
212   tr_filter_set_free(filts);
213   switch(ftype) {
214     case TR_FILTER_TYPE_TID_INBOUND:
215       tid_req_free(target->tid_req);
216       break;
217
218     case TR_FILTER_TYPE_TRP_INBOUND:
219     case TR_FILTER_TYPE_TRP_OUTBOUND:
220       trp_inforec_free(target->trp_inforec);
221       if (target->trp_upd!=NULL)
222         trp_upd_free(target->trp_upd);
223       break;
224
225     default:
226       printf("Unknown filter type.\n");
227   }
228   tr_filter_target_free(target);
229   return 1;
230 }
231
232 int test_filter(void)
233 {
234   json_t *test_list=json_load_file(FILTER_PATH "filter-tests.json", JSON_DISABLE_EOF_CHECK, NULL);
235   json_t *this;
236   size_t ii;
237   char *filt_file, *target_file;
238   TR_FILTER_TYPE ftype;
239   int expect_match;
240   TR_FILTER_ACTION action;
241
242   json_array_foreach(test_list, ii, this) {
243     printf("Running filter test case: %s\n", json_string_value(json_object_get(this, "test label")));
244     fflush(stdout);
245
246     filt_file=talloc_strdup(NULL, json_string_value(json_object_get(this, "filter file")));
247     ftype=tr_filter_type_from_string(json_string_value(json_object_get(this, "filter type")));
248     target_file=talloc_strdup(NULL, json_string_value(json_object_get(this, "target file")));
249     if (0==strcmp("yes", json_string_value(json_object_get(this, "expect match"))))
250       expect_match=TR_FILTER_MATCH;
251     else
252       expect_match=TR_FILTER_NO_MATCH;
253
254     if (0==strcmp("accept", json_string_value(json_object_get(this, "action"))))
255       action=TR_FILTER_ACTION_ACCEPT;
256     else
257       action=TR_FILTER_ACTION_REJECT;
258
259     assert(test_one_filter(filt_file, ftype, target_file, expect_match, action));
260
261     talloc_free(filt_file);
262     talloc_free(target_file);
263   }
264
265   return 1;
266 }
267
268
269
270 int main(void)
271 {
272   assert(test_load_filter());
273   assert(test_filter());
274   printf("Success\n");
275   return 0;
276 }