blob: 250b3637b4277d1c0666bcfcc4caa11610387340 [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;
Neels Hofmeyr9c2bbc82017-10-09 17:30:32 +020073static int64_t g_id;
Neels Hofmeyr98509462017-10-09 17:28:53 +020074
75#define Pfv(name, fmt, val) \
76 fprintf(stderr, " ." #name " = " fmt ",\n", val)
77#define Pfo(name, fmt, obj) \
78 Pfv(name, fmt, obj->name)
79
80/* Print a subscriber struct to stderr to be validated by db_test.err. */
81void dump_subscr(struct hlr_subscriber *subscr)
82{
83#define Ps(name) \
84 if (*subscr->name) \
85 Pfo(name, "'%s'", subscr)
86#define Pd(name) \
87 Pfv(name, "%"PRId64, (int64_t)subscr->name)
88#define Pd_nonzero(name) \
89 if (subscr->name) \
90 Pd(name)
91#define Pb(if_val, name) \
92 if (subscr->name == (if_val)) \
93 Pfv(name, "%s", subscr->name ? "true" : "false")
94
95 fprintf(stderr, "struct hlr_subscriber {\n");
96 Pd(id);
97 Ps(imsi);
98 Ps(msisdn);
99 Ps(vlr_number);
100 Ps(sgsn_number);
101 Ps(sgsn_address);
102 Pd_nonzero(periodic_lu_timer);
103 Pd_nonzero(periodic_rau_tau_timer);
104 Pb(false, nam_cs);
105 Pb(false, nam_ps);
106 if (subscr->lmsi)
107 Pfo(lmsi, "0x%x", subscr);
108 Pb(true, ms_purged_cs);
109 Pb(true, ms_purged_ps);
110 fprintf(stderr, "}\n");
111#undef Ps
112#undef Pd
113#undef Pd_nonzero
114#undef Pb
115}
116
117void dump_aud(const char *label, struct osmo_sub_auth_data *aud)
118{
119 if (aud->type == OSMO_AUTH_TYPE_NONE) {
120 fprintf(stderr, "%s: none\n", label);
121 return;
122 }
123
124 fprintf(stderr, "%s: struct osmo_sub_auth_data {\n", label);
125#define Pf(name, fmt) \
126 Pfo(name, fmt, aud)
127#define Phex(name) \
128 Pfv(name, "'%s'", osmo_hexdump_nospc(aud->name, sizeof(aud->name)))
129
130 Pfv(type, "%s", osmo_sub_auth_type_name(aud->type));
131 Pfv(algo, "%s", osmo_auth_alg_name(aud->algo));
132 switch (aud->type) {
133 case OSMO_AUTH_TYPE_GSM:
134 Phex(u.gsm.ki);
135 break;
136 case OSMO_AUTH_TYPE_UMTS:
137 Phex(u.umts.opc);
138 Pf(u.umts.opc_is_op, "%u");
139 Phex(u.umts.k);
140 Phex(u.umts.amf);
141 if (aud->u.umts.sqn) {
142 Pf(u.umts.sqn, "%"PRIu64);
143 Pf(u.umts.sqn, "0x%"PRIx64);
144 }
145 if (aud->u.umts.ind_bitlen)
146 Pf(u.umts.ind_bitlen, "%u");
147 break;
148 default:
149 OSMO_ASSERT(false);
150 }
151
152 fprintf(stderr, "}\n");
153
154#undef Pf
155#undef Phex
156}
157
158static const char *imsi0 = "123456789000000";
159static const char *imsi1 = "123456789000001";
160static const char *imsi2 = "123456789000002";
161static const char *short_imsi = "123456";
162static const char *unknown_imsi = "999999999";
163
164static void test_subscr_create_update_sel_delete()
165{
166 int64_t id0, id1, id2, id_short;
167 comment_start();
168
169 comment("Create with valid / invalid IMSI");
170
171 ASSERT_RC(db_subscr_create(dbc, imsi0), 0);
172 ASSERT_SEL(imsi, imsi0, 0);
173 id0 = g_subscr.id;
174 ASSERT_RC(db_subscr_create(dbc, imsi1), 0);
175 ASSERT_SEL(imsi, imsi1, 0);
176 id1 = g_subscr.id;
177 ASSERT_RC(db_subscr_create(dbc, imsi2), 0);
178 ASSERT_SEL(imsi, imsi2, 0);
179 id2 = g_subscr.id;
180 ASSERT_RC(db_subscr_create(dbc, imsi0), -EIO);
181 ASSERT_SEL(imsi, imsi0, 0);
182 ASSERT_RC(db_subscr_create(dbc, imsi1), -EIO);
183 ASSERT_RC(db_subscr_create(dbc, imsi1), -EIO);
184 ASSERT_SEL(imsi, imsi1, 0);
185 ASSERT_RC(db_subscr_create(dbc, imsi2), -EIO);
186 ASSERT_RC(db_subscr_create(dbc, imsi2), -EIO);
187 ASSERT_SEL(imsi, imsi2, 0);
188
189 ASSERT_RC(db_subscr_create(dbc, "123456789 000003"), -EINVAL);
Neels Hofmeyr9c2bbc82017-10-09 17:30:32 +0200190 ASSERT_SEL(imsi, "123456789000003", -ENOENT);
Neels Hofmeyr98509462017-10-09 17:28:53 +0200191
192 ASSERT_RC(db_subscr_create(dbc, "123456789000002123456"), -EINVAL);
Neels Hofmeyr9c2bbc82017-10-09 17:30:32 +0200193 ASSERT_SEL(imsi, "123456789000002123456", -ENOENT);
Neels Hofmeyr98509462017-10-09 17:28:53 +0200194
195 ASSERT_RC(db_subscr_create(dbc, "foobar123"), -EINVAL);
Neels Hofmeyr9c2bbc82017-10-09 17:30:32 +0200196 ASSERT_SEL(imsi, "foobar123", -ENOENT);
Neels Hofmeyr98509462017-10-09 17:28:53 +0200197
198 ASSERT_RC(db_subscr_create(dbc, "123"), -EINVAL);
Neels Hofmeyr9c2bbc82017-10-09 17:30:32 +0200199 ASSERT_SEL(imsi, "123", -ENOENT);
Neels Hofmeyr98509462017-10-09 17:28:53 +0200200
201 ASSERT_RC(db_subscr_create(dbc, short_imsi), 0);
202 ASSERT_SEL(imsi, short_imsi, 0);
203 id_short = g_subscr.id;
204
205
206 comment("Set valid / invalid MSISDN");
207
208 ASSERT_SEL(imsi, imsi0, 0);
209 ASSERT_RC(db_subscr_update_msisdn_by_imsi(dbc, imsi0, "54321"), 0);
210 ASSERT_SEL(imsi, imsi0, 0);
Neels Hofmeyr9c2bbc82017-10-09 17:30:32 +0200211 ASSERT_SEL(msisdn, "54321", 0);
Neels Hofmeyr98509462017-10-09 17:28:53 +0200212 ASSERT_RC(db_subscr_update_msisdn_by_imsi(dbc, imsi0,
213 "54321012345678912345678"), -EINVAL);
214 ASSERT_SEL(imsi, imsi0, 0);
Neels Hofmeyr9c2bbc82017-10-09 17:30:32 +0200215 ASSERT_SEL(msisdn, "54321", 0);
216 ASSERT_SEL(msisdn, "54321012345678912345678", -ENOENT);
Neels Hofmeyr98509462017-10-09 17:28:53 +0200217 ASSERT_RC(db_subscr_update_msisdn_by_imsi(dbc, imsi0,
218 "543 21"), -EINVAL);
219 ASSERT_SEL(imsi, imsi0, 0);
Neels Hofmeyr9c2bbc82017-10-09 17:30:32 +0200220 ASSERT_SEL(msisdn, "543 21", -ENOENT);
Neels Hofmeyr98509462017-10-09 17:28:53 +0200221 ASSERT_RC(db_subscr_update_msisdn_by_imsi(dbc, imsi0,
222 "foobar123"), -EINVAL);
223 ASSERT_SEL(imsi, imsi0, 0);
Neels Hofmeyr9c2bbc82017-10-09 17:30:32 +0200224 ASSERT_SEL(msisdn, "foobar123", -ENOENT);
Neels Hofmeyr98509462017-10-09 17:28:53 +0200225 ASSERT_RC(db_subscr_update_msisdn_by_imsi(dbc, imsi0,
226 "5"), 0);
227 ASSERT_SEL(imsi, imsi0, 0);
Neels Hofmeyr9c2bbc82017-10-09 17:30:32 +0200228 ASSERT_SEL(msisdn, "5", 0);
229 ASSERT_SEL(msisdn, "54321", -ENOENT);
Neels Hofmeyr98509462017-10-09 17:28:53 +0200230 ASSERT_RC(db_subscr_update_msisdn_by_imsi(dbc, imsi0,
231 "543210123456789"), 0);
232 ASSERT_SEL(imsi, imsi0, 0);
Neels Hofmeyr9c2bbc82017-10-09 17:30:32 +0200233 ASSERT_SEL(msisdn, "543210123456789", 0);
Neels Hofmeyr98509462017-10-09 17:28:53 +0200234 ASSERT_RC(db_subscr_update_msisdn_by_imsi(dbc, imsi0,
235 "5432101234567891"), -EINVAL);
236 ASSERT_SEL(imsi, imsi0, 0);
Neels Hofmeyr9c2bbc82017-10-09 17:30:32 +0200237 ASSERT_SEL(msisdn, "5432101234567891", -ENOENT);
Neels Hofmeyr98509462017-10-09 17:28:53 +0200238
239 comment("Set MSISDN on non-existent / invalid IMSI");
240
241 ASSERT_RC(db_subscr_update_msisdn_by_imsi(dbc, unknown_imsi, "99"), -ENOENT);
Neels Hofmeyr9c2bbc82017-10-09 17:30:32 +0200242 ASSERT_SEL(msisdn, "99", -ENOENT);
Neels Hofmeyr98509462017-10-09 17:28:53 +0200243
244 ASSERT_RC(db_subscr_update_msisdn_by_imsi(dbc, "foobar", "99"), -ENOENT);
Neels Hofmeyr9c2bbc82017-10-09 17:30:32 +0200245 ASSERT_SEL(msisdn, "99", -ENOENT);
Neels Hofmeyr98509462017-10-09 17:28:53 +0200246
247 comment("Delete non-existent / invalid IDs");
248
249 ASSERT_RC(db_subscr_delete_by_id(dbc, 999), -ENOENT);
250 ASSERT_RC(db_subscr_delete_by_id(dbc, -10), -ENOENT);
251
252 comment("Delete subscribers");
253
254 ASSERT_SEL(imsi, imsi0, 0);
255 ASSERT_RC(db_subscr_delete_by_id(dbc, id0), 0);
Neels Hofmeyr9c2bbc82017-10-09 17:30:32 +0200256 ASSERT_SEL(imsi, imsi0, -ENOENT);
Neels Hofmeyr98509462017-10-09 17:28:53 +0200257 ASSERT_RC(db_subscr_delete_by_id(dbc, id0), -ENOENT);
258
259 ASSERT_SEL(imsi, imsi1, 0);
260 ASSERT_RC(db_subscr_delete_by_id(dbc, id1), 0);
Neels Hofmeyr9c2bbc82017-10-09 17:30:32 +0200261 ASSERT_SEL(imsi, imsi1, -ENOENT);
Neels Hofmeyr98509462017-10-09 17:28:53 +0200262
263 ASSERT_SEL(imsi, imsi2, 0);
264 ASSERT_RC(db_subscr_delete_by_id(dbc, id2), 0);
Neels Hofmeyr9c2bbc82017-10-09 17:30:32 +0200265 ASSERT_SEL(imsi, imsi2, -ENOENT);
Neels Hofmeyr98509462017-10-09 17:28:53 +0200266
267 ASSERT_SEL(imsi, short_imsi, 0);
268 ASSERT_RC(db_subscr_delete_by_id(dbc, id_short), 0);
Neels Hofmeyr9c2bbc82017-10-09 17:30:32 +0200269 ASSERT_SEL(imsi, short_imsi, -ENOENT);
Neels Hofmeyr98509462017-10-09 17:28:53 +0200270
271 comment_end();
272}
273
274static struct {
275 bool verbose;
276} cmdline_opts = {
277 .verbose = false,
278};
279
280static void print_help(const char *program)
281{
282 printf("Usage:\n"
283 " %s [-v] [N [N...]]\n"
284 "Options:\n"
285 " -h --help show this text.\n"
286 " -v --verbose print source file and line numbers\n",
287 program
288 );
289}
290
291static void handle_options(int argc, char **argv)
292{
293 while (1) {
294 int option_index = 0, c;
295 static struct option long_options[] = {
296 {"help", 0, 0, 'h'},
297 {"verbose", 1, 0, 'v'},
298 {0, 0, 0, 0}
299 };
300
301 c = getopt_long(argc, argv, "hv",
302 long_options, &option_index);
303 if (c == -1)
304 break;
305
306 switch (c) {
307 case 'h':
308 print_help(argv[0]);
309 exit(0);
310 case 'v':
311 cmdline_opts.verbose = true;
312 break;
313 default:
314 /* catch unknown options *as well as* missing arguments. */
315 fprintf(stderr, "Error in command line options. Exiting.\n");
316 exit(-1);
317 break;
318 }
319 }
320
321 if (optind < argc) {
322 fprintf(stderr, "too many args\n");
323 exit(-1);
324 }
325}
326
327int main(int argc, char **argv)
328{
329 printf("db_test.c\n");
330
331 ctx = talloc_named_const(NULL, 1, "db_test");
332
333 handle_options(argc, argv);
334
335 osmo_init_logging(&hlr_log_info);
336 log_set_print_filename(osmo_stderr_target, cmdline_opts.verbose);
337 log_set_print_timestamp(osmo_stderr_target, 0);
338 log_set_use_color(osmo_stderr_target, 0);
339 log_set_print_category(osmo_stderr_target, 1);
340
341 /* omit the SQLite version and compilation flags from test output */
342 log_set_log_level(osmo_stderr_target, LOGL_ERROR);
343 dbc = db_open(ctx, "db_test.db");
344 log_set_log_level(osmo_stderr_target, 0);
345 OSMO_ASSERT(dbc);
346
347 test_subscr_create_update_sel_delete();
348
349 printf("Done\n");
350 return 0;
351}
352
353/* stubs */
354int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
355 struct osmo_sub_auth_data *aud2g,
356 struct osmo_sub_auth_data *aud3g,
357 const uint8_t *rand_auts, const uint8_t *auts)
358{ OSMO_ASSERT(false); return -1; }