bridges/bridge_t38: Add a bridging module for managing T.38 state
[asterisk/asterisk.git] / tests / test_sorcery.c
index 2d811b1..5d96422 100644 (file)
@@ -32,7 +32,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "")
+ASTERISK_REGISTER_FILE()
 
 #include "asterisk/test.h"
 #include "asterisk/module.h"
@@ -138,6 +138,9 @@ struct sorcery_test_caching {
        /*! \brief Whether the object has been deleted from the cache or not */
        unsigned int deleted:1;
 
+       /*! \brief Whether the object is stale or not */
+       unsigned int is_stale:1;
+
        /*! \brief Object to return when asked */
        struct test_sorcery_object object;
 };
@@ -179,6 +182,19 @@ static struct sorcery_test_caching cache = { 0, };
 /*! \brief Global scope observer structure for testing */
 static struct sorcery_test_observer observer;
 
+static void *wizard2_data;
+
+static void *sorcery_test_open(const char *data)
+{
+       wizard2_data = (void *)data;
+       return wizard2_data;
+}
+
+static void sorcery_test_close(void *data)
+{
+
+}
+
 static int sorcery_test_create(const struct ast_sorcery *sorcery, void *data, void *object)
 {
        cache.created = 1;
@@ -204,7 +220,13 @@ static int sorcery_test_delete(const struct ast_sorcery *sorcery, void *data, vo
        return 0;
 }
 
-/*! \brief Dummy sorcery wizard, not actually used so we only populate the name and nothing else */
+static int sorcery_test_is_stale(const struct ast_sorcery *sorcery, void *data, void *object)
+{
+       cache.is_stale = 1;
+       return 1;
+}
+
+/*! \brief Dummy sorcery wizards, not actually used so we only populate the name and nothing else */
 static struct ast_sorcery_wizard test_wizard = {
        .name = "test",
        .create = sorcery_test_create,
@@ -213,6 +235,17 @@ static struct ast_sorcery_wizard test_wizard = {
        .delete = sorcery_test_delete,
 };
 
+static struct ast_sorcery_wizard test_wizard2 = {
+       .name = "test2",
+       .open = sorcery_test_open,
+       .close = sorcery_test_close,
+       .create = sorcery_test_create,
+       .retrieve_id = sorcery_test_retrieve_id,
+       .update = sorcery_test_update,
+       .delete = sorcery_test_delete,
+       .is_stale = sorcery_test_is_stale,
+};
+
 static void sorcery_observer_created(const void *object)
 {
        SCOPED_MUTEX(lock, &observer.lock);
@@ -493,7 +526,7 @@ AST_TEST_DEFINE(apply_config)
                return AST_TEST_NOT_RUN;
        }
 
-       if (!ast_category_get(config, "test_sorcery_section")) {
+       if (!ast_category_get(config, "test_sorcery_section", NULL)) {
                ast_test_status_update(test, "Sorcery configuration file does not have test_sorcery section\n");
                ast_config_destroy(config);
                return AST_TEST_NOT_RUN;
@@ -2200,6 +2233,84 @@ AST_TEST_DEFINE(object_delete_uncreated)
        return AST_TEST_PASS;
 }
 
+AST_TEST_DEFINE(object_is_stale)
+{
+       RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
+       RAII_VAR(struct ast_sorcery_wizard *, wizard1, &test_wizard, ast_sorcery_wizard_unregister);
+       RAII_VAR(struct ast_sorcery_wizard *, wizard2, &test_wizard2, ast_sorcery_wizard_unregister);
+       RAII_VAR(struct test_sorcery_object *, obj1, NULL, ao2_cleanup);
+       RAII_VAR(struct test_sorcery_object *, obj2, NULL, ao2_cleanup);
+
+       switch (cmd) {
+       case TEST_INIT:
+               info->name = "object_is_stale";
+               info->category = "/main/sorcery/";
+               info->summary = "sorcery object staleness unit test";
+               info->description =
+                       "Test whether sorcery will query a wizard correctly if asked\n"
+                       "if an object is stale.";
+               return AST_TEST_NOT_RUN;
+       case TEST_EXECUTE:
+               break;
+       }
+
+       if (ast_sorcery_wizard_register(&test_wizard)) {
+               ast_test_status_update(test, "Failed to register a perfectly valid sorcery wizard\n");
+               return AST_TEST_FAIL;
+       }
+
+       if (ast_sorcery_wizard_register(&test_wizard2)) {
+               ast_test_status_update(test, "Failed to register a perfectly valid sorcery wizard\n");
+               return AST_TEST_FAIL;
+       }
+
+       if (!(sorcery = ast_sorcery_open())) {
+               ast_test_status_update(test, "Failed to open sorcery structure\n");
+               return AST_TEST_FAIL;
+       }
+
+       if ((ast_sorcery_apply_default(sorcery, "test", "test", NULL) != AST_SORCERY_APPLY_SUCCESS) ||
+               ast_sorcery_internal_object_register(sorcery, "test", test_sorcery_object_alloc, NULL, NULL)) {
+               return AST_TEST_FAIL;
+       }
+
+       ast_sorcery_object_field_register_nodoc(sorcery, "test", "bob", "5", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, bob));
+       ast_sorcery_object_field_register_nodoc(sorcery, "test", "joe", "10", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, joe));
+       ast_sorcery_object_field_register_custom_nodoc(sorcery, "test", "jim", "444", jim_handler, NULL, jim_vl, 0, 0);
+       ast_sorcery_object_field_register_custom_nodoc(sorcery, "test", "jack", "888,999", jack_handler, jack_str, NULL, 0, 0);
+
+
+       if ((ast_sorcery_apply_default(sorcery, "test2", "test2", "test2data") != AST_SORCERY_APPLY_SUCCESS) ||
+               ast_sorcery_internal_object_register(sorcery, "test2", test_sorcery_object_alloc, NULL, NULL)) {
+               return AST_TEST_FAIL;
+       }
+
+       ast_sorcery_object_field_register_nodoc(sorcery, "test2", "bob", "5", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, bob));
+       ast_sorcery_object_field_register_nodoc(sorcery, "test2", "joe", "10", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, joe));
+       ast_sorcery_object_field_register_custom_nodoc(sorcery, "test2", "jim", "444", jim_handler, NULL, jim_vl, 0, 0);
+       ast_sorcery_object_field_register_custom_nodoc(sorcery, "test2", "jack", "888,999", jack_handler, jack_str, NULL, 0, 0);
+
+
+       if (!(obj1 = ast_sorcery_alloc(sorcery, "test", "blah"))) {
+               ast_test_status_update(test, "Failed to allocate a known object type\n");
+               return AST_TEST_FAIL;
+       }
+
+       if (!(obj2 = ast_sorcery_alloc(sorcery, "test2", "blah"))) {
+               ast_test_status_update(test, "Failed to allocate a known object type\n");
+               return AST_TEST_FAIL;
+       }
+
+       /* The 'test' wizard has no is_stale callback */
+       ast_test_validate(test, ast_sorcery_is_stale(sorcery, obj1) == 0);
+
+       /* The 'test2' wizard should return stale */
+       ast_test_validate(test, ast_sorcery_is_stale(sorcery, obj2) == 1);
+       ast_test_validate(test, cache.is_stale == 1);
+
+       return AST_TEST_PASS;
+}
+
 AST_TEST_DEFINE(caching_wizard_behavior)
 {
        struct ast_flags flags = { CONFIG_FLAG_NOCACHE };
@@ -2226,7 +2337,7 @@ AST_TEST_DEFINE(caching_wizard_behavior)
                return AST_TEST_NOT_RUN;
        }
 
