mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-13 00:04:53 +00:00
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
This commit is contained in:
@@ -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");
|
||||
|
||||
|
1443
tests/test_voicemail_api.c
Normal file
1443
tests/test_voicemail_api.c
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user