diff options
author | Mark Michelson <mmichelson@digium.com> | 2012-06-04 20:26:12 +0000 |
---|---|---|
committer | Mark Michelson <mmichelson@digium.com> | 2012-06-04 20:26:12 +0000 |
commit | 14a985560ed5830aa3e1b5880890a59a5d0f0c2f (patch) | |
tree | 4d6f57c4358566c5508d79e97560640ce59df5c8 /tests/test_config.c | |
parent | c1bbe79748bb1615ab116fe287b8d5d28a83b330 (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.c | 359 |
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"); + |