1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "spdk/stdinc.h" 35 36 #include "CUnit/Basic.h" 37 #include "spdk_cunit.h" 38 39 #include "spdk/util.h" 40 41 #include "scsi/dev.c" 42 #include "scsi/port.c" 43 44 #include "spdk_internal/mock.h" 45 46 DEFINE_STUB(spdk_scsi_lun_is_removing, bool, 47 (const struct spdk_scsi_lun *lun), false); 48 49 static char *g_bdev_names[] = { 50 "malloc0", 51 "malloc1", 52 }; 53 54 static struct spdk_scsi_port *g_initiator_port_with_pending_tasks = NULL; 55 static struct spdk_scsi_port *g_initiator_port_with_pending_mgmt_tasks = NULL; 56 57 static struct spdk_scsi_task * 58 spdk_get_task(uint32_t *owner_task_ctr) 59 { 60 struct spdk_scsi_task *task; 61 62 task = calloc(1, sizeof(*task)); 63 if (!task) { 64 return NULL; 65 } 66 67 return task; 68 } 69 70 void 71 spdk_scsi_task_put(struct spdk_scsi_task *task) 72 { 73 free(task); 74 } 75 76 struct spdk_scsi_lun *scsi_lun_construct(const char *bdev_name, 77 void (*resize_cb)(const struct spdk_scsi_lun *, void *), 78 void *resize_ctx, 79 void (*hotremove_cb)(const struct spdk_scsi_lun *, void *), 80 void *hotremove_ctx) 81 { 82 struct spdk_scsi_lun *lun; 83 size_t i; 84 85 for (i = 0; i < SPDK_COUNTOF(g_bdev_names); i++) { 86 if (strcmp(bdev_name, g_bdev_names[i]) == 0) { 87 lun = calloc(1, sizeof(struct spdk_scsi_lun)); 88 SPDK_CU_ASSERT_FATAL(lun != NULL); 89 90 return lun; 91 } 92 } 93 94 return NULL; 95 } 96 97 void 98 scsi_lun_destruct(struct spdk_scsi_lun *lun) 99 { 100 free(lun); 101 } 102 103 DEFINE_STUB_V(scsi_lun_execute_mgmt_task, 104 (struct spdk_scsi_lun *lun, struct spdk_scsi_task *task)); 105 106 DEFINE_STUB_V(scsi_lun_execute_task, 107 (struct spdk_scsi_lun *lun, struct spdk_scsi_task *task)); 108 109 DEFINE_STUB(scsi_lun_allocate_io_channel, int, 110 (struct spdk_scsi_lun *lun), 0); 111 112 DEFINE_STUB_V(scsi_lun_free_io_channel, (struct spdk_scsi_lun *lun)); 113 114 bool 115 scsi_lun_has_pending_mgmt_tasks(const struct spdk_scsi_lun *lun, 116 const struct spdk_scsi_port *initiator_port) 117 { 118 return (g_initiator_port_with_pending_mgmt_tasks == initiator_port); 119 } 120 121 bool 122 scsi_lun_has_pending_tasks(const struct spdk_scsi_lun *lun, 123 const struct spdk_scsi_port *initiator_port) 124 { 125 return (g_initiator_port_with_pending_tasks == initiator_port); 126 } 127 128 static void 129 dev_destruct_null_dev(void) 130 { 131 /* pass null for the dev */ 132 spdk_scsi_dev_destruct(NULL, NULL, NULL); 133 } 134 135 static void 136 dev_destruct_zero_luns(void) 137 { 138 struct spdk_scsi_dev dev = { .is_allocated = 1 }; 139 140 /* No luns attached to the dev */ 141 142 /* free the dev */ 143 spdk_scsi_dev_destruct(&dev, NULL, NULL); 144 } 145 146 static void 147 dev_destruct_null_lun(void) 148 { 149 struct spdk_scsi_dev dev = { .is_allocated = 1 }; 150 151 /* pass null for the lun */ 152 dev.lun[0] = NULL; 153 154 /* free the dev */ 155 spdk_scsi_dev_destruct(&dev, NULL, NULL); 156 } 157 158 static void 159 dev_destruct_success(void) 160 { 161 struct spdk_scsi_dev dev = { .is_allocated = 1 }; 162 int rc; 163 164 /* dev with a single lun */ 165 rc = spdk_scsi_dev_add_lun(&dev, "malloc0", 0, NULL, NULL); 166 167 CU_ASSERT(rc == 0); 168 169 /* free the dev */ 170 spdk_scsi_dev_destruct(&dev, NULL, NULL); 171 172 } 173 174 static void 175 dev_construct_num_luns_zero(void) 176 { 177 struct spdk_scsi_dev *dev; 178 const char *bdev_name_list[1] = {}; 179 int lun_id_list[1] = { 0 }; 180 181 dev = spdk_scsi_dev_construct("Name", bdev_name_list, lun_id_list, 0, 182 SPDK_SPC_PROTOCOL_IDENTIFIER_ISCSI, NULL, NULL); 183 184 /* dev should be null since we passed num_luns = 0 */ 185 CU_ASSERT_TRUE(dev == NULL); 186 } 187 188 static void 189 dev_construct_no_lun_zero(void) 190 { 191 struct spdk_scsi_dev *dev; 192 const char *bdev_name_list[1] = {}; 193 int lun_id_list[1] = { 0 }; 194 195 lun_id_list[0] = 1; 196 197 dev = spdk_scsi_dev_construct("Name", bdev_name_list, lun_id_list, 1, 198 SPDK_SPC_PROTOCOL_IDENTIFIER_ISCSI, NULL, NULL); 199 200 /* dev should be null since no LUN0 was specified (lun_id_list[0] = 1) */ 201 CU_ASSERT_TRUE(dev == NULL); 202 } 203 204 static void 205 dev_construct_null_lun(void) 206 { 207 struct spdk_scsi_dev *dev; 208 const char *bdev_name_list[1] = {}; 209 int lun_id_list[1] = { 0 }; 210 211 dev = spdk_scsi_dev_construct("Name", bdev_name_list, lun_id_list, 1, 212 SPDK_SPC_PROTOCOL_IDENTIFIER_ISCSI, NULL, NULL); 213 214 /* dev should be null since no LUN0 was specified (lun_list[0] = NULL) */ 215 CU_ASSERT_TRUE(dev == NULL); 216 } 217 218 static void 219 dev_construct_name_too_long(void) 220 { 221 struct spdk_scsi_dev *dev; 222 const char *bdev_name_list[1] = {"malloc0"}; 223 int lun_id_list[1] = { 0 }; 224 char name[SPDK_SCSI_DEV_MAX_NAME + 1 + 1]; 225 226 /* Try to construct a dev with a name that is one byte longer than allowed. */ 227 memset(name, 'x', sizeof(name) - 1); 228 name[sizeof(name) - 1] = '\0'; 229 230 dev = spdk_scsi_dev_construct(name, bdev_name_list, lun_id_list, 1, 231 SPDK_SPC_PROTOCOL_IDENTIFIER_ISCSI, NULL, NULL); 232 233 CU_ASSERT(dev == NULL); 234 } 235 236 static void 237 dev_construct_success(void) 238 { 239 struct spdk_scsi_dev *dev; 240 const char *bdev_name_list[1] = {"malloc0"}; 241 int lun_id_list[1] = { 0 }; 242 243 dev = spdk_scsi_dev_construct("Name", bdev_name_list, lun_id_list, 1, 244 SPDK_SPC_PROTOCOL_IDENTIFIER_ISCSI, NULL, NULL); 245 246 /* Successfully constructs and returns a dev */ 247 CU_ASSERT_TRUE(dev != NULL); 248 249 /* free the dev */ 250 spdk_scsi_dev_destruct(dev, NULL, NULL); 251 } 252 253 static void 254 dev_construct_success_lun_zero_not_first(void) 255 { 256 struct spdk_scsi_dev *dev; 257 const char *bdev_name_list[2] = {"malloc1", "malloc0"}; 258 int lun_id_list[2] = { 1, 0 }; 259 260 dev = spdk_scsi_dev_construct("Name", bdev_name_list, lun_id_list, 2, 261 SPDK_SPC_PROTOCOL_IDENTIFIER_ISCSI, NULL, NULL); 262 263 /* Successfully constructs and returns a dev */ 264 CU_ASSERT_TRUE(dev != NULL); 265 266 /* free the dev */ 267 spdk_scsi_dev_destruct(dev, NULL, NULL); 268 } 269 270 static void 271 dev_queue_mgmt_task_success(void) 272 { 273 struct spdk_scsi_dev *dev; 274 const char *bdev_name_list[1] = {"malloc0"}; 275 int lun_id_list[1] = { 0 }; 276 struct spdk_scsi_task *task; 277 278 dev = spdk_scsi_dev_construct("Name", bdev_name_list, lun_id_list, 1, 279 SPDK_SPC_PROTOCOL_IDENTIFIER_ISCSI, NULL, NULL); 280 281 /* Successfully constructs and returns a dev */ 282 CU_ASSERT_TRUE(dev != NULL); 283 284 task = spdk_get_task(NULL); 285 286 task->function = SPDK_SCSI_TASK_FUNC_LUN_RESET; 287 spdk_scsi_dev_queue_mgmt_task(dev, task); 288 289 spdk_scsi_task_put(task); 290 291 spdk_scsi_dev_destruct(dev, NULL, NULL); 292 } 293 294 static void 295 dev_queue_task_success(void) 296 { 297 struct spdk_scsi_dev *dev; 298 const char *bdev_name_list[1] = {"malloc0"}; 299 int lun_id_list[1] = { 0 }; 300 struct spdk_scsi_task *task; 301 302 dev = spdk_scsi_dev_construct("Name", bdev_name_list, lun_id_list, 1, 303 SPDK_SPC_PROTOCOL_IDENTIFIER_ISCSI, NULL, NULL); 304 305 /* Successfully constructs and returns a dev */ 306 CU_ASSERT_TRUE(dev != NULL); 307 308 task = spdk_get_task(NULL); 309 310 spdk_scsi_dev_queue_task(dev, task); 311 312 spdk_scsi_task_put(task); 313 314 spdk_scsi_dev_destruct(dev, NULL, NULL); 315 } 316 317 static void 318 dev_stop_success(void) 319 { 320 struct spdk_scsi_dev dev = { 0 }; 321 struct spdk_scsi_task *task; 322 struct spdk_scsi_task *task_mgmt; 323 324 task = spdk_get_task(NULL); 325 326 spdk_scsi_dev_queue_task(&dev, task); 327 328 task_mgmt = spdk_get_task(NULL); 329 330 /* Enqueue the tasks into dev->task_mgmt_submit_queue */ 331 task->function = SPDK_SCSI_TASK_FUNC_LUN_RESET; 332 spdk_scsi_dev_queue_mgmt_task(&dev, task_mgmt); 333 334 spdk_scsi_task_put(task); 335 spdk_scsi_task_put(task_mgmt); 336 } 337 338 static void 339 dev_add_port_max_ports(void) 340 { 341 struct spdk_scsi_dev dev = { 0 }; 342 const char *name; 343 int id, rc; 344 345 /* dev is set to SPDK_SCSI_DEV_MAX_PORTS */ 346 dev.num_ports = SPDK_SCSI_DEV_MAX_PORTS; 347 name = "Name of Port"; 348 id = 1; 349 350 rc = spdk_scsi_dev_add_port(&dev, id, name); 351 352 /* returns -1; since the dev already has maximum 353 * number of ports (SPDK_SCSI_DEV_MAX_PORTS) */ 354 CU_ASSERT_TRUE(rc < 0); 355 } 356 357 static void 358 dev_add_port_construct_failure1(void) 359 { 360 struct spdk_scsi_dev dev = { 0 }; 361 const int port_name_length = SPDK_SCSI_PORT_MAX_NAME_LENGTH + 2; 362 char name[port_name_length]; 363 uint64_t id; 364 int rc; 365 366 dev.num_ports = 1; 367 /* Set the name such that the length exceeds SPDK_SCSI_PORT_MAX_NAME_LENGTH 368 * SPDK_SCSI_PORT_MAX_NAME_LENGTH = 256 */ 369 memset(name, 'a', port_name_length - 1); 370 name[port_name_length - 1] = '\0'; 371 id = 1; 372 373 rc = spdk_scsi_dev_add_port(&dev, id, name); 374 375 /* returns -1; since the length of the name exceeds 376 * SPDK_SCSI_PORT_MAX_NAME_LENGTH */ 377 CU_ASSERT_TRUE(rc < 0); 378 } 379 380 static void 381 dev_add_port_construct_failure2(void) 382 { 383 struct spdk_scsi_dev dev = { 0 }; 384 const char *name; 385 uint64_t id; 386 int rc; 387 388 dev.num_ports = 1; 389 name = "Name of Port"; 390 id = 1; 391 392 /* Initialize port[0] to be valid and its index is set to 1 */ 393 dev.port[0].id = id; 394 dev.port[0].is_used = 1; 395 396 rc = spdk_scsi_dev_add_port(&dev, id, name); 397 398 /* returns -1; since the dev already has a port whose index to be 1 */ 399 CU_ASSERT_TRUE(rc < 0); 400 } 401 402 static void 403 dev_add_port_success1(void) 404 { 405 struct spdk_scsi_dev dev = { 0 }; 406 const char *name; 407 int id, rc; 408 409 dev.num_ports = 1; 410 name = "Name of Port"; 411 id = 1; 412 413 rc = spdk_scsi_dev_add_port(&dev, id, name); 414 415 /* successfully adds a port */ 416 CU_ASSERT_EQUAL(rc, 0); 417 /* Assert num_ports has been incremented to 2 */ 418 CU_ASSERT_EQUAL(dev.num_ports, 2); 419 } 420 421 static void 422 dev_add_port_success2(void) 423 { 424 struct spdk_scsi_dev dev = { 0 }; 425 const char *name; 426 uint64_t id; 427 int rc; 428 429 dev.num_ports = 1; 430 name = "Name of Port"; 431 id = 1; 432 /* set id of invalid port[0] to 1. This must be ignored */ 433 dev.port[0].id = id; 434 dev.port[0].is_used = 0; 435 436 rc = spdk_scsi_dev_add_port(&dev, id, name); 437 438 /* successfully adds a port */ 439 CU_ASSERT_EQUAL(rc, 0); 440 /* Assert num_ports has been incremented to 1 */ 441 CU_ASSERT_EQUAL(dev.num_ports, 2); 442 } 443 444 static void 445 dev_add_port_success3(void) 446 { 447 struct spdk_scsi_dev dev = { 0 }; 448 const char *name; 449 uint64_t add_id; 450 int rc; 451 452 dev.num_ports = 1; 453 name = "Name of Port"; 454 dev.port[0].id = 1; 455 dev.port[0].is_used = 1; 456 add_id = 2; 457 458 /* Add a port with id = 2 */ 459 rc = spdk_scsi_dev_add_port(&dev, add_id, name); 460 461 /* successfully adds a port */ 462 CU_ASSERT_EQUAL(rc, 0); 463 /* Assert num_ports has been incremented to 2 */ 464 CU_ASSERT_EQUAL(dev.num_ports, 2); 465 } 466 467 static void 468 dev_find_port_by_id_num_ports_zero(void) 469 { 470 struct spdk_scsi_dev dev = { 0 }; 471 struct spdk_scsi_port *rp_port; 472 uint64_t id; 473 474 dev.num_ports = 0; 475 id = 1; 476 477 rp_port = spdk_scsi_dev_find_port_by_id(&dev, id); 478 479 /* returns null; since dev's num_ports is 0 */ 480 CU_ASSERT_TRUE(rp_port == NULL); 481 } 482 483 static void 484 dev_find_port_by_id_id_not_found_failure(void) 485 { 486 struct spdk_scsi_dev dev = { 0 }; 487 struct spdk_scsi_port *rp_port; 488 const char *name; 489 int rc; 490 uint64_t id, find_id; 491 492 id = 1; 493 dev.num_ports = 1; 494 name = "Name of Port"; 495 find_id = 2; 496 497 /* Add a port with id = 1 */ 498 rc = spdk_scsi_dev_add_port(&dev, id, name); 499 500 CU_ASSERT_EQUAL(rc, 0); 501 502 /* Find port with id = 2 */ 503 rp_port = spdk_scsi_dev_find_port_by_id(&dev, find_id); 504 505 /* returns null; failed to find port specified by id = 2 */ 506 CU_ASSERT_TRUE(rp_port == NULL); 507 } 508 509 static void 510 dev_find_port_by_id_success(void) 511 { 512 struct spdk_scsi_dev dev = { 0 }; 513 struct spdk_scsi_port *rp_port; 514 const char *name; 515 int rc; 516 uint64_t id; 517 518 id = 1; 519 dev.num_ports = 1; 520 name = "Name of Port"; 521 522 /* Add a port */ 523 rc = spdk_scsi_dev_add_port(&dev, id, name); 524 525 CU_ASSERT_EQUAL(rc, 0); 526 527 /* Find port by the same id as the one added above */ 528 rp_port = spdk_scsi_dev_find_port_by_id(&dev, id); 529 530 /* Successfully found port specified by id */ 531 CU_ASSERT_TRUE(rp_port != NULL); 532 if (rp_port != NULL) { 533 /* Assert the found port's id and name are same as 534 * the port added. */ 535 CU_ASSERT_EQUAL(rp_port->id, 1); 536 CU_ASSERT_STRING_EQUAL(rp_port->name, "Name of Port"); 537 } 538 } 539 540 static void 541 dev_add_lun_bdev_not_found(void) 542 { 543 int rc; 544 struct spdk_scsi_dev dev = {0}; 545 546 rc = spdk_scsi_dev_add_lun(&dev, "malloc2", 0, NULL, NULL); 547 548 SPDK_CU_ASSERT_FATAL(dev.lun[0] == NULL); 549 CU_ASSERT_NOT_EQUAL(rc, 0); 550 } 551 552 static void 553 dev_add_lun_no_free_lun_id(void) 554 { 555 int rc; 556 int i; 557 struct spdk_scsi_dev dev = {0}; 558 struct spdk_scsi_lun lun; 559 560 for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) { 561 dev.lun[i] = &lun; 562 } 563 564 rc = spdk_scsi_dev_add_lun(&dev, "malloc0", -1, NULL, NULL); 565 566 CU_ASSERT_NOT_EQUAL(rc, 0); 567 } 568 569 static void 570 dev_add_lun_success1(void) 571 { 572 int rc; 573 struct spdk_scsi_dev dev = {0}; 574 575 rc = spdk_scsi_dev_add_lun(&dev, "malloc0", -1, NULL, NULL); 576 577 CU_ASSERT_EQUAL(rc, 0); 578 579 spdk_scsi_dev_destruct(&dev, NULL, NULL); 580 } 581 582 static void 583 dev_add_lun_success2(void) 584 { 585 int rc; 586 struct spdk_scsi_dev dev = {0}; 587 588 rc = spdk_scsi_dev_add_lun(&dev, "malloc0", 0, NULL, NULL); 589 590 CU_ASSERT_EQUAL(rc, 0); 591 592 spdk_scsi_dev_destruct(&dev, NULL, NULL); 593 } 594 595 static void 596 dev_check_pending_tasks(void) 597 { 598 struct spdk_scsi_dev dev = {}; 599 struct spdk_scsi_lun lun = {}; 600 struct spdk_scsi_port initiator_port = {}; 601 602 g_initiator_port_with_pending_tasks = NULL; 603 g_initiator_port_with_pending_mgmt_tasks = NULL; 604 605 CU_ASSERT(spdk_scsi_dev_has_pending_tasks(&dev, NULL) == false); 606 607 dev.lun[SPDK_SCSI_DEV_MAX_LUN - 1] = &lun; 608 609 CU_ASSERT(spdk_scsi_dev_has_pending_tasks(&dev, NULL) == true); 610 CU_ASSERT(spdk_scsi_dev_has_pending_tasks(&dev, &initiator_port) == false); 611 612 g_initiator_port_with_pending_tasks = &initiator_port; 613 CU_ASSERT(spdk_scsi_dev_has_pending_tasks(&dev, NULL) == true); 614 CU_ASSERT(spdk_scsi_dev_has_pending_tasks(&dev, &initiator_port) == true); 615 616 g_initiator_port_with_pending_tasks = NULL; 617 g_initiator_port_with_pending_mgmt_tasks = &initiator_port; 618 CU_ASSERT(spdk_scsi_dev_has_pending_tasks(&dev, NULL) == true); 619 CU_ASSERT(spdk_scsi_dev_has_pending_tasks(&dev, &initiator_port) == true); 620 } 621 622 int 623 main(int argc, char **argv) 624 { 625 CU_pSuite suite = NULL; 626 unsigned int num_failures; 627 628 CU_set_error_action(CUEA_ABORT); 629 CU_initialize_registry(); 630 631 suite = CU_add_suite("dev_suite", NULL, NULL); 632 633 CU_ADD_TEST(suite, dev_destruct_null_dev); 634 CU_ADD_TEST(suite, dev_destruct_zero_luns); 635 CU_ADD_TEST(suite, dev_destruct_null_lun); 636 CU_ADD_TEST(suite, dev_destruct_success); 637 CU_ADD_TEST(suite, dev_construct_num_luns_zero); 638 CU_ADD_TEST(suite, dev_construct_no_lun_zero); 639 CU_ADD_TEST(suite, dev_construct_null_lun); 640 CU_ADD_TEST(suite, dev_construct_name_too_long); 641 CU_ADD_TEST(suite, dev_construct_success); 642 CU_ADD_TEST(suite, dev_construct_success_lun_zero_not_first); 643 CU_ADD_TEST(suite, dev_queue_mgmt_task_success); 644 CU_ADD_TEST(suite, dev_queue_task_success); 645 CU_ADD_TEST(suite, dev_stop_success); 646 CU_ADD_TEST(suite, dev_add_port_max_ports); 647 CU_ADD_TEST(suite, dev_add_port_construct_failure1); 648 CU_ADD_TEST(suite, dev_add_port_construct_failure2); 649 CU_ADD_TEST(suite, dev_add_port_success1); 650 CU_ADD_TEST(suite, dev_add_port_success2); 651 CU_ADD_TEST(suite, dev_add_port_success3); 652 CU_ADD_TEST(suite, dev_find_port_by_id_num_ports_zero); 653 CU_ADD_TEST(suite, dev_find_port_by_id_id_not_found_failure); 654 CU_ADD_TEST(suite, dev_find_port_by_id_success); 655 CU_ADD_TEST(suite, dev_add_lun_bdev_not_found); 656 CU_ADD_TEST(suite, dev_add_lun_no_free_lun_id); 657 CU_ADD_TEST(suite, dev_add_lun_success1); 658 CU_ADD_TEST(suite, dev_add_lun_success2); 659 CU_ADD_TEST(suite, dev_check_pending_tasks); 660 661 CU_basic_set_mode(CU_BRM_VERBOSE); 662 CU_basic_run_tests(); 663 num_failures = CU_get_number_of_failures(); 664 CU_cleanup_registry(); 665 666 return num_failures; 667 } 668