summaryrefslogtreecommitdiff
path: root/tests/test_config.c
diff options
context:
space:
mode:
authorMark Michelson <mmichelson@digium.com>2012-06-04 20:26:12 +0000
committerMark Michelson <mmichelson@digium.com>2012-06-04 20:26:12 +0000
commit14a985560ed5830aa3e1b5880890a59a5d0f0c2f (patch)
tree4d6f57c4358566c5508d79e97560640ce59df5c8 /tests/test_config.c
parentc1bbe79748bb1615ab116fe287b8d5d28a83b330 (diff)
Merge changes dealing with support for Digium phones.
Presence support has been added. This is accomplished by allowing for presence hints in addition to device state hints. A dialplan function called PRESENCE_STATE has been added to allow for setting and reading presence. Presence can be transmitted to Digium phones using custom XML elements in a PIDF presence document. Voicemail has new APIs that allow for moving, removing, forwarding, and playing messages. Messages have had a new unique message ID added to them so that the APIs will work reliably. The state of a voicemail mailbox can be obtained using an API that allows one to get a snapshot of the mailbox. A voicemail Dialplan App called VoiceMailPlayMsg has been added to be able to play back a specific message. Configuration hooks have been added. Configuration hooks allow for a piece of code to be executed when a specific configuration file is loaded by a specific module. This is useful for modules that are dependent on the configuration of other modules. chan_sip now has a public method that allows for a custom SIP INFO request to be sent mid-dialog. Digium phones use this in order to display progress bars when files are played. Messaging support has been expanded a bit. The main visible difference is the addition of an AMI action MessageSend. Finally, a ParkingLots manager action has been added in order to get a list of parking lots. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@368435 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'tests/test_config.c')
-rw-r--r--tests/test_config.c359
1 files changed, 350 insertions, 9 deletions
diff --git a/tests/test_config.c b/tests/test_config.c
index c8f7a077b..57d2bbded 100644
--- a/tests/test_config.c
+++ b/tests/test_config.c
@@ -1,9 +1,9 @@
/*
* Asterisk -- An open source telephony toolkit.
*
- * Copyright (C) 2011, Digium, Inc.
+ * Copyright (C) 2010, Digium, Inc.
*
- * Terry Wilson <twilson@digium.com>
+ * Mark Michelson <mmichelson@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
@@ -18,9 +18,9 @@
/*!
* \file
- * \brief Config-related tests
+ * \brief Configuration unit tests
*
- * \author Terry Wilson <twilson@digium.com>
+ * \author Mark Michelson <mmichelson@digium.com>
*
*/
@@ -31,13 +31,14 @@
#include "asterisk.h"
-ASTERISK_FILE_VERSION(__FILE__, "")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
#include <math.h> /* HUGE_VAL */
-#include "asterisk/test.h"
-#include "asterisk/module.h"
#include "asterisk/config.h"
+#include "asterisk/module.h"
+#include "asterisk/test.h"
+#include "asterisk/paths.h"
#include "asterisk/config_options.h"
#include "asterisk/netsock2.h"
#include "asterisk/acl.h"
@@ -45,6 +46,342 @@ ASTERISK_FILE_VERSION(__FILE__, "")
#include "asterisk/utils.h"
#include "asterisk/logger.h"
+#define CONFIG_FILE "test_config.conf"
+
+/*
+ * This builds the folowing config:
+ * [Capitals]
+ * Germany = Berlin
+ * China = Beijing
+ * Canada = Ottawa
+ *
+ * [Protagonists]
+ * 1984 = Winston Smith
+ * Green Eggs And Ham = Sam I Am
+ * The Kalevala = Vainamoinen
+ *
+ * This config is used for all tests below.
+ */
+const char cat1[] = "Capitals";
+const char cat1varname1[] = "Germany";
+const char cat1varvalue1[] = "Berlin";
+const char cat1varname2[] = "China";
+const char cat1varvalue2[] = "Beijing";
+const char cat1varname3[] = "Canada";
+const char cat1varvalue3[] = "Ottawa";
+
+const char cat2[] = "Protagonists";
+const char cat2varname1[] = "1984";
+const char cat2varvalue1[] = "Winston Smith";
+const char cat2varname2[] = "Green Eggs And Ham";
+const char cat2varvalue2[] = "Sam I Am";
+const char cat2varname3[] = "The Kalevala";
+const char cat2varvalue3[] = "Vainamoinen";
+
+struct pair {
+ const char *name;
+ const char *val;
+};
+
+struct association {
+ const char *category;
+ struct pair vars[3];
+} categories [] = {
+ { cat1,
+ {
+ { cat1varname1, cat1varvalue1 },
+ { cat1varname2, cat1varvalue2 },
+ { cat1varname3, cat1varvalue3 },
+ }
+ },
+ { cat2,
+ {
+ { cat2varname1, cat2varvalue1 },
+ { cat2varname2, cat2varvalue2 },
+ { cat2varname3, cat2varvalue3 },
+ }
+ },
+};
+
+/*!
+ * \brief Build ast_config struct from above definitions
+ *
+ * \retval NULL Failed to build the config
+ * \retval non-NULL An ast_config struct populated with data
+ */
+static struct ast_config *build_cfg(void)
+{
+ struct ast_config *cfg;
+ struct association *cat_iter;
+ struct pair *var_iter;
+ size_t i;
+ size_t j;
+
+ cfg = ast_config_new();
+ if (!cfg) {
+ goto fail;
+ }
+
+ for (i = 0; i < ARRAY_LEN(categories); ++i) {
+ struct ast_category *cat;
+ cat_iter = &categories[i];
+
+ cat = ast_category_new(cat_iter->category, "", 999999);
+ if (!cat) {
+ goto fail;
+ }
+ ast_category_append(cfg, cat);
+
+ for (j = 0; j < ARRAY_LEN(cat_iter->vars); ++j) {
+ struct ast_variable *var;
+ var_iter = &cat_iter->vars[j];
+
+ var = ast_variable_new(var_iter->name, var_iter->val, "");
+ if (!var) {
+ goto fail;
+ }
+ ast_variable_append(cat, var);
+ }
+ }
+
+ return cfg;
+
+fail:
+ ast_config_destroy(cfg);
+ return NULL;
+}
+
+/*!
+ * \brief Tests that the contents of an ast_config is what is expected
+ *
+ * \param cfg Config to test
+ * \retval -1 Failed to pass a test
+ * \retval 0 Config passes checks
+ */
+static int test_config_validity(struct ast_config *cfg)
+{
+ int i;
+ const char *cat_iter = NULL;
+ /* Okay, let's see if the correct content is there */
+ for (i = 0; i < ARRAY_LEN(categories); ++i) {
+ struct ast_variable *var = NULL;
+ size_t j;
+ cat_iter = ast_category_browse(cfg, cat_iter);
+ if (strcmp(cat_iter, categories[i].category)) {
+ ast_log(LOG_ERROR, "Category name mismatch, %s does not match %s\n", cat_iter, categories[i].category);
+ return -1;
+ }
+ for (j = 0; j < ARRAY_LEN(categories[i].vars); ++j) {
+ var = var ? var->next : ast_variable_browse(cfg, cat_iter);
+ if (strcmp(var->name, categories[i].vars[j].name)) {
+ ast_log(LOG_ERROR, "Variable name mismatch, %s does not match %s\n", var->name, categories[i].vars[j].name);
+ return -1;
+ }
+ if (strcmp(var->value, categories[i].vars[j].val)) {
+ ast_log(LOG_ERROR, "Variable value mismatch, %s does not match %s\n", var->value, categories[i].vars[j].val);
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+AST_TEST_DEFINE(copy_config)
+{
+ enum ast_test_result_state res = AST_TEST_FAIL;
+ struct ast_config *cfg = NULL;
+ struct ast_config *copy = NULL;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "copy_config";
+ info->category = "/main/config/";
+ info->summary = "Test copying configuration";
+ info->description =
+ "Ensure that variables and categories are copied correctly";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ cfg = build_cfg();
+ if (!cfg) {
+ goto out;
+ }
+
+ copy = ast_config_copy(cfg);
+ if (!copy) {
+ goto out;
+ }
+
+ if (test_config_validity(copy) != 0) {
+ goto out;
+ }
+
+ res = AST_TEST_PASS;
+
+out:
+ ast_config_destroy(cfg);
+ ast_config_destroy(copy);
+ return res;
+}
+
+/*!
+ * \brief Write the config file to disk
+ *
+ * This is necessary for testing config hooks since
+ * they are only triggered when a config is read from
+ * its intended storage medium
+ */
+static int write_config_file(void)
+{
+ int i;
+ FILE *config_file;
+ char filename[PATH_MAX];
+
+ snprintf(filename, sizeof(filename), "%s/%s",
+ ast_config_AST_CONFIG_DIR, CONFIG_FILE);
+ config_file = fopen(filename, "w");
+
+ if (!config_file) {
+ return -1;
+ }
+
+ for (i = 0; i < ARRAY_LEN(categories); ++i) {
+ int j;
+ fprintf(config_file, "[%s]\n", categories[i].category);
+ for (j = 0; j < ARRAY_LEN(categories[i].vars); ++j) {
+ fprintf(config_file, "%s = %s\n",
+ categories[i].vars[j].name,
+ categories[i].vars[j].val);
+ }
+ }
+
+ fclose(config_file);
+ return 0;
+}
+
+/*!
+ * \brief Delete config file created by write_config_file
+ */
+static void delete_config_file(void)
+{
+ char filename[PATH_MAX];
+ snprintf(filename, sizeof(filename), "%s/%s",
+ ast_config_AST_CONFIG_DIR, CONFIG_FILE);
+ unlink(filename);
+}
+
+/*
+ * Boolean to indicate if the config hook has run
+ */
+static int hook_run;
+
+/*
+ * Boolean to indicate if, when the hook runs, the
+ * data passed to it is what is expected
+ */
+static int hook_config_sane;
+
+static int hook_cb(struct ast_config *cfg)
+{
+ hook_run = 1;
+ if (test_config_validity(cfg) == 0) {
+ hook_config_sane = 1;
+ }
+ ast_config_destroy(cfg);
+ return 0;
+}
+
+AST_TEST_DEFINE(config_hook)
+{
+ enum ast_test_result_state res = AST_TEST_FAIL;
+ enum config_hook_flags hook_flags = { 0, };
+ struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED };
+ struct ast_config *cfg;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "config_hook";
+ info->category = "/main/config/";
+ info->summary = "Test config hooks";
+ info->description =
+ "Ensure that config hooks are called at approriate times,"
+ "not called at inappropriate times, and that all information"
+ "that should be present is present.";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ write_config_file();
+
+ /*
+ * Register a config hook to run when CONFIG_FILE is loaded by this module
+ */
+ ast_config_hook_register("test_hook",
+ CONFIG_FILE,
+ AST_MODULE,
+ hook_flags,
+ hook_cb);
+
+ /*
+ * Try loading the config file. This should result in the hook
+ * being called
+ */
+ cfg = ast_config_load(CONFIG_FILE, config_flags);
+ ast_config_destroy(cfg);
+ if (!hook_run || !hook_config_sane) {
+ ast_test_status_update(test, "Config hook either did not run or was given bad data!\n");
+ goto out;
+ }
+
+ /*
+ * Now try loading the wrong config file but from the right module.
+ * Hook should not run
+ */
+ hook_run = 0;
+ cfg = ast_config_load("asterisk.conf", config_flags);
+ ast_config_destroy(cfg);
+ if (hook_run) {
+ ast_test_status_update(test, "Config hook ran even though an incorrect file was specified.\n");
+ goto out;
+ }
+
+ /*
+ * Now try loading the correct config file but from the wrong module.
+ * Hook should not run
+ */
+ hook_run = 0;
+ cfg = ast_config_load2(CONFIG_FILE, "fake_module.so", config_flags);
+ ast_config_destroy(cfg);
+ if (hook_run) {
+ ast_test_status_update(test, "Config hook ran even though an incorrect module was specified.\n");
+ goto out;
+ }
+
+ /*
+ * Now try loading the file correctly, but without any changes to the file.
+ * Hook should not run
+ */
+ hook_run = 0;
+ cfg = ast_config_load(CONFIG_FILE, config_flags);
+ /* Only destroy this cfg conditionally. Otherwise a crash happens. */
+ if (cfg != CONFIG_STATUS_FILEUNCHANGED) {
+ ast_config_destroy(cfg);
+ }
+ if (hook_run) {
+ ast_test_status_update(test, "Config hook ran even though file contents had not changed\n");
+ goto out;
+ }
+
+ res = AST_TEST_PASS;
+
+out:
+ delete_config_file();
+ return res;
+}
+
enum {
EXPECT_FAIL = 0,
EXPECT_SUCCEED,
@@ -278,7 +615,6 @@ AST_TEST_DEFINE(ast_parse_arg_test)
return ret;
}
-
struct test_item {
AST_DECLARE_STRING_FIELDS(
AST_STRING_FIELD(name);
@@ -575,6 +911,8 @@ AST_TEST_DEFINE(config_options_test)
static int unload_module(void)
{
+ AST_TEST_UNREGISTER(copy_config);
+ AST_TEST_UNREGISTER(config_hook);
AST_TEST_UNREGISTER(ast_parse_arg_test);
AST_TEST_UNREGISTER(config_options_test);
return 0;
@@ -582,9 +920,12 @@ static int unload_module(void)
static int load_module(void)
{
+ AST_TEST_REGISTER(copy_config);
+ AST_TEST_REGISTER(config_hook);
AST_TEST_REGISTER(ast_parse_arg_test);
AST_TEST_REGISTER(config_options_test);
return AST_MODULE_LOAD_SUCCESS;
}
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "config test module");
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Config test module");
+