Vadim Yanitskiy | e1e7247 | 2019-04-09 16:55:44 +0700 | [diff] [blame] | 1 | /* |
| 2 | * Test the storage API of the internal SMS Centre. |
| 3 | * |
| 4 | * (C) 2019 by Vadim Yanitskiy <axilirator@gmail.com> |
| 5 | * |
| 6 | * All Rights Reserved |
| 7 | * |
| 8 | * This program is free software; you can redistribute it and/or modify |
| 9 | * it under the terms of the GNU Affero General Public License as published by |
| 10 | * the Free Software Foundation; either version 3 of the License, or |
| 11 | * (at your option) any later version. |
| 12 | * |
| 13 | * This program is distributed in the hope that it will be useful, |
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | * GNU Affero General Public License for more details. |
| 17 | * |
| 18 | * You should have received a copy of the GNU Affero General Public License |
| 19 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 20 | * |
| 21 | */ |
| 22 | |
| 23 | #include <inttypes.h> |
| 24 | #include <stdbool.h> |
| 25 | #include <string.h> |
| 26 | #include <stdio.h> |
| 27 | |
| 28 | #include <osmocom/core/application.h> |
| 29 | #include <osmocom/core/utils.h> |
| 30 | |
| 31 | #include <osmocom/gsm/protocol/gsm_03_40.h> |
| 32 | |
| 33 | #include <osmocom/msc/gsm_data.h> |
| 34 | #include <osmocom/msc/debug.h> |
| 35 | #include <osmocom/msc/vlr.h> |
| 36 | #include <osmocom/msc/db.h> |
| 37 | |
| 38 | /* Talloc context of this unit test */ |
| 39 | static void *talloc_ctx = NULL; |
| 40 | |
| 41 | static const struct sms_tp_ud { |
| 42 | /* Data Coding Scheme */ |
| 43 | uint8_t dcs; |
| 44 | /* TP User-Data-Length (depends on DCS) */ |
| 45 | uint8_t length; |
| 46 | /* Static TP User-Data filler (0 means disabled) */ |
| 47 | uint8_t filler_byte; |
| 48 | /* TP User-Data */ |
| 49 | uint8_t data[GSM340_UDL_OCT_MAX]; |
| 50 | /* Decoded text (for 7-bit default alphabet only) */ |
| 51 | char dec_text[GSM340_UDL_SPT_MAX + 1]; |
| 52 | } sms_tp_ud_set[] = { |
| 53 | { |
| 54 | .dcs = 0x00, /* Default GSM 7-bit alphabet */ |
| 55 | .length = 9, /* in septets */ |
| 56 | .dec_text = "Mahlzeit!", |
| 57 | .data = { |
| 58 | 0xcd, 0x30, 0x9a, 0xad, 0x2f, 0xa7, 0xe9, 0x21, |
| 59 | }, |
| 60 | }, |
| 61 | { |
| 62 | .dcs = 0x08, /* UCS-2 (16-bit) / UTF-16 */ |
| 63 | .length = 120, /* in octets */ |
| 64 | .data = { |
| 65 | 0x04, 0x23, 0x04, 0x32, 0x04, 0x30, 0x04, 0x36, |
| 66 | 0x04, 0x30, 0x04, 0x35, 0x04, 0x3c, 0x04, 0x4b, |
| 67 | 0x04, 0x39, 0x00, 0x20, 0x04, 0x3a, 0x04, 0x3b, |
| 68 | 0x04, 0x38, 0x04, 0x35, 0x04, 0x3d, 0x04, 0x42, |
| 69 | 0x00, 0x21, 0x00, 0x20, 0x04, 0x1d, 0x04, 0x30, |
| 70 | 0x04, 0x41, 0x04, 0x42, 0x04, 0x40, 0x04, 0x3e, |
| 71 | 0x04, 0x39, 0x04, 0x3a, 0x04, 0x38, 0x00, 0x20, |
| 72 | 0x00, 0x49, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, |
| 73 | 0x00, 0x72, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x74, |
| 74 | 0x00, 0x20, 0x04, 0x38, 0x00, 0x20, 0x00, 0x4d, |
| 75 | 0x00, 0x4d, 0x00, 0x53, 0x00, 0x20, 0x04, 0x31, |
| 76 | 0x04, 0x43, 0x04, 0x34, 0x04, 0x43, 0x04, 0x42, |
| 77 | 0x00, 0x20, 0x04, 0x34, 0x04, 0x3e, 0x04, 0x41, |
| 78 | 0x04, 0x42, 0x04, 0x30, 0x04, 0x32, 0x04, 0x3b, |
| 79 | 0x04, 0x35, 0x04, 0x3d, 0x04, 0x4b, 0x00, 0x2e, |
| 80 | }, |
| 81 | }, |
| 82 | { |
| 83 | .dcs = 0x04, /* 8-bit data */ |
| 84 | .length = 12, /* in octets */ |
| 85 | .data = { |
| 86 | /* User-Data-Header */ |
| 87 | 0x1e, /* Buffer-overflow! (should be 0x05) */ |
| 88 | /* Concatenated SM, 8-bit reference number */ |
| 89 | 0x00, 0x03, 0x5a, 0x05, 0x01, |
| 90 | |
| 91 | /* Dummy payload... */ |
| 92 | 0x05, 0x04, 0x0b, 0x84, 0x0b, 0x84, |
| 93 | }, |
| 94 | }, |
| 95 | { |
| 96 | .dcs = 0x00, /* Default GSM 7-bit alphabet */ |
| 97 | .length = 160, /* maximum, in septets */ |
| 98 | .filler_byte = 0x41, |
| 99 | }, |
| 100 | { |
| 101 | .dcs = 0x04, /* 8-bit data */ |
| 102 | .length = 140, /* maximum, in octets */ |
| 103 | .filler_byte = 0x42, |
| 104 | }, |
| 105 | { |
| 106 | .dcs = 0x00, /* Default GSM 7-bit alphabet */ |
| 107 | .length = 200, /* invalid, buffer overflow */ |
| 108 | .filler_byte = 0x41, |
| 109 | }, |
| 110 | { |
| 111 | .dcs = 0x04, /* 8-bit data */ |
| 112 | .length = 0xff, /* invalid, buffer overflow */ |
| 113 | .filler_byte = 0x42, |
| 114 | }, |
| 115 | }; |
| 116 | |
| 117 | #define SMS_ADDR(addr) \ |
| 118 | { 0x00, 0x00, addr } |
| 119 | |
| 120 | static struct sms_test { |
| 121 | /* Human-readable name of particular test message */ |
| 122 | const char *name; |
| 123 | /* Whether we expect db_sms_store() to fail */ |
| 124 | bool exp_db_sms_store_fail; |
| 125 | /* Whether we expect db_sms_get() to fail */ |
| 126 | bool exp_db_sms_get_fail; |
| 127 | /* SM TP-User-Data from sms_tp_ud_set[] */ |
| 128 | const struct sms_tp_ud *ud; |
| 129 | /* The message itself */ |
| 130 | struct gsm_sms sms; |
| 131 | } sms_test_set[] = { |
| 132 | { |
| 133 | .name = "Regular MO SMS", |
| 134 | .sms = { |
| 135 | .msg_ref = 0xde, |
| 136 | .src = SMS_ADDR("123456"), |
| 137 | .dst = SMS_ADDR("654321"), |
| 138 | .validity_minutes = 10, |
| 139 | .protocol_id = 0x00, |
| 140 | /* SM TP-User-Data is taken from sms_tp_ud_set[] */ |
| 141 | }, |
| 142 | .ud = &sms_tp_ud_set[0], |
| 143 | }, |
| 144 | { |
| 145 | .name = "Regular MT SMS", |
| 146 | .sms = { |
| 147 | .msg_ref = 0xbe, |
| 148 | .src = SMS_ADDR("654321"), |
| 149 | .dst = SMS_ADDR("123456"), |
| 150 | .validity_minutes = 180, |
| 151 | .protocol_id = 0x00, |
| 152 | /* SM TP-User-Data is taken from sms_tp_ud_set[] */ |
| 153 | }, |
| 154 | .ud = &sms_tp_ud_set[1], |
| 155 | }, |
| 156 | { |
| 157 | .name = "Complete TP-UD (160 septets, 7-bit encoding)", |
| 158 | .sms = { |
| 159 | .msg_ref = 0xee, |
| 160 | .src = SMS_ADDR("266753837248772"), |
| 161 | .dst = SMS_ADDR("266753837248378"), |
| 162 | .validity_minutes = 360, |
| 163 | .protocol_id = 0x00, |
| 164 | /* SM TP-User-Data is taken from sms_tp_ud_set[] */ |
| 165 | }, |
| 166 | .ud = &sms_tp_ud_set[3], |
| 167 | }, |
| 168 | { |
| 169 | .name = "Complete TP-UD (140 octets, 8-bit encoding)", |
| 170 | .sms = { |
| 171 | .msg_ref = 0xee, |
| 172 | .src = SMS_ADDR("266753838248772"), |
| 173 | .dst = SMS_ADDR("266753838248378"), |
| 174 | .validity_minutes = 360, |
| 175 | .protocol_id = 0xaa, |
| 176 | /* SM TP-User-Data is taken from sms_tp_ud_set[] */ |
| 177 | }, |
| 178 | .ud = &sms_tp_ud_set[4], |
| 179 | }, |
| 180 | { |
| 181 | .name = "TP-UD buffer overflow (UDH-Length > UD-Length)", |
| 182 | .sms = { |
| 183 | .msg_ref = 0x88, |
| 184 | .src = SMS_ADDR("834568373569772"), |
| 185 | .dst = SMS_ADDR("834568373569378"), |
| 186 | .validity_minutes = 200, |
| 187 | .protocol_id = 0xbb, |
| 188 | .ud_hdr_ind = 0x01, |
| 189 | /* SM TP-User-Data is taken from sms_tp_ud_set[] */ |
| 190 | }, |
| 191 | .ud = &sms_tp_ud_set[2], |
| 192 | }, |
| 193 | { |
| 194 | .name = "Truncated TP-UD (200 septets, 7-bit encoding)", |
| 195 | .sms = { |
| 196 | .msg_ref = 0xee, |
| 197 | .src = { 0x01, 0x00, "8786228337248772" }, |
| 198 | .dst = { 0x00, 0x01, "8786228337248378" }, |
| 199 | .validity_minutes = 360, |
| 200 | .protocol_id = 0xcc, |
| 201 | /* SM TP-User-Data is taken from sms_tp_ud_set[] */ |
| 202 | }, |
| 203 | .ud = &sms_tp_ud_set[5], |
| 204 | }, |
| 205 | { |
| 206 | .name = "Truncated TP-UD (255 octets, 8-bit encoding)", |
| 207 | .sms = { |
| 208 | .msg_ref = 0xee, |
| 209 | .src = { 0x01, 0x01, "8786228338248772" }, |
| 210 | .dst = { 0xaa, 0xff, "8786228338248378" }, |
| 211 | .validity_minutes = 360, |
| 212 | .protocol_id = 0xbb, |
| 213 | /* SM TP-User-Data is taken from sms_tp_ud_set[] */ |
| 214 | }, |
| 215 | .ud = &sms_tp_ud_set[6], |
| 216 | }, |
| 217 | { |
| 218 | .name = "Same MSISDN #1", |
| 219 | .sms = { |
| 220 | .msg_ref = 0x11, |
| 221 | .src = SMS_ADDR("72631"), |
| 222 | .dst = SMS_ADDR("72632"), |
| 223 | .validity_minutes = 10, |
| 224 | /* SM TP-User-Data is taken from sms_tp_ud_set[] */ |
| 225 | }, |
| 226 | .ud = &sms_tp_ud_set[0], |
| 227 | }, |
| 228 | { |
| 229 | .name = "Same MSISDN #2", |
| 230 | .sms = { |
| 231 | .msg_ref = 0x12, |
| 232 | .src = SMS_ADDR("72632"), |
| 233 | .dst = SMS_ADDR("72631"), |
| 234 | .validity_minutes = 10, |
| 235 | /* SM TP-User-Data is taken from sms_tp_ud_set[] */ |
| 236 | }, |
| 237 | .ud = &sms_tp_ud_set[0], |
| 238 | }, |
| 239 | { |
| 240 | .name = "Expired SMS", |
| 241 | .sms = { |
| 242 | .msg_ref = 0xde, |
| 243 | .src = SMS_ADDR("3974733772"), |
| 244 | .dst = SMS_ADDR("3974733378"), |
| 245 | .validity_minutes = 0, |
| 246 | /* SM TP-User-Data is taken from sms_tp_ud_set[] */ |
| 247 | }, |
| 248 | .ud = &sms_tp_ud_set[0], |
| 249 | }, |
Vadim Yanitskiy | e1e7247 | 2019-04-09 16:55:44 +0700 | [diff] [blame] | 250 | { |
| 251 | .name = "Empty TP-UD", |
| 252 | .sms = { |
| 253 | .msg_ref = 0x38, |
| 254 | .src = SMS_ADDR("3678983772"), |
| 255 | .dst = SMS_ADDR("3678983378"), |
| 256 | .validity_minutes = 450, |
| 257 | .is_report = true, |
| 258 | .reply_path_req = 0x01, |
| 259 | .status_rep_req = 0x01, |
| 260 | .protocol_id = 0x55, |
| 261 | .data_coding_scheme = 0x08, |
| 262 | .ud_hdr_ind = 0x00, |
| 263 | .user_data_len = 0x00, |
| 264 | /* No TP-User-Data */ |
| 265 | }, |
| 266 | .ud = NULL, |
| 267 | }, |
Vadim Yanitskiy | e1e7247 | 2019-04-09 16:55:44 +0700 | [diff] [blame] | 268 | }; |
| 269 | |
| 270 | static void prepare_sms_test_set(void) |
| 271 | { |
| 272 | int i; |
| 273 | |
| 274 | for (i = 0; i < ARRAY_SIZE(sms_test_set); i++) { |
| 275 | struct sms_test *test = &sms_test_set[i]; |
| 276 | const struct sms_tp_ud *ud = test->ud; |
| 277 | |
| 278 | /* ID auto-increment */ |
| 279 | test->sms.id = i + 1; |
| 280 | |
| 281 | if (ud == NULL) |
| 282 | continue; |
| 283 | |
| 284 | test->sms.data_coding_scheme = ud->dcs; |
| 285 | test->sms.user_data_len = ud->length; |
| 286 | |
| 287 | if (ud->filler_byte) { |
| 288 | memset(test->sms.user_data, ud->filler_byte, |
| 289 | sizeof(test->sms.user_data)); |
| 290 | } else { |
| 291 | memcpy(test->sms.user_data, ud->data, sizeof(ud->data)); |
| 292 | if (ud->dec_text[0] != '\0') |
| 293 | strcpy(test->sms.text, ud->dec_text); |
| 294 | } |
| 295 | } |
| 296 | } |
| 297 | |
| 298 | static void test_db_sms_store(void) |
| 299 | { |
| 300 | int rc, i; |
| 301 | |
| 302 | LOGP(DDB, LOGL_INFO, "Testing db_sms_store()...\n"); |
| 303 | |
| 304 | /* Store test SMS messages */ |
| 305 | for (i = 0; i < ARRAY_SIZE(sms_test_set); i++) { |
| 306 | struct sms_test *test = &sms_test_set[i]; |
| 307 | |
| 308 | LOGP(DDB, LOGL_NOTICE, "%s('%s'): ", __func__, test->name); |
| 309 | |
| 310 | rc = db_sms_store(&test->sms); |
| 311 | if (!test->exp_db_sms_store_fail && rc == 0) |
| 312 | LOGPC(DDB, LOGL_INFO, "success, as expected\n"); |
| 313 | else if (test->exp_db_sms_store_fail && rc != 0) |
| 314 | LOGPC(DDB, LOGL_INFO, "failure, as expected\n"); |
| 315 | else |
| 316 | LOGPC(DDB, LOGL_ERROR, "unexpected rc=%d\n", rc); |
| 317 | } |
| 318 | } |
| 319 | |
| 320 | static int verify_sms(const struct sms_test *test, const struct gsm_sms *sms) |
| 321 | { |
| 322 | int rc; |
| 323 | |
| 324 | LOGP(DDB, LOGL_NOTICE, "%s('%s'): ", __func__, test->name); |
| 325 | |
| 326 | #define MATCH_SMS_ADDR(ADDR) \ |
| 327 | if (strcmp(sms->ADDR.addr, test->sms.ADDR.addr) \ |
| 328 | || sms->ADDR.npi != test->sms.ADDR.npi \ |
| 329 | || sms->ADDR.ton != test->sms.ADDR.ton) { \ |
| 330 | LOGPC(DDB, LOGL_ERROR, #ADDR " address mismatch\n"); \ |
| 331 | return -EINVAL; \ |
| 332 | } |
| 333 | |
| 334 | MATCH_SMS_ADDR(src); |
| 335 | MATCH_SMS_ADDR(dst); |
| 336 | |
| 337 | #define MATCH_SMS_PARAM(PARAM, FMT) \ |
| 338 | if (sms->PARAM != test->sms.PARAM) { \ |
| 339 | LOGPC(DDB, LOGL_ERROR, \ |
| 340 | #PARAM " mismatch: E%" FMT " vs A%" FMT "\n", \ |
| 341 | test->sms.PARAM, sms->PARAM); \ |
| 342 | return -EINVAL; \ |
| 343 | } |
| 344 | |
| 345 | MATCH_SMS_PARAM(id, "llu"); |
| 346 | MATCH_SMS_PARAM(validity_minutes, "lu"); |
| 347 | MATCH_SMS_PARAM(is_report, "i"); |
| 348 | MATCH_SMS_PARAM(reply_path_req, PRIu8); |
| 349 | MATCH_SMS_PARAM(status_rep_req, PRIu8); |
| 350 | MATCH_SMS_PARAM(ud_hdr_ind, PRIu8); |
| 351 | MATCH_SMS_PARAM(protocol_id, PRIu8); |
| 352 | MATCH_SMS_PARAM(data_coding_scheme, PRIu8); |
| 353 | MATCH_SMS_PARAM(msg_ref, PRIu8); |
| 354 | MATCH_SMS_PARAM(user_data_len, PRIu8); |
| 355 | |
| 356 | /* Compare TP-User-Data */ |
| 357 | rc = memcmp(sms->user_data, test->sms.user_data, |
| 358 | sizeof(sms->user_data)); |
| 359 | if (rc) { |
Pau Espin Pedrol | 17aa464 | 2019-06-04 11:18:37 +0200 | [diff] [blame] | 360 | LOGPC(DDB, LOGL_ERROR, "TP-User-Data mismatch\n"); |
Vadim Yanitskiy | e1e7247 | 2019-04-09 16:55:44 +0700 | [diff] [blame] | 361 | return -EINVAL; |
| 362 | } |
| 363 | |
| 364 | /* Compare decoded text */ |
| 365 | rc = strncmp(sms->text, test->sms.text, sizeof(sms->text)); |
| 366 | if (rc) { |
Pau Espin Pedrol | 17aa464 | 2019-06-04 11:18:37 +0200 | [diff] [blame] | 367 | LOGPC(DDB, LOGL_ERROR, "TP-User-Data (text) mismatch\n"); |
Vadim Yanitskiy | e1e7247 | 2019-04-09 16:55:44 +0700 | [diff] [blame] | 368 | return -EINVAL; |
| 369 | } |
| 370 | |
| 371 | LOGPC(DDB, LOGL_NOTICE, "match\n"); |
| 372 | return 0; |
| 373 | } |
| 374 | |
| 375 | static void test_db_sms_get(void) |
| 376 | { |
| 377 | struct gsm_sms *sms; |
| 378 | int i; |
| 379 | |
| 380 | LOGP(DDB, LOGL_INFO, "Testing db_sms_get()...\n"); |
| 381 | |
| 382 | /* Retrieve stored SMS messages */ |
| 383 | for (i = 0; i < ARRAY_SIZE(sms_test_set); i++) { |
| 384 | const struct sms_test *test = &sms_test_set[i]; |
| 385 | |
| 386 | LOGP(DDB, LOGL_NOTICE, "%s('%s'): ", __func__, test->name); |
| 387 | |
| 388 | sms = db_sms_get(NULL, test->sms.id); |
| 389 | if (!test->exp_db_sms_get_fail && sms != NULL) |
| 390 | LOGPC(DDB, LOGL_INFO, "success, as expected\n"); |
| 391 | else if (test->exp_db_sms_get_fail && sms == NULL) |
| 392 | LOGPC(DDB, LOGL_INFO, "failure, as expected\n"); |
| 393 | else |
| 394 | LOGPC(DDB, LOGL_ERROR, "unexpected result\n"); |
| 395 | |
| 396 | if (sms) { |
| 397 | verify_sms(test, sms); |
| 398 | talloc_free(sms); |
| 399 | } |
| 400 | } |
| 401 | } |
| 402 | |
| 403 | static void test_db_sms_delivery(void) |
| 404 | { |
| 405 | struct gsm_sms *sms1, *sms2; |
| 406 | struct gsm_sms *sms; |
| 407 | int rc; |
| 408 | |
| 409 | LOGP(DDB, LOGL_INFO, "Testing db_sms_get_next_unsent() " |
| 410 | "and db_sms_mark_delivered()...\n"); |
| 411 | |
| 412 | /* Retrieve both #1 and #2 */ |
| 413 | sms1 = db_sms_get_next_unsent(NULL, 1, 0); |
| 414 | LOGP(DDB, LOGL_NOTICE, "db_sms_get_next_unsent(#1): %s\n", |
| 415 | sms1 ? "found" : "not found"); |
| 416 | if (sms1 != NULL) |
| 417 | verify_sms(&sms_test_set[0], sms1); |
| 418 | |
| 419 | sms2 = db_sms_get_next_unsent(NULL, 2, 0); |
| 420 | LOGP(DDB, LOGL_NOTICE, "db_sms_get_next_unsent(#2): %s\n", |
| 421 | sms2 ? "found" : "not found"); |
| 422 | if (sms2 != NULL) |
| 423 | verify_sms(&sms_test_set[1], sms2); |
| 424 | |
| 425 | /* Mark both #1 and #2 and delivered, release memory */ |
| 426 | if (sms1) { |
| 427 | LOGP(DDB, LOGL_DEBUG, "Marking #%llu as delivered: ", sms1->id); |
| 428 | rc = db_sms_mark_delivered(sms1); |
| 429 | LOGPC(DDB, LOGL_DEBUG, "rc=%d\n", rc); |
| 430 | talloc_free(sms1); |
| 431 | } |
| 432 | |
| 433 | if (sms2) { |
| 434 | LOGP(DDB, LOGL_DEBUG, "Marking #%llu as delivered: ", sms2->id); |
| 435 | rc = db_sms_mark_delivered(sms2); |
| 436 | LOGPC(DDB, LOGL_DEBUG, "rc=%d\n", rc); |
| 437 | talloc_free(sms2); |
| 438 | } |
| 439 | |
| 440 | /* Expect #3 as the next undelivered */ |
| 441 | sms = db_sms_get_next_unsent(NULL, 1, 0); |
| 442 | LOGP(DDB, LOGL_NOTICE, "db_sms_get_next_unsent(starting from #1): %s\n", |
| 443 | sms ? "found" : "not found"); |
| 444 | if (sms) { |
| 445 | verify_sms(&sms_test_set[2], sms); |
| 446 | talloc_free(sms); |
| 447 | } |
| 448 | } |
| 449 | |
| 450 | static void test_db_sms_delete(void) |
| 451 | { |
| 452 | int rc; |
| 453 | |
| 454 | LOGP(DDB, LOGL_INFO, "Testing db_sms_delete_sent_message_by_id()...\n"); |
| 455 | |
| 456 | /* Delete #1, which is marked as sent */ |
| 457 | LOGP(DDB, LOGL_NOTICE, "db_sms_delete_sent_message_by_id(#1, sent): "); |
| 458 | rc = db_sms_delete_sent_message_by_id(1); |
| 459 | LOGPC(DDB, LOGL_NOTICE, "rc=%d\n", rc); |
| 460 | /* Don't expect to retrieve this message anymore */ |
| 461 | sms_test_set[0].exp_db_sms_get_fail = true; |
| 462 | |
| 463 | /* Try to delete #3, which is not marked as sent */ |
| 464 | LOGP(DDB, LOGL_NOTICE, "db_sms_delete_sent_message_by_id(#3, not sent): "); |
| 465 | rc = db_sms_delete_sent_message_by_id(3); |
| 466 | LOGPC(DDB, LOGL_NOTICE, "rc=%d\n", rc); |
| 467 | /* Do expect to retrieve this message anyway */ |
| 468 | sms_test_set[2].exp_db_sms_get_fail = false; |
| 469 | |
| 470 | LOGP(DDB, LOGL_INFO, "Testing db_sms_delete_by_msisdn()...\n"); |
| 471 | |
| 472 | LOGP(DDB, LOGL_NOTICE, "db_sms_delete_by_msisdn('72631'): "); |
| 473 | rc = db_sms_delete_by_msisdn("72631"); |
| 474 | LOGPC(DDB, LOGL_NOTICE, "rc=%d\n", rc); |
| 475 | |
| 476 | /* Don't expect both #8 and #9 anymore */ |
| 477 | sms_test_set[7].exp_db_sms_get_fail = true; |
| 478 | sms_test_set[8].exp_db_sms_get_fail = true; |
| 479 | |
| 480 | LOGP(DDB, LOGL_INFO, "Testing db_sms_delete_oldest_expired_message()...\n"); |
| 481 | |
| 482 | LOGP(DDB, LOGL_NOTICE, "db_sms_delete_oldest_expired_message()\n"); |
| 483 | db_sms_delete_oldest_expired_message(); |
| 484 | |
| 485 | /* Don't expect #10 anymore */ |
| 486 | sms_test_set[9].exp_db_sms_get_fail = true; |
| 487 | |
| 488 | /* We need to make sure that we removed exactly what we expected to remove */ |
| 489 | LOGP(DDB, LOGL_INFO, "Expectations updated, retrieving all messages again\n"); |
| 490 | test_db_sms_get(); |
| 491 | } |
| 492 | |
| 493 | static struct log_info_cat db_sms_test_categories[] = { |
| 494 | [DDB] = { |
| 495 | .name = "DDB", |
| 496 | .description = "Database Layer", |
| 497 | .enabled = 1, .loglevel = LOGL_DEBUG, |
| 498 | }, |
| 499 | }; |
| 500 | |
| 501 | static struct log_info info = { |
| 502 | .cat = db_sms_test_categories, |
| 503 | .num_cat = ARRAY_SIZE(db_sms_test_categories), |
| 504 | }; |
| 505 | |
| 506 | int main(int argc, char **argv) |
| 507 | { |
| 508 | void *logging_ctx; |
| 509 | int rc; |
| 510 | |
| 511 | /* Track the use of talloc NULL memory contexts */ |
| 512 | talloc_enable_null_tracking(); |
| 513 | |
| 514 | talloc_ctx = talloc_named_const(NULL, 0, "db_sms_test"); |
| 515 | logging_ctx = talloc_named_const(talloc_ctx, 0, "logging"); |
| 516 | osmo_init_logging2(logging_ctx, &info); |
| 517 | |
| 518 | OSMO_ASSERT(osmo_stderr_target); |
| 519 | log_set_use_color(osmo_stderr_target, 0); |
| 520 | log_set_print_timestamp(osmo_stderr_target, 0); |
| 521 | log_set_print_filename(osmo_stderr_target, 0); |
| 522 | log_set_print_category(osmo_stderr_target, 1); |
| 523 | log_set_print_level(osmo_stderr_target, 1); |
| 524 | |
| 525 | #if 0 |
| 526 | /* Having the database stored in a regular file may be useful |
| 527 | * for debugging, but this comes at the price of performance. */ |
| 528 | FILE *dbf = fopen("db_sms_test.db", "wb"); |
| 529 | OSMO_ASSERT(dbf != NULL); |
| 530 | fclose(dbf); |
| 531 | #endif |
| 532 | |
| 533 | /* Init a volatile database in RAM */ |
| 534 | LOGP(DDB, LOGL_DEBUG, "Init a new database\n"); |
| 535 | |
| 536 | /* HACK: db_init() prints libdbi version using LOGL_NOTICE, so |
| 537 | * the test output is not deterministic. Let's suppress this |
| 538 | * message by increasing the log level to LOGL_ERROR. */ |
| 539 | log_parse_category_mask(osmo_stderr_target, "DDB,7"); |
| 540 | rc = db_init(":memory:"); |
| 541 | OSMO_ASSERT(rc == 0); |
| 542 | |
| 543 | /* HACK: relax log level back to LOGL_DEBUG (see note above) */ |
| 544 | log_parse_category_mask(osmo_stderr_target, "DDB,1"); |
| 545 | |
| 546 | /* Prepare some tables */ |
| 547 | rc = db_prepare(); |
| 548 | OSMO_ASSERT(rc == 0); |
| 549 | LOGP(DDB, LOGL_DEBUG, "Init complete\n"); |
| 550 | |
| 551 | /* Prepare the test set */ |
| 552 | prepare_sms_test_set(); |
| 553 | |
| 554 | test_db_sms_store(); |
| 555 | test_db_sms_get(); |
| 556 | |
| 557 | test_db_sms_delivery(); |
| 558 | test_db_sms_delete(); |
| 559 | |
| 560 | /* Close the database */ |
| 561 | db_fini(); |
| 562 | |
| 563 | /* Deinit logging */ |
| 564 | log_fini(); |
| 565 | |
| 566 | /* Check for memory leaks */ |
| 567 | rc = talloc_total_blocks(talloc_ctx); |
| 568 | OSMO_ASSERT(rc == 2); /* db_sms_test + logging */ |
| 569 | talloc_free(talloc_ctx); |
| 570 | |
| 571 | talloc_report_full(NULL, stderr); |
| 572 | talloc_disable_null_tracking(); |
| 573 | |
| 574 | return 0; |
| 575 | } |