[asterisk-commits] dlee: branch dlee/stasis-http r379129 - in /team/dlee/stasis-http: include/as...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Tue Jan 15 16:28:57 CST 2013
Author: dlee
Date: Tue Jan 15 16:28:53 2013
New Revision: 379129
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=379129
Log:
API unit tests
Added:
team/dlee/stasis-http/res/res_stasis_http.exports.in (with props)
team/dlee/stasis-http/tests/test_stasis_http.c (with props)
Modified:
team/dlee/stasis-http/include/asterisk/stasis_http.h
team/dlee/stasis-http/res/res_stasis_http.c
Modified: team/dlee/stasis-http/include/asterisk/stasis_http.h
URL: http://svnview.digium.com/svn/asterisk/team/dlee/stasis-http/include/asterisk/stasis_http.h?view=diff&rev=379129&r1=379128&r2=379129
==============================================================================
--- team/dlee/stasis-http/include/asterisk/stasis_http.h (original)
+++ team/dlee/stasis-http/include/asterisk/stasis_http.h Tue Jan 15 16:28:53 2013
@@ -78,8 +78,21 @@
};
/*!
- * Handler for the root RESTful resource.
+ * \brief Handler for the root RESTful resource.
*/
struct stasis_rest_handlers *stasis_root_handler(void);
+/*!
+ * \internal
+ * \brief Service function for API declarations. =
+ *
+ * Only call from res_stasis_http and test_stasis_http. Only public to allow
+ * for unit testing.
+ *
+ * \param uri Requested URI.
+ * \param headers HTTP headers.
+ * \param[out] response RESTful HTTP response.
+ */
+void stasis_http_get_api(const char *uri, struct ast_variable *headers, struct stasis_http_response *response);
+
#endif /* _ASTERISK_STASIS_HTTP_H */
Modified: team/dlee/stasis-http/res/res_stasis_http.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/stasis-http/res/res_stasis_http.c?view=diff&rev=379129&r1=379128&r2=379129
==============================================================================
--- team/dlee/stasis-http/res/res_stasis_http.c (original)
+++ team/dlee/stasis-http/res/res_stasis_http.c Tue Jan 15 16:28:53 2013
@@ -68,7 +68,8 @@
/*!
* \internal
* \brief Fill in an OK \a stasis_http_response.
- * \param response Response to fill in.
+ * \param response Response to fill in. This reference is stolen, so just
+ * \ref ast_json_incref if you need to keep a reference to it.
* \param message JSON response.
*/
static void response_ok(struct stasis_http_response *response, struct ast_json *message)
@@ -157,17 +158,19 @@
* \param headers HTTP headers.
* \param[out] response RESTful HTTP response.
*/
-static void stasis_http_get_api(const char *uri, struct ast_variable *headers, struct stasis_http_response *response) {
+void stasis_http_get_api(const char *uri, struct ast_variable *headers, struct stasis_http_response *response) {
RAII_VAR(struct ast_str *, absolute_path_builder, ast_str_create(80), ast_free);
RAII_VAR(char *, absolute_api_dirname, NULL, free);
RAII_VAR(char *, absolute_filename, NULL, free);
- RAII_VAR(struct ast_json *, obj, NULL, ast_json_unref);
+ struct ast_json *obj = NULL;
char *relative_filename = NULL;
struct ast_variable *host = NULL;
struct ast_json_error error = {};
+ ast_log(LOG_DEBUG, "%s(%s)\n", __func__, uri);
+
if (absolute_path_builder == NULL) {
- ast_log(LOG_ERROR, "Allocation failed.");
+ ast_log(LOG_ERROR, "Allocation failed\n");
response_error(response, "Allocation failed", 500, "Internal Server Error");
return;
}
@@ -211,14 +214,14 @@
/* HACKERZ! */
ast_log(LOG_ERROR, "Invalid attempt to access '%s' (not in %s)\n", absolute_filename, absolute_api_dirname);
response_error(response, "Resource not found", 404, "Not Found");
- goto done;
+ return;
}
/* Load resource object from file */
obj = ast_json_load_new_file(absolute_filename, &error);
if (obj == NULL) {
response_error(response, "Yikes! Cannot parse resource", 500, "Internal Server Error");
- goto done;
+ return;
}
/* Update the basePath properly */
@@ -261,10 +264,12 @@
struct ast_variable *headers)
{
RAII_VAR(struct ast_str *, http_headers, ast_str_create(40), ast_free);
- RAII_VAR(struct ast_str *, response_text, ast_str_create(256), ast_free);
+ RAII_VAR(struct ast_str *, response_body, ast_str_create(256), ast_free);
struct stasis_http_response response = {};
-
- if (!http_headers || !out) {
+ int ret;
+
+ if (!http_headers || !response_body) {
+ ast_log(LOG_ERROR, "Allocation failure!\n");
return -1;
}
@@ -286,12 +291,21 @@
ast_assert(response.response_code > 0);
ast_str_set(&http_headers, 0, "Content-type: application/json\r\nAccess-Control-Allow-Origin: *\r\n");
- response_text = ast_json_dump_str(response.message);
-
- ast_http_send(ser, method, response.response_code, response.response_text, http_headers, response_text, 0, 0);
+
+ if (ast_json_dump_str(response.message, &response_body) == 0) {
+ ast_http_send(ser, method, response.response_code, response.response_text, http_headers, response_body, 0, 0);
+ /* ast_http_send takes ownership, so we don't have to free them */
+ http_headers = NULL;
+ response_body = NULL;
+ ret = 0;
+ } else {
+ ast_log(LOG_ERROR, "Failed to encode JSON response\n");
+ ast_http_send(ser, method, 500, "Internal Server Error", http_headers, ast_str_alloca(0), 0, 0);
+ ret = -1;
+ }
ast_json_unref(response.message);
- return 0;
+ return ret;
}
static struct ast_http_uri http_uri = {
@@ -313,7 +327,7 @@
* \return -1 on error.
*/
static int ast_websocket_write_json(struct ast_websocket *session, struct ast_json *message) {
- RAII_VAR(char *str, ast_json_dump_string(message), ast_free);
+ RAII_VAR(char *, str, ast_json_dump_string(message), ast_free);
if (str == NULL) {
ast_log(LOG_ERROR, "Failed to encode JSON object\n");
@@ -399,9 +413,8 @@
return r;
}
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Stasis HTTP bindings",
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Stasis HTTP bindings",
.load = load_module,
.unload = unload_module,
- .load_pri = AST_MODPRI_DEFAULT,
.nonoptreq = "app_stasis,res_http_websocket,res_stasis_core,res_json"
);
Added: team/dlee/stasis-http/res/res_stasis_http.exports.in
URL: http://svnview.digium.com/svn/asterisk/team/dlee/stasis-http/res/res_stasis_http.exports.in?view=auto&rev=379129
==============================================================================
--- team/dlee/stasis-http/res/res_stasis_http.exports.in (added)
+++ team/dlee/stasis-http/res/res_stasis_http.exports.in Tue Jan 15 16:28:53 2013
@@ -1,0 +1,6 @@
+{
+ global:
+ LINKER_SYMBOL_PREFIXstasis_http_get_api;
+ local:
+ *;
+};
Propchange: team/dlee/stasis-http/res/res_stasis_http.exports.in
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/dlee/stasis-http/res/res_stasis_http.exports.in
------------------------------------------------------------------------------
svn:keywords = Author Date Id Rev URL
Propchange: team/dlee/stasis-http/res/res_stasis_http.exports.in
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: team/dlee/stasis-http/tests/test_stasis_http.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/stasis-http/tests/test_stasis_http.c?view=auto&rev=379129
==============================================================================
--- team/dlee/stasis-http/tests/test_stasis_http.c (added)
+++ team/dlee/stasis-http/tests/test_stasis_http.c Tue Jan 15 16:28:53 2013
@@ -1,0 +1,255 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee at 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 Test Stasis HTTP API.
+ * \author\verbatim David M. Lee, II <dlee at digium.com> \endverbatim
+ *
+ * \ingroup tests
+ */
+
+/*** MODULEINFO
+ <depend>TEST_FRAMEWORK</depend>
+ <depend>res_stasis_http</depend>
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/module.h"
+#include "asterisk/test.h"
+#include "asterisk/stasis_http.h"
+
+/*!@{*/
+#if 0
+/*!
+ * These structs and functions define the restful API:
+ * - /foo (GET)
+ * - /foo/bar (GET, POST)
+ * - /foo/{bam} (GET)
+ * - /foo/{bam}/bang (GET, POST, DELETE)
+ */
+
+struct test_received {
+ char *function;
+ struct ast_variable *get_params;
+ struct ast_variable *path_vars;
+ struct ast_variable *headers;
+};
+
+struct test_received test_received = {};
+
+#define HANDLER(name) \
+ static void name(struct ast_variable *get_params, \
+ struct ast_variable *path_vars, \
+ struct ast_variable *headers, \
+ struct stasis_http_response *response) \
+ { \
+ test_received.function = #name; \
+ test_received.get_params = get_params; \
+ test_received.path_vars = path_vars; \
+ test_received.headers = headers; \
+ }
+
+
+HANDLER(bang_get)
+HANDLER(bang_post)
+HANDLER(bang_delete)
+HANDLER(bar_get)
+HANDLER(bar_post)
+HANDLER(bam_get)
+HANDLER(foo_get)
+
+static struct stasis_rest_handlers bang = {
+ .path_segment = "bang",
+ .callbacks = {
+ [AST_HTTP_GET] = bang_get,
+ [AST_HTTP_POST] = bang_post,
+ [AST_HTTP_DELETE] = bang_delete,
+ },
+ .num_children = 0
+};
+static struct stasis_rest_handlers bar = {
+ .path_segment = "bar",
+ .callbacks = {
+ [AST_HTTP_GET] = bar_get,
+ [AST_HTTP_POST] = bar_post,
+ },
+ .num_children = 0
+};
+static struct stasis_rest_handlers bam = {
+ .path_segment = "bam",
+ .is_wildcard = 1,
+ .callbacks = {
+ [AST_HTTP_GET] = bam_get,
+ },
+ .num_children = 1,
+ .children = { &bang }
+};
+static struct stasis_rest_handlers foo = {
+ .path_segment = "foo",
+ .callbacks = {
+ [AST_HTTP_GET] = foo_get,
+ },
+ .num_children = 3,
+ .children = { &bar, &bam, &bang }
+};
+
+#endif // 0
+
+static struct stasis_http_response *response_alloc(void)
+{
+ struct stasis_http_response *ret = ast_calloc(1, sizeof(struct stasis_http_response));
+ return ret;
+}
+
+static void response_free(struct stasis_http_response *resp)
+{
+ ast_json_unref(resp->message);
+ ast_free(resp);
+}
+
+/*!@}*/
+
+AST_TEST_DEFINE(get_api)
+{
+ RAII_VAR(struct stasis_http_response *, response, response_alloc, response_free);
+ RAII_VAR(struct ast_variable *, headers, NULL, ast_variables_destroy);
+ struct ast_json *basePathJson;
+ const char *basePath;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = __func__;
+ info->category = "/stasis/http/";
+ info->summary = "Test simple API get.";
+ info->description = "Test Stasis HTTP binding logic.";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ headers = ast_variable_new("Host", "stasis.asterisk.org", __FILE__);
+ stasis_http_get_api("api/resources.json", headers, response);
+ ast_test_validate(test, 200 == response.response_code);
+
+ /* basePath should be relative to the Host header */
+ basePathJson = ast_json_object_get(response.message, "basePath");
+ ast_test_validate(test, NULL != basePathJson);
+ basePath = ast_json_string_get(basePathJson);
+ ast_test_validate(test, 0 == strcmp("http://stasis.asterisk.org/stasis", basePath));
+
+ return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(get_api_nohost)
+{
+ RAII_VAR(struct stasis_http_response *, response, response_alloc, response_free);
+ struct ast_variable *headers = NULL;
+ struct ast_json *basePathJson;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = __func__;
+ info->category = "/stasis/http/";
+ info->summary = "Test API get without a Host header";
+ info->description = "Test Stasis HTTP binding logic.";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ stasis_http_get_api("api/resources.json", headers, response);
+ ast_test_validate(test, 200 == response.response_code);
+
+ /* basePath should be relative to the Host header */
+ basePathJson = ast_json_object_get(response.message, "basePath");
+ ast_test_validate(test, NULL == basePathJson);
+
+ return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(get_api_notfound)
+{
+ RAII_VAR(struct stasis_http_response *, response, response_alloc, response_free);
+ struct ast_variable *headers = NULL;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = __func__;
+ info->category = "/stasis/http/";
+ info->summary = "Test API get for invalid resource";
+ info->description = "Test Stasis HTTP binding logic.";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ stasis_http_get_api("api/i-am-not-a-resource.json", headers, response);
+ ast_test_validate(test, 404 == response.response_code);
+
+ return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(get_api_hackerz)
+{
+ RAII_VAR(struct stasis_http_response *, response, response_alloc, response_free);
+ struct ast_variable *headers = NULL;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = __func__;
+ info->category = "/stasis/http/";
+ info->summary = "Test API get for a file outside the rest-api path";
+ info->description = "Test Stasis HTTP binding logic.";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ stasis_http_get_api("api/../../../../sbin/asterisk", headers, response);
+ ast_test_validate(test, 404 == response.response_code);
+
+ return AST_TEST_PASS;
+}
+
+static int unload_module(void)
+{
+ AST_TEST_UNREGISTER(get_api);
+ AST_TEST_UNREGISTER(get_api_nohost);
+ AST_TEST_UNREGISTER(get_api_notfound);
+ AST_TEST_UNREGISTER(get_api_hackerz);
+ return 0;
+}
+
+static int load_module(void)
+{
+ AST_TEST_REGISTER(get_api);
+ AST_TEST_REGISTER(get_api_nohost);
+ AST_TEST_REGISTER(get_api_notfound);
+ AST_TEST_REGISTER(get_api_hackerz);
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Stasis HTTP testing",
+ .load = load_module,
+ .unload = unload_module,
+ .nonoptreq = "res_stasis_http"
+ );
Propchange: team/dlee/stasis-http/tests/test_stasis_http.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/dlee/stasis-http/tests/test_stasis_http.c
------------------------------------------------------------------------------
svn:keywords = Author Date Id Rev URL
Propchange: team/dlee/stasis-http/tests/test_stasis_http.c
------------------------------------------------------------------------------
svn:mime-type = text/plain
More information about the asterisk-commits
mailing list