blob: 9bd082ebb8823d160366338e80d4a6638b1fb40b [file] [log] [blame]
Neels Hofmeyr98509462017-10-09 17:28:53 +02001/* (C) 2017 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
2 * All Rights Reserved
3 *
4 * Author: Neels Hofmeyr <nhofmeyr@sysmocom.de>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include <stdio.h>
22#include <errno.h>
23#include <getopt.h>
24#include <inttypes.h>
25
26#include <osmocom/core/application.h>
27#include <osmocom/core/utils.h>
28#include <osmocom/core/logging.h>
29
30#include "db.h"
31#include "logging.h"
32
33#define comment_start() fprintf(stderr, "\n===== %s\n", __func__);
34#define comment(fmt, args...) fprintf(stderr, "\n--- " fmt "\n\n", ## args);
35#define comment_end() fprintf(stderr, "===== %s: SUCCESS\n\n", __func__);
36
37/* Perform a function call and verbosely assert that its return value is as expected.
38 * The return code is then available in g_rc. */
39#define ASSERT_RC(call, expect_rc) \
40 do { \
41 fprintf(stderr, #call " --> " #expect_rc "\n"); \
42 g_rc = call; \
43 if (g_rc != (expect_rc)) \
44 fprintf(stderr, " MISMATCH: got rc = %d, expected: " \
45 #expect_rc " = %d\n", g_rc, expect_rc); \
46 OSMO_ASSERT(g_rc == (expect_rc)); \
47 fprintf(stderr, "\n"); \
48 } while (0)
49
50/* Do db_subscr_get_by_xxxx and verbosely assert that its return value is as expected.
51 * Print the subscriber struct to stderr to be validated by db_test.err.
52 * The result is then available in g_subscr. */
53#define ASSERT_SEL(by, val, expect_rc) \
54 do { \
55 int rc; \
56 g_subscr = (struct hlr_subscriber){}; \
57 fprintf(stderr, "db_subscr_get_by_" #by "(dbc, " #val ", &g_subscr) --> " \
58 #expect_rc "\n"); \
59 rc = db_subscr_get_by_##by(dbc, val, &g_subscr); \
60 if (rc != (expect_rc)) \
61 fprintf(stderr, " MISMATCH: got rc = %d, expected: " \
62 #expect_rc " = %d\n", rc, expect_rc); \
63 OSMO_ASSERT(rc == (expect_rc)); \
64 if (!rc) \
65 dump_subscr(&g_subscr); \
66 fprintf(stderr, "\n"); \
67 } while (0)
68
69static struct db_context *dbc = NULL;
70static void *ctx = NULL;
71static struct hlr_subscriber g_subscr;
72static int g_rc;
73
74#define Pfv(name, fmt, val) \
75 fprintf(stderr, " ." #name " = " fmt ",\n", val)
76#define Pfo(name, fmt, obj) \
77 Pfv(name, fmt, obj->name)
78
79/* Print a subscriber struct to stderr to be validated by db_test.err. */
80void dump_subscr(struct hlr_subscriber *subscr)
81{
82#define Ps(name) \
83 if (*subscr->name) \
84 Pfo(name, "'%s'", subscr)
85#define Pd(name) \
86 Pfv(name, "%"PRId64, (int64_t)subscr->name)
87#define Pd_nonzero(name) \
88 if (subscr->name) \
89 Pd(name)
90#define Pb(if_val, name) \
91 if (subscr->name == (if_val)) \
92 Pfv(name, "%s", subscr->name ? "true" : "false")
93
94 fprintf(stderr, "struct hlr_subscriber {\n");
95 Pd(id);
96 Ps(imsi);
97 Ps(msisdn);
98 Ps(vlr_number);
99 Ps(sgsn_number);
100 Ps(sgsn_address);
101 Pd_nonzero(periodic_lu_timer);
102 Pd_nonzero(periodic_rau_tau_timer);
103 Pb(false, nam_cs);
104 Pb(false, nam_ps);
105 if (subscr->lmsi)
106 Pfo(lmsi, "0x%x", subscr);
107 Pb(true, ms_purged_cs);
108 Pb(true, ms_purged_ps);
109 fprintf(stderr, "}\n");
110#undef Ps
111#undef Pd
112#undef Pd_nonzero
113#undef Pb
114}
115
116void dump_aud(const char *label, struct osmo_sub_auth_data *aud)
117{
118 if (aud->type == OSMO_AUTH_TYPE_NONE) {
119 fprintf(stderr, "%s: none\n", label);
120 return;
121 }
122
123 fprintf(stderr, "%s: struct osmo_sub_auth_data {\n", label);
124#define Pf(name, fmt) \
125 Pfo(name, fmt, aud)
126#define Phex(name) \
127 Pfv(name, "'%s'", osmo_hexdump_nospc(aud->name, sizeof(aud->name)))
128
129 Pfv(type, "%s", osmo_sub_auth_type_name(aud->type));
130 Pfv(algo, "%s", osmo_auth_alg_name(aud->algo));
131 switch (aud->type) {
132 case OSMO_AUTH_TYPE_GSM:
133 Phex(u.gsm.ki);
134 break;
135 case OSMO_AUTH_TYPE_UMTS:
136 Phex(u.umts.opc);
137 Pf(u.umts.opc_is_op, "%u");
138 Phex(u.umts.k);
139 Phex(u.umts.amf);
140 if (aud->u.umts.sqn) {
141 Pf(u.umts.sqn, "%"PRIu64);
142 Pf(u.umts.sqn, "0x%"PRIx64);
143 }
144 if (aud->u.umts.ind_bitlen)
145 Pf(u.umts.ind_bitlen, "%u");
146 break;
147 default:
148 OSMO_ASSERT(false);
149 }
150
151 fprintf(stderr, "}\n");
152
153#undef Pf
154#undef Phex
155}
156
157static const char *imsi0 = "123456789000000";
158static const char *imsi1 = "123456789000001";
159static const char *imsi2 = "123456789000002";
160static const char *short_imsi = "123456";
161static const char *unknown_imsi = "999999999";
162
163static void test_subscr_create_update_sel_delete()
164{
165 int64_t id0, id1, id2, id_short;
166 comment_start();
167
168 comment("Create with valid / invalid IMSI");
169
170 ASSERT_RC(db_subscr_create(dbc, imsi0), 0);
171 ASSERT_SEL(imsi, imsi0, 0);
172 id0 = g_subscr.id;
173 ASSERT_RC(db_subscr_create(dbc, imsi1), 0);
174 ASSERT_SEL(imsi, imsi1, 0);
175 id1 = g_subscr.id;
176 ASSERT_RC(db_subscr_create(dbc, imsi2), 0);
177 ASSERT_SEL(imsi, imsi2, 0);
178 id2 = g_subscr.id;
179 ASSERT_RC(db_subscr_create(dbc, imsi0), -EIO);
180 ASSERT_SEL(imsi, imsi0, 0);
181 ASSERT_RC(db_subscr_create(dbc, imsi1), -EIO);
182 ASSERT_RC(db_subscr_create(dbc, imsi1), -EIO);
183 ASSERT_SEL(imsi, imsi1, 0);
184 ASSERT_RC(db_subscr_create(dbc, imsi2), -EIO);
185 ASSERT_RC(db_subscr_create(dbc, imsi2), -EIO);
186 ASSERT_SEL(imsi, imsi2, 0);
187
188 ASSERT_RC(db_subscr_create(dbc, "123456789 000003"), -EINVAL);
189 ASSERT_SEL(imsi, "123456789000003", -ENOEXEC);
190
191 ASSERT_RC(db_subscr_create(dbc, "123456789000002123456"), -EINVAL);
192 ASSERT_SEL(imsi, "123456789000002123456", -ENOEXEC);
193
194 ASSERT_RC(db_subscr_create(dbc, "foobar123"), -EINVAL);
195 ASSERT_SEL(imsi, "foobar123", -ENOEXEC);
196
197 ASSERT_RC(db_subscr_create(dbc, "123"), -EINVAL);
198 ASSERT_SEL(imsi, "123", -ENOEXEC);
199
200 ASSERT_RC(db_subscr_create(dbc, short_imsi), 0);
201 ASSERT_SEL(imsi, short_imsi, 0);
202 id_short = g_subscr.id;
203
204
205 comment("Set valid / invalid MSISDN");
206
207 ASSERT_SEL(imsi, imsi0, 0);
208 ASSERT_RC(db_subscr_update_msisdn_by_imsi(dbc, imsi0, "54321"), 0);
209 ASSERT_SEL(imsi, imsi0, 0);
210 ASSERT_RC(db_subscr_update_msisdn_by_imsi(dbc, imsi0,
211 "54321012345678912345678"), -EINVAL);
212 ASSERT_SEL(imsi, imsi0, 0);
213 ASSERT_RC(db_subscr_update_msisdn_by_imsi(dbc, imsi0,
214 "543 21"), -EINVAL);
215 ASSERT_SEL(imsi, imsi0, 0);
216 ASSERT_RC(db_subscr_update_msisdn_by_imsi(dbc, imsi0,
217 "foobar123"), -EINVAL);
218 ASSERT_SEL(imsi, imsi0, 0);
219 ASSERT_RC(db_subscr_update_msisdn_by_imsi(dbc, imsi0,
220 "5"), 0);
221 ASSERT_SEL(imsi, imsi0, 0);
222 ASSERT_RC(db_subscr_update_msisdn_by_imsi(dbc, imsi0,
223 "543210123456789"), 0);
224 ASSERT_SEL(imsi, imsi0, 0);
225 ASSERT_RC(db_subscr_update_msisdn_by_imsi(dbc, imsi0,
226 "5432101234567891"), -EINVAL);
227 ASSERT_SEL(imsi, imsi0, 0);
228
229 comment("Set MSISDN on non-existent / invalid IMSI");
230
231 ASSERT_RC(db_subscr_update_msisdn_by_imsi(dbc, unknown_imsi, "99"), -ENOENT);
232
233 ASSERT_RC(db_subscr_update_msisdn_by_imsi(dbc, "foobar", "99"), -ENOENT);
234
235 comment("Delete non-existent / invalid IDs");
236
237 ASSERT_RC(db_subscr_delete_by_id(dbc, 999), -ENOENT);
238 ASSERT_RC(db_subscr_delete_by_id(dbc, -10), -ENOENT);
239
240 comment("Delete subscribers");
241
242 ASSERT_SEL(imsi, imsi0, 0);
243 ASSERT_RC(db_subscr_delete_by_id(dbc, id0), 0);
244 ASSERT_SEL(imsi, imsi0, -ENOEXEC);
245 ASSERT_RC(db_subscr_delete_by_id(dbc, id0), -ENOENT);
246
247 ASSERT_SEL(imsi, imsi1, 0);
248 ASSERT_RC(db_subscr_delete_by_id(dbc, id1), 0);
249 ASSERT_SEL(imsi, imsi1, -ENOEXEC);
250
251 ASSERT_SEL(imsi, imsi2, 0);
252 ASSERT_RC(db_subscr_delete_by_id(dbc, id2), 0);
253 ASSERT_SEL(imsi, imsi2, -ENOEXEC);
254
255 ASSERT_SEL(imsi, short_imsi, 0);
256 ASSERT_RC(db_subscr_delete_by_id(dbc, id_short), 0);
257 ASSERT_SEL(imsi, short_imsi, -ENOEXEC);
258
259 comment_end();
260}
261
262static struct {
263 bool verbose;
264} cmdline_opts = {
265 .verbose = false,
266};
267
268static void print_help(const char *program)
269{
270 printf("Usage:\n"
271 " %s [-v] [N [N...]]\n"
272 "Options:\n"
273 " -h --help show this text.\n"
274 " -v --verbose print source file and line numbers\n",
275 program
276 );
277}
278
279static void handle_options(int argc, char **argv)
280{
281 while (1) {
282 int option_index = 0, c;
283 static struct option long_options[] = {
284 {"help", 0, 0, 'h'},
285 {"verbose", 1, 0, 'v'},
286 {0, 0, 0, 0}
287 };
288
289 c = getopt_long(argc, argv, "hv",
290 long_options, &option_index);
291 if (c == -1)
292 break;
293
294 switch (c) {
295 case 'h':
296 print_help(argv[0]);
297 exit(0);
298 case 'v':
299 cmdline_opts.verbose = true;
300 break;
301 default:
302 /* catch unknown options *as well as* missing arguments. */
303 fprintf(stderr, "Error in command line options. Exiting.\n");
304 exit(-1);
305 break;
306 }
307 }
308
309 if (optind < argc) {
310 fprintf(stderr, "too many args\n");
311 exit(-1);
312 }
313}
314
315int main(int argc, char **argv)
316{
317 printf("db_test.c\n");
318
319 ctx = talloc_named_const(NULL, 1, "db_test");
320
321 handle_options(argc, argv);
322
323 osmo_init_logging(&hlr_log_info);
324 log_set_print_filename(osmo_stderr_target, cmdline_opts.verbose);
325 log_set_print_timestamp(osmo_stderr_target, 0);
326 log_set_use_color(osmo_stderr_target, 0);
327 log_set_print_category(osmo_stderr_target, 1);
328
329 /* omit the SQLite version and compilation flags from test output */
330 log_set_log_level(osmo_stderr_target, LOGL_ERROR);
331 dbc = db_open(ctx, "db_test.db");
332 log_set_log_level(osmo_stderr_target, 0);
333 OSMO_ASSERT(dbc);
334
335 test_subscr_create_update_sel_delete();
336
337 printf("Done\n");
338 return 0;
339}
340
341/* stubs */
342int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
343 struct osmo_sub_auth_data *aud2g,
344 struct osmo_sub_auth_data *aud3g,
345 const uint8_t *rand_auts, const uint8_t *auts)
346{ OSMO_ASSERT(false); return -1; }