aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authormmichelson <mmichelson@f38db490-d61c-443f-a65b-d21fe96a405b>2010-02-16 18:29:42 +0000
committermmichelson <mmichelson@f38db490-d61c-443f-a65b-d21fe96a405b>2010-02-16 18:29:42 +0000
commitd3b43c06508c4cf8aa7b497bb7582c557c1bd989 (patch)
tree83b1e4306b2b482357a2ae5eadabd52dfd010fc3 /tests
parent80f73350ff5afa2915b87db3db19425be4dc5ea2 (diff)
Add unit test for dialplan pattern matching.
This test works by reading input from arrays to build a sample dialplan. From there, patterns are attempted to be matched against said dialplan, with the expected match given. We then search in our example dialplan to see if we find a match and if what we find matches what we expected it to match. (closes issue #16809) Reported by: lmadsen Tested by: mmichelson Review: https://reviewboard.asterisk.org/r/504/ git-svn-id: http://svn.digium.com/svn/asterisk/trunk@246942 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'tests')
-rw-r--r--tests/test_pbx.c330
1 files changed, 330 insertions, 0 deletions
diff --git a/tests/test_pbx.c b/tests/test_pbx.c
new file mode 100644
index 000000000..af2375601
--- /dev/null
+++ b/tests/test_pbx.c
@@ -0,0 +1,330 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * Mark Michelson <mmichelson@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief PBX Tests
+ *
+ * \author Mark Michelson <mmichelson@digium.com>
+ *
+ * This module will run some PBX tests.
+ * \ingroup tests
+ */
+
+/*** MODULEINFO
+ <depend>TEST_FRAMEWORK</depend>
+ ***/
+
+#include "asterisk.h"
+#include "asterisk/module.h"
+#include "asterisk/pbx.h"
+#include "asterisk/test.h"
+
+/*!
+ * If we determine that we really need
+ * to be able to register more than 10
+ * priorities for a single extension, then
+ * fine, we can do that later.
+ */
+#define MAX_PRIORITIES 10
+
+/*!
+ * \brief an extension to add to our context
+ */
+struct exten_info {
+ /*!
+ * \brief Context
+ *
+ * \details
+ * The extension specified will be added to
+ * this context when it is created.
+ */
+ const char *context;
+ /*!
+ * \brief Extension pattern
+ *
+ * \details
+ * The extension pattern to use. This can be
+ * anything you would normally find in a dialplan,
+ * such as "1000" or "NXXNXXX" or whatever you
+ * wish it to be. If, however, you want a CID match
+ * to be part of the extension, do not include that
+ * here.
+ */
+ const char *exten;
+ /*!
+ * \brief CID match
+ *
+ * \details
+ * If your extension requires a specific caller ID in
+ * order to match, place that in this field. Note that
+ * a NULL and an empty CID match are two very different
+ * things. If you want no CID match, leave this NULL. If
+ * you want to explicitly match a blank CID, then put
+ * an empty string here.
+ */
+ const char *cid;
+ /*!
+ * \brief Number of priorities
+ *
+ * \details
+ * Tell the number of priorities to register for this
+ * extension. All priorities registered will just have a
+ * Noop application with the extension pattern as its
+ * data.
+ */
+ const int num_priorities;
+ /*!
+ * \brief The priorities to register
+ *
+ * \details
+ * In most cases, when registering multiple priorities for
+ * an extension, we'll be starting at priority 1 and going
+ * sequentially until we've read num_priorities. However,
+ * for some tests, it may be beneficial to start at a higher
+ * priority or skip certain priorities. This is why you have
+ * the freedom here to specify which priorities to register
+ * for the extension.
+ */
+ const int priorities[MAX_PRIORITIES];
+};
+
+struct pbx_test_pattern {
+ /*!
+ * \brief Test context
+ *
+ * \details
+ * This is the context to look in for a specific extension.
+ */
+ const char *context;
+ /*!
+ * \brief Test extension number
+ *
+ * \details
+ * This should be in the form of a specific number or string.
+ * For instance, if you were trying to match an extension defined
+ * with the pattern "_2." you might have as the test_exten one of
+ * "2000" , "2legit2quit" or some other specific match for the pattern.
+ */
+ const char *test_exten;
+ /*!
+ * \brief Test CID match
+ *
+ * \details
+ * If a specific CID match is required for pattern matching, then specify
+ * it in this parameter. Remember that a NULL CID and an empty CID are
+ * interpreted differently. For no CID match, leave this NULL. If you wish
+ * to explicitly match an empty CID, then use an empty string here.
+ */
+ const char *test_cid;
+ /*!
+ * \brief The priority to find
+ */
+ const int priority;
+ /*!
+ * \brief Expected extension match.
+ *
+ * \details
+ * This struct corresponds to an extension that was previously
+ * added to our test context. Once we have used all the above data
+ * to find an extension in the dialplan. We compare the data from that
+ * extension to the data that we have stored in this structure to be
+ * sure that what was matched was what we expected to match.
+ */
+ const struct exten_info *exten;
+};
+
+static int test_exten(const struct pbx_test_pattern *test_pattern, struct ast_test *test)
+{
+ struct pbx_find_info pfi = { { 0 }, };
+ struct ast_exten *exten;
+ if (!(exten = pbx_find_extension(NULL, NULL, &pfi, test_pattern->context,
+ test_pattern->test_exten, test_pattern->priority, NULL,
+ test_pattern->test_cid, E_MATCH))) {
+ ast_test_status_update(test, "Cannot find extension %s in context %s."
+ "Test failed.\n", test_pattern->test_exten, test_pattern->context);
+ return -1;
+ }
+ if (strcmp(ast_get_extension_name(exten), test_pattern->exten->exten)) {
+ ast_test_status_update(test, "Expected extension %s but got extension %s instead."
+ "Test failed.\n", test_pattern->exten->exten, ast_get_extension_name(exten));
+ return -1;
+ }
+ if (test_pattern->test_cid && strcmp(ast_get_extension_cidmatch(exten), test_pattern->test_cid)) {
+ ast_test_status_update(test, "Expected CID match %s but got CID match %s instead."
+ "Test failed.\n", test_pattern->exten->cid, ast_get_extension_cidmatch(exten));
+ return -1;
+ }
+ ast_test_status_update(test, "Successfully matched %s to exten %s in context %s\n",
+ test_pattern->test_exten, test_pattern->exten->exten, test_pattern->context);
+ return 0;
+}
+
+AST_TEST_DEFINE(pattern_match_test)
+{
+ static const char registrar[] = "test_pbx";
+ enum ast_test_result_state res = AST_TEST_PASS;
+ static const char TEST_PATTERN[] = "test_pattern";
+ static const char TEST_PATTERN_INCLUDE[] = "test_pattern_include";
+ int i;
+
+ /* The array of contexts to register for our test.
+ * To add more contexts, just add more rows to this array.
+ */
+ struct {
+ const char * context_string;
+ struct ast_context *context;
+ } contexts[] = {
+ { TEST_PATTERN, },
+ { TEST_PATTERN_INCLUDE, },
+ };
+
+ /*
+ * Map to indicate which contexts should be included inside
+ * other contexts. The first context listed will include
+ * the second context listed.
+ *
+ * To add more inclusions, add new rows to this array.
+ */
+ const struct {
+ const char *outer_context;
+ const char *inner_context;
+ } context_includes[] = {
+ { TEST_PATTERN, TEST_PATTERN_INCLUDE },
+ };
+
+ /* The array of extensions to add to our test context.
+ * For more information about the individual fields, see
+ * the doxygen for struct exten_info.
+ *
+ * To add new extensions to the test, simply add new rows
+ * to this array. All extensions will automatically be
+ * added when the test is run.
+ */
+ const struct exten_info extens[] = {
+ [0] = { TEST_PATTERN, "_2.", NULL, 1, { 1 } },
+ [1] = { TEST_PATTERN, "2000", NULL, 1, { 1 } },
+ [2] = { TEST_PATTERN_INCLUDE, "2000", NULL, 1, { 2 } },
+ };
+
+ /* This array contains our test material. See the doxygen
+ * for struct pbx_test_pattern for more information on each
+ * component.
+ *
+ * To add more test cases, add more lines to this array. Each
+ * case will be tested automatically when the test is run.
+ */
+ const struct pbx_test_pattern tests[] = {
+ { TEST_PATTERN, "200", NULL, 1, &extens[0] },
+ { TEST_PATTERN, "2000", NULL, 1, &extens[1] },
+ { TEST_PATTERN, "2000", NULL, 2, &extens[2] },
+ { TEST_PATTERN_INCLUDE, "2000", NULL, 2, &extens[2] },
+ };
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "pattern_match_test";
+ info->category = "main/pbx/";
+ info->summary = "Test pattern matching";
+ info->description = "Create a context with a bunch of extensions within. Then attempt\n"
+ "to match some strings to the extensions.";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ /* Step one is to build the dialplan.
+ *
+ * We iterate first through the contexts array to build
+ * all the contexts we'll need. Then, we iterate over the
+ * extens array to add all the extensions to the appropriate
+ * contexts.
+ */
+
+ for (i = 0; i < ARRAY_LEN(contexts); ++i) {
+ if (!(contexts[i].context = ast_context_find_or_create(NULL, NULL, contexts[i].context_string, registrar))) {
+ ast_test_status_update(test, "Failed to create context %s\n", contexts[i].context_string);
+ res = AST_TEST_FAIL;
+ goto cleanup;
+ }
+ }
+
+ for (i = 0; i < ARRAY_LEN(context_includes); ++i) {
+ if (ast_context_add_include(context_includes[i].outer_context,
+ context_includes[i].inner_context, registrar)) {
+ ast_test_status_update(test, "Failed to include context %s inside context %s\n",
+ context_includes[i].inner_context, context_includes[i].outer_context);
+ res = AST_TEST_FAIL;
+ goto cleanup;
+ }
+ }
+
+ for (i = 0; i < ARRAY_LEN(extens); ++i) {
+ int priority;
+ if (extens[i].num_priorities > MAX_PRIORITIES) {
+ ast_test_status_update(test, "Invalid number of priorities specified for extension %s."
+ "Max is %d, but we requested %d. Test failed\n",
+ extens[i].exten, MAX_PRIORITIES, extens[i].num_priorities);
+ res = AST_TEST_FAIL;
+ goto cleanup;
+ }
+ for (priority = 0; priority < extens[i].num_priorities; ++priority) {
+ if (ast_add_extension(extens[i].context, 0, extens[i].exten, extens[i].priorities[priority],
+ NULL, extens[i].cid, "Noop", (void *) extens[i].exten, NULL, registrar)) {
+ ast_test_status_update(test, "Failed to add extension %s, priority %d, to context %s."
+ "Test failed\n", extens[i].exten, extens[i].priorities[priority], extens[i].context);
+ res = AST_TEST_FAIL;
+ goto cleanup;
+ }
+ }
+ }
+
+ /* At this stage, the dialplan is built. Now we iterate over
+ * the tests array to attempt to find each of the specified
+ * extensions.
+ */
+ for (i = 0; i < ARRAY_LEN(tests); ++i) {
+ if (test_exten(&tests[i], test)) {
+ res = AST_TEST_FAIL;
+ break;
+ }
+ }
+
+cleanup:
+ for (i = 0; i < ARRAY_LEN(contexts); ++i) {
+ if (contexts[i].context) {
+ ast_context_destroy(contexts[i].context, registrar);
+ }
+ }
+
+ return res;
+}
+
+static int unload_module(void)
+{
+ AST_TEST_UNREGISTER(pattern_match_test);
+ return 0;
+}
+
+static int load_module(void)
+{
+ AST_TEST_REGISTER(pattern_match_test);
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "PBX test module");