/* test_config_queue_reconcile.c -- bug-1469: a queue added by a live config * upgrade used to exist only after a restart, because build_queues() ran * only at boot. reconcile_config_queues() creates the missing runtime queue * objects when a config is activated, notifies the scheduler/apiserver * (without a WAL fact -- config queues are config-owned), leaves existing * queues untouched, and is idempotent (boot's build_queues() uses it too). */ #include #include #include #include #include #include "clusterconfig.h" #include "cluster.h" #include "hook.h" #include "myconf.h" #include "qobj.h" #include "xce/cluster_def.h" #include "xstring.h" static int g_cqr_queue_updates; static int cqr_queue_spy(int type, int situation, int detail, void* data, va_list ap) { (void)type; (void)data; (void)ap; if (situation == HOOK_AFTER_EVENT && detail == HOOK_DETAIL_QUEUE_UPDATE) g_cqr_queue_updates++; return 0; } static queue_t* cqr_find(cluster_t* c, const char* name) { queue_t* q = NULL; lock(c->qmgr, RTTI_LOCK_READ); key_find(c->qmgr, (void*)name, (void**)&q); unlock(c->qmgr); return q; } static void test_reconcile_creates_queue_added_by_config(void) { kvmgr_params_t str_params = { .key_type = KVMGR_KEY_STRING, .nslots = 16, .delta = 8 }; cluster_t c; myconf_t conf; cluster_config_t cfg; xce_queue_t qa, qb; xce_queue_t* queues[2]; queue_t* before; if (makeString((char*)"cqr-probe") == NULL) xstring_table_init(64); memset(&c, 0, sizeof(c)); memset(&conf, 0, sizeof(conf)); memset(&cfg, 0, sizeof(cfg)); TEST_ASSERT_EQUAL_INT(0, xce_hook_init(&c.hooksys, XCE_CONTROLLER_HOOK_MAX)); c.qmgr = makeInstance(&xkvmgr_type, &str_params); TEST_ASSERT_NOT_NULL(c.qmgr); memset(&qa, 0, sizeof(qa)); qa.queue = (char*)"cqr-existing"; memset(&qb, 0, sizeof(qb)); qb.queue = (char*)"cqr-added"; queues[0] = &qa; queues[1] = &qb; cfg.nqueues = 2; cfg.queues = queues; conf.cluster_config = &cfg; c.myconf = &conf; /* The old config's queue already exists at runtime. */ TEST_ASSERT_NOT_NULL(create_queue(&c, &qa)); before = cqr_find(&c, "cqr-existing"); TEST_ASSERT_NOT_NULL(before); g_cqr_queue_updates = 0; TEST_ASSERT_EQUAL_INT(0, xce_add_hook(&c.hooksys, XCE_CONTROLLER_HOOK_QUEUE, cqr_queue_spy, NULL)); TEST_ASSERT_EQUAL_INT_MESSAGE(1, reconcile_config_queues(&c, 1), "bug-1469: the queue added by the new config must be created"); TEST_ASSERT_NOT_NULL(cqr_find(&c, "cqr-added")); TEST_ASSERT_EQUAL_PTR_MESSAGE(before, cqr_find(&c, "cqr-existing"), "an existing queue object must be left untouched"); TEST_ASSERT_EQUAL_INT_MESSAGE(1, g_cqr_queue_updates, "the scheduler/apiserver must be told about the new queue"); /* Idempotent: a second activation (or boot's build_queues) adds nothing. */ TEST_ASSERT_EQUAL_INT(0, reconcile_config_queues(&c, 1)); TEST_ASSERT_EQUAL_INT(1, g_cqr_queue_updates); TEST_ASSERT_EQUAL_INT(0, build_queues(&c)); TEST_ASSERT_EQUAL_PTR(before, cqr_find(&c, "cqr-existing")); xce_hook_fini(&c.hooksys); dereference(c.qmgr); } void test_config_queue_reconcile(void) { UnitySetTestFile(__FILE__); RUN_TEST(test_reconcile_creates_queue_added_by_config); }