From a2a53cc306ea5fec65daf3630716a7c6ee13adad Mon Sep 17 00:00:00 2001 From: "David M. Lee" Date: Mon, 8 Apr 2013 13:27:45 +0000 Subject: Stasis application WebSocket support This is the API that binds the Stasis dialplan application to external Stasis applications. It also adds the beginnings of WebSocket application support. This module registers a dialplan function named Stasis, which is used to put a channel into the named Stasis app. As a channel enters and leaves the Stasis diaplan application, the Stasis app receives a 'stasis-start' and 'stasis-end' events. Stasis apps register themselves using the stasis_app_register and stasis_app_unregister functions. Messages are sent to an application using stasis_app_send. Finally, Stasis apps control channels through the use of the stasis_app_control object, and the family of stasis_app_control_* functions. Other changes along for the ride are: * An ast_frame_dtor function that's RAII_VAR safe * Some common JSON encoders for name/number, timeval, and context/extension/priority Review: https://reviewboard.asterisk.org/r/2361/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@384879 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- tests/test_abstract_jb.c | 25 ++---- tests/test_app_stasis.c | 194 +++++++++++++++++++++++++++++++++++++++++++++++ tests/test_json.c | 102 +++++++++++++++++++++++++ 3 files changed, 303 insertions(+), 18 deletions(-) create mode 100644 tests/test_app_stasis.c (limited to 'tests') diff --git a/tests/test_abstract_jb.c b/tests/test_abstract_jb.c index f39b0b03b..17861e6bc 100644 --- a/tests/test_abstract_jb.c +++ b/tests/test_abstract_jb.c @@ -67,17 +67,6 @@ static void dispose_jitterbuffer(struct ast_jb *jb) jb->jbobj = NULL; } -/*! \internal \brief Destructor for frames - * \param f The frame to destroy - */ -static void dispose_frame(struct ast_frame *f) -{ - if (!f) { - return; - } - ast_frfree(f); -} - /*! \internal \brief Create a test frame * \param timestamp the time in ms of the frame * \param seqno the frame's sequence number @@ -217,8 +206,8 @@ static struct ast_jb default_jb = { RAII_VAR(struct ast_jb *, jb, &default_jb, dispose_jitterbuffer); \ const struct ast_jb_impl *impl; \ struct ast_jb_conf conf; \ - RAII_VAR(struct ast_frame *, expected_frame, NULL, dispose_frame); \ - RAII_VAR(struct ast_frame *, actual_frame, NULL, dispose_frame); \ + RAII_VAR(struct ast_frame *, expected_frame, NULL, ast_frame_dtor); \ + RAII_VAR(struct ast_frame *, actual_frame, NULL, ast_frame_dtor); \ int res; \ \ switch (cmd) { \ @@ -273,8 +262,8 @@ static struct ast_jb default_jb = { RAII_VAR(struct ast_jb *, jb, &default_jb, dispose_jitterbuffer); \ const struct ast_jb_impl *impl; \ struct ast_jb_conf conf; \ - RAII_VAR(struct ast_frame *, expected_frame, NULL, dispose_frame); \ - RAII_VAR(struct ast_frame *, actual_frame, NULL, dispose_frame); \ + RAII_VAR(struct ast_frame *, expected_frame, NULL, ast_frame_dtor); \ + RAII_VAR(struct ast_frame *, actual_frame, NULL, ast_frame_dtor); \ int res; \ long next; \ int i; \ @@ -336,7 +325,7 @@ static struct ast_jb default_jb = { RAII_VAR(struct ast_jb *, jb, &default_jb, dispose_jitterbuffer); \ const struct ast_jb_impl *impl; \ struct ast_jb_conf conf; \ - RAII_VAR(struct ast_frame *, expected_frame, NULL, dispose_frame); \ + RAII_VAR(struct ast_frame *, expected_frame, NULL, ast_frame_dtor); \ int res; \ int i; \ \ @@ -401,8 +390,8 @@ static struct ast_jb default_jb = { RAII_VAR(struct ast_jb *, jb, &default_jb, dispose_jitterbuffer); \ const struct ast_jb_impl *impl; \ struct ast_jb_conf conf; \ - RAII_VAR(struct ast_frame *, actual_frame, NULL, dispose_frame); \ - RAII_VAR(struct ast_frame *, expected_frame, NULL, dispose_frame); \ + RAII_VAR(struct ast_frame *, actual_frame, NULL, ast_frame_dtor); \ + RAII_VAR(struct ast_frame *, expected_frame, NULL, ast_frame_dtor); \ int res; \ long next; \ int i; \ diff --git a/tests/test_app_stasis.c b/tests/test_app_stasis.c new file mode 100644 index 000000000..02eb85af0 --- /dev/null +++ b/tests/test_app_stasis.c @@ -0,0 +1,194 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2013, Digium, Inc. + * + * David M. Lee, II + * + * 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 Test Stasis Application API. + * \author\verbatim David M. Lee, II \endverbatim + * + * \ingroup tests + */ + +/*** MODULEINFO + TEST_FRAMEWORK + app_stasis + core + ***/ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include "asterisk/module.h" +#include "asterisk/test.h" +#include "asterisk/app_stasis.h" + +static const char *test_category = "/stasis/app/"; + +AST_TEST_DEFINE(app_invoke_dne) +{ + int res; + + switch (cmd) { + case TEST_INIT: + info->name = __func__; + info->category = test_category; + info->summary = "Test stasis app invocation."; + info->description = "Test stasis app invocation."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + res = stasis_app_send("i-am-not-an-app", ast_json_null()); + ast_test_validate(test, -1 == res); + + return AST_TEST_PASS; +} + +struct app_data { + int invocations; + struct ast_json *messages; +}; + +static void app_data_dtor(void *obj) +{ + struct app_data *actual = obj; + + ast_json_unref(actual->messages); + actual->messages = NULL; +} + +static struct app_data *app_data_create(void) +{ + struct app_data *res = ao2_alloc(sizeof(struct app_data), app_data_dtor); + + if (!res) { + return NULL; + } + + res->messages = ast_json_array_create(); + return res; +} + +static void test_handler(void *data, const char *app_name, struct ast_json *message) +{ + struct app_data *actual = data; + int res; + ++(actual->invocations); + res = ast_json_array_append(actual->messages, ast_json_copy(message)); + ast_assert(res == 0); +} + +AST_TEST_DEFINE(app_invoke_one) +{ + RAII_VAR(struct app_data *, app_data, NULL, ao2_cleanup); + RAII_VAR(char *, app_name, NULL, stasis_app_unregister); + RAII_VAR(struct ast_json *, expected_message, NULL, ast_json_unref); + RAII_VAR(struct ast_json *, message, NULL, ast_json_unref); + int res; + + switch (cmd) { + case TEST_INIT: + info->name = __func__; + info->category = test_category; + info->summary = "Test stasis app invocation."; + info->description = "Test stasis app invocation."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + app_name = "test-handler"; + + app_data = app_data_create(); + + stasis_app_register(app_name, test_handler, app_data); + message = ast_json_pack("{ s: o }", "test-message", ast_json_null()); + expected_message = ast_json_pack("[o]", ast_json_ref(message)); + + res = stasis_app_send(app_name, message); + ast_test_validate(test, 0 == res); + ast_test_validate(test, 1 == app_data->invocations); + ast_test_validate(test, ast_json_equal(expected_message, app_data->messages)); + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(app_replaced) +{ + RAII_VAR(struct app_data *, app_data1, NULL, ao2_cleanup); + RAII_VAR(struct app_data *, app_data2, NULL, ao2_cleanup); + RAII_VAR(char *, app_name, NULL, stasis_app_unregister); + RAII_VAR(struct ast_json *, expected_message1, NULL, ast_json_unref); + RAII_VAR(struct ast_json *, message, NULL, ast_json_unref); + RAII_VAR(struct ast_json *, expected_message2, NULL, ast_json_unref); + int res; + + switch (cmd) { + case TEST_INIT: + info->name = __func__; + info->category = test_category; + info->summary = "Test stasis app invocation."; + info->description = "Test stasis app invocation."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + app_name = "test-handler"; + + app_data1 = app_data_create(); + app_data2 = app_data_create(); + + stasis_app_register(app_name, test_handler, app_data1); + stasis_app_register(app_name, test_handler, app_data2); + expected_message1 = ast_json_pack("[{s: {}}]", "application-replaced"); + message = ast_json_pack("{ s: o }", "test-message", ast_json_null()); + expected_message2 = ast_json_pack("[o]", ast_json_ref(message)); + + res = stasis_app_send(app_name, message); + ast_test_validate(test, 0 == res); + ast_test_validate(test, 1 == app_data1->invocations); + ast_test_validate(test, ast_json_equal(expected_message1, app_data1->messages)); + ast_test_validate(test, 1 == app_data2->invocations); + ast_test_validate(test, ast_json_equal(expected_message2, app_data2->messages)); + + return AST_TEST_PASS; +} + +static int unload_module(void) +{ + AST_TEST_UNREGISTER(app_invoke_dne); + AST_TEST_UNREGISTER(app_invoke_one); + AST_TEST_UNREGISTER(app_replaced); + return 0; +} + +static int load_module(void) +{ + AST_TEST_REGISTER(app_replaced); + AST_TEST_REGISTER(app_invoke_one); + AST_TEST_REGISTER(app_invoke_dne); + return AST_MODULE_LOAD_SUCCESS; +} + +AST_MODULE_INFO(ASTERISK_GPL_KEY, 0, "Stasis Core testing", + .load = load_module, + .unload = unload_module, + .nonoptreq = "app_stasis" + ); diff --git a/tests/test_json.c b/tests/test_json.c index 603867279..9b4be5beb 100644 --- a/tests/test_json.c +++ b/tests/test_json.c @@ -1611,6 +1611,102 @@ AST_TEST_DEFINE(json_test_clever_circle) return AST_TEST_PASS; } +AST_TEST_DEFINE(json_test_name_number) +{ + RAII_VAR(void *, alloc_debug, json_test_init(test), json_test_finish); + RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref); + RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref); + + switch (cmd) { + case TEST_INIT: + info->name = "name_number"; + info->category = "/main/json/"; + info->summary = "JSON encoding of name/number pair."; + info->description = "Test JSON abstraction library."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + ast_test_validate(test, NULL == ast_json_name_number("name", NULL)); + ast_test_validate(test, NULL == ast_json_name_number(NULL, "1234")); + ast_test_validate(test, NULL == ast_json_name_number(NULL, NULL)); + + expected = ast_json_pack("{s: s, s: s}", + "name", "Jenny", + "number", "867-5309"); + uut = ast_json_name_number("Jenny", "867-5309"); + ast_test_validate(test, ast_json_equal(expected, uut)); + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(json_test_timeval) +{ + RAII_VAR(void *, alloc_debug, json_test_init(test), json_test_finish); + RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref); + RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref); + struct timeval tv = {}; + + switch (cmd) { + case TEST_INIT: + info->name = "timeval"; + info->category = "/main/json/"; + info->summary = "JSON encoding of timevals."; + info->description = "Test JSON abstraction library."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + ast_test_validate(test, NULL == ast_json_timeval(NULL, NULL)); + expected = ast_json_string_create("2013-02-07T09:32:34.314-0600"); + + tv.tv_sec = 1360251154; + tv.tv_usec = 314159; + uut = ast_json_timeval(&tv, "America/Chicago"); + + ast_test_validate(test, ast_json_equal(expected, uut)); + + return AST_TEST_PASS; +} + +AST_TEST_DEFINE(json_test_cep) +{ + RAII_VAR(void *, alloc_debug, json_test_init(test), json_test_finish); + RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref); + RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref); + + switch (cmd) { + case TEST_INIT: + info->name = "cep"; + info->category = "/main/json/"; + info->summary = "JSON with circular references cannot be encoded."; + info->description = "Test JSON abstraction library."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + expected = ast_json_pack("{s: o, s: o, s: o}", + "context", ast_json_null(), + "exten", ast_json_null(), + "priority", ast_json_null()); + uut = ast_json_dialplan_cep(NULL, NULL, -1); + ast_test_validate(test, ast_json_equal(expected, uut)); + + ast_json_unref(expected); + ast_json_unref(uut); + expected = ast_json_pack("{s: s, s: s, s: i}", + "context", "main", + "exten", "4321", + "priority", 7); + uut = ast_json_dialplan_cep("main", "4321", 7); + ast_test_validate(test, ast_json_equal(expected, uut)); + + return AST_TEST_PASS; +} + static int unload_module(void) { AST_TEST_UNREGISTER(json_test_false); @@ -1661,6 +1757,9 @@ static int unload_module(void) AST_TEST_UNREGISTER(json_test_circular_object); AST_TEST_UNREGISTER(json_test_circular_array); AST_TEST_UNREGISTER(json_test_clever_circle); + AST_TEST_UNREGISTER(json_test_name_number); + AST_TEST_UNREGISTER(json_test_timeval); + AST_TEST_UNREGISTER(json_test_cep); return 0; } @@ -1714,6 +1813,9 @@ static int load_module(void) AST_TEST_REGISTER(json_test_circular_object); AST_TEST_REGISTER(json_test_circular_array); AST_TEST_REGISTER(json_test_clever_circle); + AST_TEST_REGISTER(json_test_name_number); + AST_TEST_REGISTER(json_test_timeval); + AST_TEST_REGISTER(json_test_cep); return AST_MODULE_LOAD_SUCCESS; } -- cgit v1.2.3