blob: 2ec94f341d088b866d092cded31882496802cdbb [file] [log] [blame]
Brian Waters13d96012017-12-08 16:53:31 -06001/*********************************************************************************************************
2* Software License Agreement (BSD License) *
3* Author: Sebastien Decugis <sdecugis@freediameter.net> *
4* *
5* Copyright (c) 2013, WIDE Project and NICT *
6* All rights reserved. *
7* *
8* Redistribution and use of this software in source and binary forms, with or without modification, are *
9* permitted provided that the following conditions are met: *
10* *
11* * Redistributions of source code must retain the above *
12* copyright notice, this list of conditions and the *
13* following disclaimer. *
14* *
15* * Redistributions in binary form must reproduce the above *
16* copyright notice, this list of conditions and the *
17* following disclaimer in the documentation and/or other *
18* materials provided with the distribution. *
19* *
20* * Neither the name of the WIDE Project or NICT nor the *
21* names of its contributors may be used to endorse or *
22* promote products derived from this software without *
23* specific prior written permission of WIDE Project and *
24* NICT. *
25* *
26* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
27* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
28* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
29* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
30* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
31* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
32* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
33* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
34*********************************************************************************************************/
35
36#include "tests.h"
37
38/* The connection string to the database */
39#ifndef TEST_CONNINFO
40#error "Please specify the conninfo information"
41#endif /* TEST_CONNINFO */
42
43/* The table used for tests. This table will receive the following instructions:
44DROP TABLE <table>;
45CREATE TABLE <table>
46(
47 recorded_on timestamp with time zone NOT NULL,
48 "Accounting-Record-Type" integer,
49 "Session-Id" bytea,
50 "Accounting-Record-Number" integer,
51 "Route-Record1" bytea,
52 "Route-Record2" bytea,
53 "Route-Record3" bytea,
54 "Route-Record4" bytea
55);
56*/
57#define TABLE "incoming_test"
58
59#include "app_acct.h"
60#include <libpq-fe.h>
61
62static int add_avp_in_conf(char * avpname, int multi)
63{
64 struct acct_conf_avp *new;
65 struct dict_object * dict;
66 struct dict_avp_data dictdata;
67
68 /* Validate the avp name first */
69 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, avpname, &dict, ENOENT) );
70 CHECK_FCT( fd_dict_getval( dict, &dictdata ));
71
72 /* Create a new entry */
73 CHECK_MALLOC( new = malloc(sizeof(struct acct_conf_avp)) );
74 memset(new, 0, sizeof(struct acct_conf_avp));
75 fd_list_init(&new->chain, NULL);
76 new->avpname = avpname;
77 new->avpobj = dict;
78 new->avptype = dictdata.avp_basetype;
79 new->multi = multi;
80
81 /* Add this new entry at the end of the list */
82 fd_list_insert_before( &acct_config->avps, &new->chain );
83
84 return 0;
85}
86
87#define LOCAL_ID "test.app.acct"
88#define LOCAL_REALM "app.acct"
89
90/* Main test routine */
91int main(int argc, char *argv[])
92{
93 extern pthread_key_t connk; /* in acct_db.c */
94 PGconn *conn;
95 extern int fd_ext_init(int major, int minor, char * conffile); /* defined in include's extension.h */
96 extern void fd_ext_fini(void); /* defined in the extension itself */
97 struct msg * msg;
98 os0_t sess_bkp;
99 size_t sess_bkp_len;
100
101 /* First, initialize the daemon modules */
102 INIT_FD();
103 fd_g_config->cnf_diamid = strdup(LOCAL_ID);
104 fd_g_config->cnf_diamid_len = CONSTSTRLEN(LOCAL_ID);
105 fd_g_config->cnf_diamrlm = strdup(LOCAL_REALM);
106 fd_g_config->cnf_diamrlm_len = CONSTSTRLEN(LOCAL_REALM);
107
108 CHECK( 0, fd_queues_init() );
109 CHECK( 0, fd_msg_init() );
110 CHECK( 0, fd_rtdisp_init() );
111
112 /* Initialize the extension configuration for the test */
113 {
114 CHECK( 0, acct_conf_init() );
115 acct_config->conninfo = strdup(TEST_CONNINFO);
116 acct_config->tablename = strdup(TABLE);
117 acct_config->tsfield = strdup("recorded_on");
118 CHECK( 0, add_avp_in_conf(strdup("Session-Id"), 0) );
119 CHECK( 0, add_avp_in_conf(strdup("Accounting-Record-Type"), 0) );
120 CHECK( 0, add_avp_in_conf(strdup("Accounting-Record-Number"), 0) );
121 CHECK( 0, add_avp_in_conf(strdup("Route-Record"), 4) );
122
123 /* Now, call the one of the extension */
124 CHECK( 0, fd_ext_init(FD_PROJECT_VERSION_MAJOR, FD_PROJECT_VERSION_MINOR,NULL) );
125 conn = pthread_getspecific(connk);
126 }
127
128 /* Drop and recreate the table for the test */
129 {
130 PGresult * res;
131 CHECK( CONNECTION_OK, PQstatus(conn) );
132
133 res = PQexec(conn, "DROP TABLE " TABLE ";");
134 CHECK( PGRES_COMMAND_OK, PQresultStatus(res) );
135 PQclear(res);
136
137 res = PQexec(conn, "CREATE TABLE " TABLE " ( "
138 " recorded_on timestamp with time zone NOT NULL, "
139 " \"Accounting-Record-Type\" integer, "
140 " \"Session-Id\" bytea, "
141 " \"Accounting-Record-Number\" integer, "
142 " \"Route-Record1\" bytea, "
143 " \"Route-Record2\" bytea, "
144 " \"Route-Record3\" bytea, "
145 " \"Route-Record4\" bytea "
146 ");"
147 );
148 CHECK( PGRES_COMMAND_OK, PQresultStatus(res) );
149 PQclear(res);
150 }
151
152 /* OK, we are ready to test now. Create an ACR message that will pass the ABNF check */
153 {
154 struct dict_object * d = NULL;
155 struct avp *avp = NULL;
156 union avp_value avp_val;
157
158 /* Now find the ACR dictionary object */
159 CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Accounting-Request", &d, ENOENT ) );
160
161 /* Create the instance */
162 CHECK( 0, fd_msg_new ( d, MSGFL_ALLOC_ETEID, &msg ) );
163
164 /* App id */
165 {
166 struct msg_hdr * h;
167 CHECK( 0, fd_msg_hdr( msg, &h ) );
168 h->msg_appl = 3;
169 }
170
171 /* sid */
172 {
173 struct session * sess = NULL;
174 os0_t s;
175 CHECK( 0, fd_sess_new( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, NULL, 0) );
176 CHECK( 0, fd_sess_getsid(sess, &s, &sess_bkp_len) );
177 CHECK( 1, (sess_bkp = os0dup(s, sess_bkp_len)) ? 1 : 0);
178
179 CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Session-Id", &d, ENOENT ) );
180 CHECK( 0, fd_msg_avp_new ( d, 0, &avp ) );
181 memset(&avp_val, 0, sizeof(avp_val));
182 avp_val.os.data = sess_bkp;
183 avp_val.os.len = sess_bkp_len;
184 CHECK( 0, fd_msg_avp_setvalue ( avp, &avp_val ) );
185 CHECK( 0, fd_msg_avp_add ( msg, MSG_BRW_FIRST_CHILD, avp) );
186 }
187
188 /* Origin-* */
189 CHECK( 0, fd_msg_add_origin(msg, 1) );
190
191 /* Destination-Realm */
192 {
193 CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Destination-Realm", &d, ENOENT ) );
194 CHECK( 0, fd_msg_avp_new ( d, 0, &avp ) );
195 memset(&avp_val, 0, sizeof(avp_val));
196 avp_val.os.data = (unsigned char *)fd_g_config->cnf_diamrlm;
197 avp_val.os.len = fd_g_config->cnf_diamrlm_len;
198 CHECK( 0, fd_msg_avp_setvalue ( avp, &avp_val ) );
199 CHECK( 0, fd_msg_avp_add ( msg, MSG_BRW_LAST_CHILD, avp) );
200 }
201
202 /* Accounting-Record-Type */
203 {
204 CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Accounting-Record-Type", &d, ENOENT ) );
205 CHECK( 0, fd_msg_avp_new ( d, 0, &avp ) );
206 memset(&avp_val, 0, sizeof(avp_val));
207 avp_val.u32 = 2;
208 CHECK( 0, fd_msg_avp_setvalue ( avp, &avp_val ) );
209 CHECK( 0, fd_msg_avp_add ( msg, MSG_BRW_LAST_CHILD, avp) );
210 }
211
212 /* Accounting-Record-Number */
213 {
214 CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Accounting-Record-Number", &d, ENOENT ) );
215 CHECK( 0, fd_msg_avp_new ( d, 0, &avp ) );
216 memset(&avp_val, 0, sizeof(avp_val));
217 avp_val.u32 = 2;
218 CHECK( 0, fd_msg_avp_setvalue ( avp, &avp_val ) );
219 CHECK( 0, fd_msg_avp_add ( msg, MSG_BRW_LAST_CHILD, avp) );
220 }
221
222 /* Route-Record */
223 {
224 CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Route-Record", &d, ENOENT ) );
225 CHECK( 0, fd_msg_avp_new ( d, 0, &avp ) );
226 memset(&avp_val, 0, sizeof(avp_val));
227 avp_val.os.data = (unsigned char *)"peer1";
228 avp_val.os.len = strlen((char *)avp_val.os.data);
229 CHECK( 0, fd_msg_avp_setvalue ( avp, &avp_val ) );
230 CHECK( 0, fd_msg_avp_add ( msg, MSG_BRW_LAST_CHILD, avp) );
231
232 CHECK( 0, fd_msg_avp_new ( d, 0, &avp ) );
233 memset(&avp_val, 0, sizeof(avp_val));
234 avp_val.os.data = (unsigned char *)"peer2";
235 avp_val.os.len = strlen((char *)avp_val.os.data);
236 CHECK( 0, fd_msg_avp_setvalue ( avp, &avp_val ) );
237 CHECK( 0, fd_msg_avp_add ( msg, MSG_BRW_LAST_CHILD, avp) );
238 }
239
240 /* Source */
241 CHECK( 0, fd_msg_source_set( msg, "peer3", CONSTSTRLEN("peer3") ) );
242 CHECK( 0, fd_msg_source_setrr( msg, "peer3", CONSTSTRLEN("peer3"), fd_g_config->cnf_dict ) );
243 }
244
245 /* Now, have the daemon handle this */
246 CHECK( 0, fd_fifo_post(fd_g_incoming, &msg) );
247
248 /* It is picked by the dispatch module, the extension handles the query, inserts the records in the DB, send creates the answer.
249 Once the answer is ready, it is sent to "peer3" which is not available of course; then the message is simply destroyed.
250 We wait 1 second for this to happen... */
251 sleep(1);
252
253 /* Now, check the record was actually registered properly */
254 {
255 PGresult * res;
256 uint8_t * bs;
257 char * es;
258 size_t l;
259
260 res = PQexec(conn, "SELECT \"Session-Id\" from " TABLE ";");
261 CHECK( PGRES_TUPLES_OK, PQresultStatus(res) );
262
263 /* We also check that the Session-Id we retrieve is the same as what we generated earlier (not trashed in the process) */
264 es = PQgetvalue(res, 0, 0);
265 bs = PQunescapeBytea((uint8_t *)es, &l);
266
267 CHECK( 0, fd_os_cmp(bs, l, sess_bkp, sess_bkp_len) );
268
269 PQclear(res);
270 PQfreemem(bs);
271 }
272
273 /* That's all for the tests yet */
274 free(sess_bkp);
275
276 PASSTEST();
277}
278