-       if (!ast_category_get(config, "test_sorcery_cache")) {
+       if (!ast_category_get(config, "test_sorcery_cache", NULL)) {
                ast_test_status_update(test, "Sorcery configuration file does not contain 'test_sorcery_cache' section\n");
                ast_config_destroy(config);
                return AST_TEST_NOT_RUN;
@@ -2995,6 +3106,456 @@ AST_TEST_DEFINE(dialplan_function)
        return AST_TEST_PASS;
 }
 
+AST_TEST_DEFINE(object_field_registered)
+{
+       RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
+       RAII_VAR(struct ast_sorcery_object_type *, object_type, NULL, ao2_cleanup);
+
+       switch (cmd) {
+       case TEST_INIT:
+               info->name = "object_field_registered";
+               info->category = "/main/sorcery/";
+               info->summary = "ast_sorcery_is_object_field_registered unit test";
+               info->description =
+                       "Test ast_sorcery_is_object_field_registered in sorcery";
+               return AST_TEST_NOT_RUN;
+       case TEST_EXECUTE:
+               break;
+       }
+
+       if (!(sorcery = alloc_and_initialize_sorcery())) {
+               ast_test_status_update(test, "Failed to open sorcery structure\n");
+               return AST_TEST_FAIL;
+       }
+
+       object_type = ast_sorcery_get_object_type(sorcery, "test");
+
+       ast_sorcery_object_fields_register(sorcery, "test", "^prefix/.", test_sorcery_regex_handler, test_sorcery_regex_fields);
+
+       ast_test_validate(test, ast_sorcery_is_object_field_registered(object_type, "joe"));
+       ast_test_validate(test, ast_sorcery_is_object_field_registered(object_type, "bob"));
+       ast_test_validate(test, ast_sorcery_is_object_field_registered(object_type, "@joebob"));
+       ast_test_validate(test, ast_sorcery_is_object_field_registered(object_type, "prefix/goober"));
+
+       ast_test_validate(test, !ast_sorcery_is_object_field_registered(object_type, "joebob"));
+       ast_test_validate(test, !ast_sorcery_is_object_field_registered(object_type, "prefix/"));
+       ast_test_validate(test, !ast_sorcery_is_object_field_registered(object_type, "goober"));
+
+       ast_sorcery_object_fields_register(sorcery, "test", "^", test_sorcery_regex_handler, test_sorcery_regex_fields);
+
+       ast_test_validate(test, ast_sorcery_is_object_field_registered(object_type, "goober"));
+
+       return AST_TEST_PASS;
+}
+
+static int event_observed;
+
+static void wizard_observer(const char *name, const struct ast_sorcery_wizard *wizard)
+{
+       if (!strcmp(wizard->name, "test")) {
+               event_observed = 1;
+       }
+}
+
+static void instance_observer(const char *name, struct ast_sorcery *sorcery)
+{
+       if (!strcmp(name, "test_sorcery")) {
+               event_observed = 1;
+       }
+}
+
+AST_TEST_DEFINE(global_observation)
+{
+       RAII_VAR(struct ast_sorcery_wizard *, wizard, &test_wizard, ast_sorcery_wizard_unregister);
+       RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
+       const struct ast_sorcery_global_observer observer = {
+               .wizard_registered = wizard_observer,
+               .instance_created = instance_observer,
+               .wizard_unregistering = wizard_observer,
+               .instance_destroying = instance_observer,
+       };
+
+       switch (cmd) {
+       case TEST_INIT:
+               info->name = "global_observation";
+               info->category = "/main/sorcery/";
+               info->summary = "global sorcery observation test";
+               info->description =
+                       "Test observation of sorcery (global)";
+               return AST_TEST_NOT_RUN;
+       case TEST_EXECUTE:
+               break;
+       }
+
+       ast_sorcery_global_observer_add(&observer);
+
+       event_observed = 0;
+       ast_sorcery_wizard_register(wizard);
+       ast_test_validate(test, (event_observed == 1), "Wizard registered failed");
+
+       event_observed = 0;
+       ast_sorcery_wizard_unregister(wizard);
+       ast_test_validate(test, (event_observed == 1), "Wizard unregistered failed");
+
+       event_observed = 0;
+       sorcery = ast_sorcery_open();
+       ast_test_validate(test, (event_observed == 1), "Instance created failed");
+
+       event_observed = 0;
+       ast_sorcery_unref(sorcery);
+       sorcery = NULL;
+       ast_test_validate(test, (event_observed == 1), "Instance destroyed failed");
+
+       ast_sorcery_global_observer_remove(&observer);
+       event_observed = 0;
+       ast_sorcery_wizard_register(&test_wizard);
+       ast_test_validate(test, (event_observed == 0), "Observer removed failed");
+
+       return AST_TEST_PASS;
+}
+
+static void instance_loaded_observer(const char *name, const struct ast_sorcery *sorcery,
+       int reloaded)
+{
+       if (!strcmp(name, "test_sorcery") && !reloaded) {
+               event_observed++;
+       }
+}
+
+static void instance_reloaded_observer(const char *name,
+       const struct ast_sorcery *sorcery, int reloaded)
+{
+       if (!strcmp(name, "test_sorcery") && reloaded) {
+               event_observed++;
+       }
+}
+
+static void wizard_mapped_observer(const char *name, struct ast_sorcery *sorcery,
+       const char *object_type, struct ast_sorcery_wizard *wizard,
+       const char *wizard_args, void *wizard_data)
+{
+       if (!strcmp(name, "test_sorcery") && !strcmp(object_type, "test_object_type")
+               && !strcmp(wizard->name, "memory") && !strcmp(wizard_args, "memwiz")) {
+               event_observed++;
+       }
+}
+
+static void object_type_registered_observer(const char *name,
+       struct ast_sorcery *sorcery, const char *object_type)
+{
+       if (!strcmp(name, "test_sorcery") && !strcmp(object_type, "test_object_type")) {
+               event_observed++;
+       }
+}
+
+static void object_type_loaded_observer(const char *name,
+       const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
+{
+       if (!strcmp(name, "test_sorcery") && !strcmp(object_type, "test_object_type")
+               && !reloaded) {
+               event_observed++;
+       }
+}
+
+static void object_type_reloaded_observer(const char *name,
+       const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
+{
+       if (!strcmp(name, "test_sorcery") && !strcmp(object_type, "test_object_type")
+               && reloaded) {
+               event_observed++;
+       }
+}
+
+AST_TEST_DEFINE(instance_observation)
+{
+       RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
+       struct ast_sorcery_instance_observer observer = {
+               .wizard_mapped = wizard_mapped_observer,
+               .object_type_registered = object_type_registered_observer,
+       };
+
+       switch (cmd) {
+       case TEST_INIT:
+               info->name = "instance_observation";
+               info->category = "/main/sorcery/";
+               info->summary = "sorcery instance observation test";
+               info->description =
+                       "Test observation of sorcery (instance)";
+               return AST_TEST_NOT_RUN;
+       case TEST_EXECUTE:
+               break;
+       }
+
+       /* Test instance load */
+       if (!(sorcery = ast_sorcery_open())) {
+               ast_test_status_update(test, "Failed to open a sorcery instance\n");
+               return AST_TEST_FAIL;
+       }
+       observer.instance_loading = instance_loaded_observer;
+       observer.instance_loaded = instance_loaded_observer;
+       ast_sorcery_instance_observer_add(sorcery, &observer);
+       event_observed = 0;
+       ast_sorcery_load(sorcery);
+       ast_test_validate(test, (event_observed == 2), "Instance loaded failed");
+       event_observed = 0;
+       ast_sorcery_reload(sorcery);
+       ast_test_validate(test, (event_observed == 0), "Instance reloaded failed");
+
+       /* Test instance reload */
+       ast_sorcery_instance_observer_remove(sorcery, &observer);
+       observer.instance_loading = instance_reloaded_observer;
+       observer.instance_loaded = instance_reloaded_observer;
+       ast_sorcery_instance_observer_add(sorcery, &observer);
+       event_observed = 0;
+       ast_sorcery_load(sorcery);
+       ast_test_validate(test, (event_observed == 0), "Instance loaded failed");
+       event_observed = 0;
+       ast_sorcery_reload(sorcery);
+       ast_test_validate(test, (event_observed == 2), "Instance reloaded failed");
+
+       /* Test wizard mapping */
+       event_observed = 0;
+       ast_sorcery_apply_default(sorcery, "test_object_type", "memory", "memwiz");
+       ast_test_validate(test, (event_observed == 1), "Wizard mapping failed");
+
+       /* Test object type register */
+       event_observed = 0;
+       ast_sorcery_internal_object_register(sorcery, "test_object_type",
+               test_sorcery_object_alloc, NULL, NULL);
+       ast_test_validate(test, (event_observed == 1), "Object type registered failed");
+
+       /* Test object type load */
+       ast_sorcery_instance_observer_remove(sorcery, &observer);
+       observer.object_type_loading = object_type_loaded_observer;
+       observer.object_type_loaded = object_type_loaded_observer;
+       ast_sorcery_instance_observer_add(sorcery, &observer);
+       event_observed = 0;
+       ast_sorcery_load_object(sorcery, "test_object_type");
+       ast_test_validate(test, (event_observed == 2), "Object type loaded failed");
+       event_observed = 0;
+       ast_sorcery_reload_object(sorcery, "test_object_type");
+       ast_test_validate(test, (event_observed == 0), "Object type reloaded failed");
+
+       /* Test object type reload */
+       ast_sorcery_instance_observer_remove(sorcery, &observer);
+       observer.object_type_loading = object_type_reloaded_observer;
+       observer.object_type_loaded = object_type_reloaded_observer;
+       ast_sorcery_instance_observer_add(sorcery, &observer);
+       event_observed = 0;
+       ast_sorcery_load_object(sorcery, "test_object_type");
+       ast_test_validate(test, (event_observed == 0), "Object type loaded failed");
+       event_observed = 0;
+       ast_sorcery_reload_object(sorcery, "test_object_type");
+       ast_test_validate(test, (event_observed == 2), "Object type reloaded failed");
+
+       ast_sorcery_instance_observer_remove(sorcery, &observer);
+       event_observed = 0;
+       ast_sorcery_apply_default(sorcery, "test_object_type", "memory", "memwiz");
+       ast_test_validate(test, (event_observed == 0), "Observer remove failed");
+
+       return AST_TEST_PASS;
+}
+
+static void wizard_loaded_observer(const char *name,
+       const struct ast_sorcery_wizard *wizard, const char *object_type, int reloaded)
+{
+       if (!strcmp(name, "test") && !strcmp(object_type, "test_object_type")
+               && !reloaded) {
+               event_observed++;
+       }
+}
+
+static void sorcery_test_load(void *data, const struct ast_sorcery *sorcery, const char *type)
+{
+       return;
+}
+
+static void wizard_reloaded_observer(const char *name,
+       const struct ast_sorcery_wizard *wizard, const char *object_type, int reloaded)
+{
+       if (!strcmp(name, "test") && !strcmp(object_type, "test_object_type")
+               && reloaded) {
+               event_observed++;
+       }
+}
+
+AST_TEST_DEFINE(wizard_observation)
+{
+       RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
+       RAII_VAR(struct ast_sorcery_wizard *, wizard, &test_wizard, ast_sorcery_wizard_unregister);
+       struct ast_sorcery_wizard_observer observer = {
+               .wizard_loading = wizard_loaded_observer,
+               .wizard_loaded = wizard_loaded_observer,
+       };
+
+       switch (cmd) {
+       case TEST_INIT:
+               info->name = "wizard_observation";
+               info->category = "/main/sorcery/";
+               info->summary = "sorcery wizard observation test";
+               info->description =
+                       "Test observation of sorcery (wizard)";
+               return AST_TEST_NOT_RUN;
+       case TEST_EXECUTE:
+               break;
+       }
+
+       wizard->load = sorcery_test_load;
+       wizard->reload = sorcery_test_load;
+
+       /* Test wizard observer remove and wizard unregister */
+       ast_sorcery_wizard_register(wizard);
+       ast_sorcery_wizard_observer_add(wizard, &observer);
+       ast_sorcery_wizard_observer_remove(wizard, &observer);
+       event_observed = 0;
+       ast_sorcery_wizard_unregister(wizard);
+       ast_test_validate(test, (event_observed == 0), "Wizard observer removed failed");
+
+       /* Setup for test loaded and reloaded */
+       if (!(sorcery = ast_sorcery_open())) {
+               ast_test_status_update(test, "Failed to open a sorcery instance\n");
+               return AST_TEST_FAIL;
+       }
+
+       ast_sorcery_wizard_register(wizard);
+       ast_sorcery_apply_default(sorcery, "test_object_type", "test", NULL);
+       ast_sorcery_internal_object_register(sorcery, "test_object_type",
+               test_sorcery_object_alloc, NULL, NULL);
+
+       /* Test wizard loading and loaded */
+       ast_sorcery_wizard_observer_add(wizard, &observer);
+
+       event_observed = 0;
+       ast_sorcery_load_object(sorcery, "test_object_type");
+       ast_test_validate(test, (event_observed == 2), "Wizard loaded failed");
+
+       event_observed = 0;
+       ast_sorcery_reload_object(sorcery, "test_object_type");
+       ast_sorcery_wizard_observer_remove(wizard, &observer);
+       ast_test_validate(test, (event_observed == 0), "Wizard reloaded failed");
+
+       /* Test wizard reloading and reloaded */
+       observer.wizard_loading = wizard_reloaded_observer;
+       observer.wizard_loaded = wizard_reloaded_observer;
+       ast_sorcery_wizard_observer_add(wizard, &observer);
+
+       event_observed = 0;
+       ast_sorcery_load_object(sorcery, "test_object_type");
+       ast_test_validate(test, (event_observed == 0), "Wizard loaded failed");
+
+       event_observed = 0;
+       ast_sorcery_reload_object(sorcery, "test_object_type");
+       ast_sorcery_wizard_observer_remove(wizard, &observer);
+       ast_test_validate(test, (event_observed == 2), "Wizard reloaded failed");
+
+       return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(wizard_apply_and_insert)
+{
+       RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
+       RAII_VAR(struct ast_sorcery_wizard *, wizard1, &test_wizard, ast_sorcery_wizard_unregister);
+       RAII_VAR(struct ast_sorcery_wizard *, wizard2, &test_wizard2, ast_sorcery_wizard_unregister);
+       RAII_VAR(struct ast_sorcery_wizard *, wizard, NULL, ao2_cleanup);
+       void *data;
+
+       switch (cmd) {
+       case TEST_INIT:
+               info->name = "wizard_apply_and_insert";
+               info->category = "/main/sorcery/";
+               info->summary = "sorcery wizard apply and insert test";
+               info->description =
+                       "sorcery wizard apply and insert test";
+               return AST_TEST_NOT_RUN;
+       case TEST_EXECUTE:
+               break;
+       }
+
+       wizard1->load = sorcery_test_load;
+       wizard1->reload = sorcery_test_load;
+
+       wizard2->load = sorcery_test_load;
+       wizard2->reload = sorcery_test_load;
+
+       if (!(sorcery = ast_sorcery_open())) {
+               ast_test_status_update(test, "Failed to open a sorcery instance\n");
+               return AST_TEST_FAIL;
+       }
+
+       ast_sorcery_wizard_register(wizard1);
+       ast_sorcery_wizard_register(wizard2);
+
+       /* test_object_type isn't registered yet so count should return error */
+       ast_test_validate(test,
+               ast_sorcery_get_wizard_mapping_count(sorcery, "test_object_type") == -1);
+
+       ast_sorcery_apply_default(sorcery, "test_object_type", "test", NULL);
+
+       ast_test_validate(test,
+               ast_sorcery_get_wizard_mapping_count(sorcery, "test_object_type") == 1);
+
+       ast_test_validate(test,
+               ast_sorcery_get_wizard_mapping(sorcery, "test_object_type", 0, &wizard, NULL) == 0);
+       ast_test_validate(test, strcmp("test", wizard->name) == 0);
+       ao2_ref(wizard, -1);
+       wizard = NULL;
+
+       ast_test_validate(test,
+               ast_sorcery_insert_wizard_mapping(sorcery, "test_object_type", "test2", "test2data", 0, 0) == 0);
+
+       ast_test_validate(test,
+               ast_sorcery_insert_wizard_mapping(sorcery, "test_object_type", "test2", "test2data", 0, 0) != 0);
+
+       ast_test_validate(test,
+               ast_sorcery_get_wizard_mapping(sorcery, "test_object_type", 0, &wizard, &data) == 0);
+       ast_test_validate(test, strcmp("test2", wizard->name) == 0);
+       ast_test_validate(test, strcmp("test2data", data) == 0);
+       ao2_ref(wizard, -1);
+       wizard = NULL;
+
+       ast_test_validate(test,
+               ast_sorcery_get_wizard_mapping(sorcery, "test_object_type", 1, &wizard, NULL) == 0);
+       ast_test_validate(test, strcmp("test", wizard->name) == 0);
+       ao2_ref(wizard, -1);
+       wizard = NULL;
+
+       /* Test failures */
+       ast_test_validate(test,
+               ast_sorcery_get_wizard_mapping(sorcery, "non-existent-type", 0, &wizard, NULL) != 0);
+
+       ast_test_validate(test,
+               ast_sorcery_get_wizard_mapping(sorcery, "test_object_type", -1, &wizard, &data) != 0);
+
+       ast_test_validate(test,
+               ast_sorcery_get_wizard_mapping(sorcery, "test_object_type", 2, &wizard, NULL) != 0);
+
+       ast_test_validate(test,
+               ast_sorcery_get_wizard_mapping(sorcery, "test_object_type", 2, NULL, NULL) != 0);
+
+       /* Test remove */
+       /* Should fail */
+       ast_test_validate(test,
+               ast_sorcery_remove_wizard_mapping(sorcery, "non-existent-type", "somewizard") != 0);
+       ast_test_validate(test,
+               ast_sorcery_remove_wizard_mapping(sorcery, "test_object_type", "somewizard") != 0);
+
+       /* should work */
+       ast_test_validate(test,
+               ast_sorcery_remove_wizard_mapping(sorcery, "test_object_type", "test") == 0);
+
+       ast_test_validate(test,
+               ast_sorcery_get_wizard_mapping_count(sorcery, "test_object_type") == 1);
+
+       ast_test_validate(test,
+               ast_sorcery_get_wizard_mapping(sorcery, "test_object_type", 0, &wizard, &data) == 0);
+       ast_test_validate(test, strcmp("test2", wizard->name) == 0);
+       ast_test_validate(test, strcmp("test2data", data) == 0);
+       ao2_ref(wizard, -1);
+       wizard = NULL;
+
+       return AST_TEST_PASS;
+}
+
 static int unload_module(void)
 {
        AST_TEST_UNREGISTER(wizard_registration);
@@ -3032,6 +3593,7 @@ static int unload_module(void)
        AST_TEST_UNREGISTER(object_update_uncreated);
        AST_TEST_UNREGISTER(object_delete);
        AST_TEST_UNREGISTER(object_delete_uncreated);
+       AST_TEST_UNREGISTER(object_is_stale);
        AST_TEST_UNREGISTER(caching_wizard_behavior);
        AST_TEST_UNREGISTER(object_type_observer);
        AST_TEST_UNREGISTER(configuration_file_wizard);
@@ -3041,11 +3603,18 @@ static int unload_module(void)
        AST_TEST_UNREGISTER(configuration_file_wizard_retrieve_multiple);
        AST_TEST_UNREGISTER(configuration_file_wizard_retrieve_multiple_all);
        AST_TEST_UNREGISTER(dialplan_function);
+       AST_TEST_UNREGISTER(object_field_registered);
+       AST_TEST_UNREGISTER(global_observation);
+       AST_TEST_UNREGISTER(instance_observation);
+       AST_TEST_UNREGISTER(wizard_observation);
+       AST_TEST_UNREGISTER(wizard_apply_and_insert);
+
        return 0;
 }
 
 static int load_module(void)
 {
+       AST_TEST_REGISTER(wizard_apply_and_insert);
        AST_TEST_REGISTER(wizard_registration);
        AST_TEST_REGISTER(sorcery_open);
        AST_TEST_REGISTER(apply_default);
@@ -3081,6 +3650,7 @@ static int load_module(void)
        AST_TEST_REGISTER(object_update_uncreated);
        AST_TEST_REGISTER(object_delete);
        AST_TEST_REGISTER(object_delete_uncreated);
+       AST_TEST_REGISTER(object_is_stale);
        AST_TEST_REGISTER(caching_wizard_behavior);
        AST_TEST_REGISTER(object_type_observer);
        AST_TEST_REGISTER(configuration_file_wizard);
@@ -3090,6 +3660,11 @@ static int load_module(void)
        AST_TEST_REGISTER(configuration_file_wizard_retrieve_multiple);
        AST_TEST_REGISTER(configuration_file_wizard_retrieve_multiple_all);
        AST_TEST_REGISTER(dialplan_function);
+       AST_TEST_REGISTER(object_field_registered);
+       AST_TEST_REGISTER(global_observation);
+       AST_TEST_REGISTER(instance_observation);
+       AST_TEST_REGISTER(wizard_observation);
+
        return AST_MODULE_LOAD_SUCCESS;
 }