Asterisk - The Open Source Telephony Project  21.4.1
test_aeap.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2021, Sangoma Technologies Corporation
5  *
6  * Kevin Harwell <kharwell@sangoma.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*** MODULEINFO
20  <depend>TEST_FRAMEWORK</depend>
21  <depend>res_aeap</depend>
22  <support_level>core</support_level>
23  ***/
24 
25 #include "asterisk.h"
26 
27 #include "asterisk/test.h"
28 #include "asterisk/module.h"
29 #include "asterisk/file.h"
31 #include "asterisk/json.h"
32 
33 #include "asterisk/res_aeap.h"
35 
36 #define CATEGORY "/res/aeap/"
37 
38 #define ADDR "127.0.0.1:8088"
39 #define AEAP_TRANSPORT_TYPE "ws"
40 #define AEAP_REMOTE_URL "ws://" ADDR "/ws"
41 #define AEAP_REMOTE_PROTOCOL "echo"
42 #define AEAP_MESSAGE_ID "foo"
43 #define AEAP_CONNECTION_TIMEOUT 2000
44 
45 AST_TEST_DEFINE(create_and_connect)
46 {
47  RAII_VAR(struct ast_aeap *, aeap, NULL, ao2_cleanup);
48 
49  switch (cmd) {
50  case TEST_INIT:
51  info->name = __func__;
52  info->explicit_only = 0;
53  info->category = CATEGORY;
54  info->summary = "test creating and connecting to an AEAP application";
55  info->description = info->summary;
56  return AST_TEST_NOT_RUN;
57  case TEST_EXECUTE:
58  break;
59  }
60 
61  ast_test_validate(test, (aeap = ast_aeap_create_and_connect(AEAP_TRANSPORT_TYPE,
62  NULL, AEAP_REMOTE_URL, AEAP_REMOTE_PROTOCOL, AEAP_CONNECTION_TIMEOUT)));
63 
64  return AST_TEST_PASS;
65 }
66 
67 static void handle_string(struct ast_aeap *aeap, const char *buf, intmax_t size)
68 {
69  int *passed = ast_aeap_user_data_object_by_id(aeap, AEAP_MESSAGE_ID);
70 
71  if (strstr(buf, AEAP_MESSAGE_ID)) {
72  ++*passed;
73  }
74 }
75 
76 static void handle_timeout(struct ast_aeap *aeap, struct ast_aeap_message *message, void *data)
77 {
78  int *passed = ast_aeap_user_data_object_by_id(aeap, AEAP_MESSAGE_ID);
79 
80  ++*passed;
81 }
82 
83 AST_TEST_DEFINE(send_msg_handle_string)
84 {
85  int passed = 0;
86  RAII_VAR(struct ast_aeap *, aeap, NULL, ao2_cleanup);
87  struct ast_aeap_tsx_params tsx_params = {0};
88  struct ast_aeap_params aeap_params = {
89  .on_string = handle_string,
90  };
91 
92  switch (cmd) {
93  case TEST_INIT:
94  info->name = __func__;
95  info->explicit_only = 0;
96  info->category = CATEGORY;
97  info->summary = "test an AEAP application string handler";
98  info->description = info->summary;
99  return AST_TEST_NOT_RUN;
100  case TEST_EXECUTE:
101  break;
102  }
103 
104  tsx_params.timeout = 2000; /* Test will end by timing out */
105  tsx_params.on_timeout = handle_timeout;
106  tsx_params.wait = 1;
107 
108  ast_test_validate(test, (aeap = ast_aeap_create_and_connect(AEAP_TRANSPORT_TYPE,
109  &aeap_params, AEAP_REMOTE_URL, AEAP_REMOTE_PROTOCOL, AEAP_CONNECTION_TIMEOUT)));
110 
111  ast_test_validate(test, (!ast_aeap_user_data_register(aeap, AEAP_MESSAGE_ID, &passed, NULL)));
112  ast_test_validate(test, (tsx_params.msg = ast_aeap_message_create_request(
113  ast_aeap_message_type_json, "foo", AEAP_MESSAGE_ID, NULL)));
114  ast_test_validate(test, ast_aeap_send_msg_tsx(aeap, &tsx_params)); /* Returns fail on timeout */
115  ast_aeap_user_data_unregister(aeap, AEAP_MESSAGE_ID);
116 
117  return passed == 2 ? AST_TEST_PASS : AST_TEST_FAIL;
118 }
119 
120 static int handle_msg(struct ast_aeap *aeap, struct ast_aeap_message *message, void *data)
121 {
122  int *passed = ast_aeap_user_data_object_by_id(aeap, AEAP_MESSAGE_ID);
123 
124  *passed = !strcmp(ast_aeap_message_id(message), AEAP_MESSAGE_ID) &&
125  ast_aeap_message_is_named(message, data);
126 
127  if (!*passed) {
128  ast_log(LOG_ERROR, "Name '%s' did not equal '%s' for message '%s'",
129  ast_aeap_message_name(message), (char *)data, ast_aeap_message_id(message));
130  }
131 
132  return 0;
133 }
134 
135 static const struct ast_aeap_message_handler handlers[] = {
136  { "foo", handle_msg },
137 };
138 
139 AST_TEST_DEFINE(send_msg_handle_response)
140 {
141  int passed = 0;
142  RAII_VAR(struct ast_aeap *, aeap, NULL, ao2_cleanup);
143  char *name = "foo";
144  struct ast_aeap_params aeap_params = {
145  .response_handlers = handlers,
146  .response_handlers_size = ARRAY_LEN(handlers),
147  };
148  struct ast_aeap_tsx_params tsx_params = {0};
149 
150  switch (cmd) {
151  case TEST_INIT:
152  info->name = __func__;
153  info->explicit_only = 0;
154  info->category = CATEGORY;
155  info->summary = "test an AEAP application response handler";
156  info->description = info->summary;
157  return AST_TEST_NOT_RUN;
158  case TEST_EXECUTE:
159  break;
160  }
161 
162  aeap_params.msg_type = ast_aeap_message_type_json;
163 
164  tsx_params.timeout = 2000;
165  tsx_params.wait = 1;
166  tsx_params.obj = name;
167 
168  ast_test_validate(test, (aeap = ast_aeap_create_and_connect(AEAP_TRANSPORT_TYPE,
169  &aeap_params, AEAP_REMOTE_URL, AEAP_REMOTE_PROTOCOL, AEAP_CONNECTION_TIMEOUT)));
170  ast_test_validate(test, (!ast_aeap_user_data_register(aeap, AEAP_MESSAGE_ID, &passed, NULL)));
171  ast_test_validate(test, (tsx_params.msg = ast_aeap_message_create_response(
172  ast_aeap_message_type_json, name, AEAP_MESSAGE_ID, NULL)));
173  ast_test_validate(test, !ast_aeap_send_msg_tsx(aeap, &tsx_params));
174  ast_aeap_user_data_unregister(aeap, AEAP_MESSAGE_ID);
175 
176  return passed ? AST_TEST_PASS : AST_TEST_FAIL;
177 }
178 
179 AST_TEST_DEFINE(send_msg_handle_request)
180 {
181  int passed = 0;
182  RAII_VAR(struct ast_aeap *, aeap, NULL, ao2_cleanup);
183  char *name = "foo";
184  struct ast_aeap_params aeap_params = {
185  .request_handlers = handlers,
186  .request_handlers_size = ARRAY_LEN(handlers),
187  };
188  struct ast_aeap_tsx_params tsx_params = {0};
189 
190  switch (cmd) {
191  case TEST_INIT:
192  info->name = __func__;
193  info->explicit_only = 0;
194  info->category = CATEGORY;
195  info->summary = "test an AEAP application request handler";
196  info->description = info->summary;
197  return AST_TEST_NOT_RUN;
198  case TEST_EXECUTE:
199  break;
200  }
201 
202  aeap_params.msg_type = ast_aeap_message_type_json;
203 
204  tsx_params.timeout = 2000;
205  tsx_params.wait = 1;
206  tsx_params.obj = name;
207 
208  ast_test_validate(test, (aeap = ast_aeap_create_and_connect(AEAP_TRANSPORT_TYPE,
209  &aeap_params, AEAP_REMOTE_URL, AEAP_REMOTE_PROTOCOL, AEAP_CONNECTION_TIMEOUT)));
210  ast_test_validate(test, (!ast_aeap_user_data_register(aeap, AEAP_MESSAGE_ID, &passed, NULL)));
211  ast_test_validate(test, (tsx_params.msg = ast_aeap_message_create_request(
212  ast_aeap_message_type_json, name, AEAP_MESSAGE_ID, NULL)));
213  ast_test_validate(test, !ast_aeap_send_msg_tsx(aeap, &tsx_params));
214  ast_aeap_user_data_unregister(aeap, AEAP_MESSAGE_ID);
215 
216  return passed ? AST_TEST_PASS : AST_TEST_FAIL;
217 }
218 
219 static struct ast_http_server *http_server;
220 
221 static int load_module(void)
222 {
223  if (!(http_server = ast_http_test_server_get("aeap transport http server", NULL))) {
225  }
226 
227  AST_TEST_REGISTER(create_and_connect);
228  AST_TEST_REGISTER(send_msg_handle_string);
229  AST_TEST_REGISTER(send_msg_handle_response);
230  AST_TEST_REGISTER(send_msg_handle_request);
231 
233 }
234 
235 static int unload_module(void)
236 {
237  AST_TEST_UNREGISTER(send_msg_handle_request);
238  AST_TEST_UNREGISTER(send_msg_handle_response);
239  AST_TEST_UNREGISTER(send_msg_handle_string);
240  AST_TEST_UNREGISTER(create_and_connect);
241 
242  ast_http_test_server_discard(http_server);
243 
244  return 0;
245 }
246 
247 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Asterisk External Application Protocol Object Tests",
248  .support_level = AST_MODULE_SUPPORT_CORE,
249  .load = load_module,
250  .unload = unload_module,
251  .requires = "res_aeap",
252 );
Asterisk External Application Protocol API.
Callbacks and other parameters used by an Asterisk external application object.
Definition: res_aeap.h:144
void ast_aeap_user_data_unregister(struct ast_aeap *aeap, const char *id)
Un-register a user data object.
Definition: aeap.c:169
Asterisk main include file. File version handling, generic pbx functions.
void(* on_string)(struct ast_aeap *aeap, const char *buf, intmax_t size)
Raised when string data is received.
Definition: res_aeap.h:180
Asterisk External Application Protocol Message API.
const struct ast_aeap_message_handler * request_handlers
Definition: res_aeap.h:160
int ast_aeap_message_is_named(const struct ast_aeap_message *message, const char *name)
Check whether or not a message's name matches the given one.
Test Framework API.
const struct ast_aeap_message_type * msg_type
Definition: res_aeap.h:152
int ast_aeap_send_msg_tsx(struct ast_aeap *aeap, struct ast_aeap_tsx_params *params)
Send a transaction based message to an external application using the given parameters.
Definition: aeap.c:464
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
void * ast_aeap_user_data_object_by_id(struct ast_aeap *aeap, const char *id)
Retrieve a registered user data object by its id.
Definition: aeap.c:174
Parameters to be used when sending a transaction based message.
Definition: res_aeap.h:331
const char * ast_aeap_message_id(const struct ast_aeap_message *message)
Retrieve a message id.
#define CATEGORY
Asterisk JSON abstraction layer.
ast_aeap_on_timeout on_timeout
Definition: res_aeap.h:337
const char * ast_aeap_message_name(const struct ast_aeap_message *message)
Retrieve a message name.
Support for WebSocket connections within the Asterisk HTTP server and client WebSocket connections to...
struct ast_aeap * ast_aeap_create_and_connect(const char *type, const struct ast_aeap_params *params, const char *url, const char *protocol, int timeout)
Create and connect to an Asterisk external application.
Definition: aeap.c:363
int ast_aeap_user_data_register(struct ast_aeap *aeap, const char *id, void *obj, ast_aeap_user_obj_cleanup cleanup)
Register a user data object.
Definition: aeap.c:150
struct ast_aeap_message * ast_aeap_message_create_response(const struct ast_aeap_message_type *type, const char *name, const char *id, const void *params)
Create an Asterisk external application response object.
Asterisk external application base message.
An Asterisk external application message handler.
Definition: res_aeap.h:108
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
struct ast_aeap_message * msg
Definition: res_aeap.h:333
#define AST_TEST_DEFINE(hdr)
Definition: test.h:126
const struct ast_aeap_message_handler * response_handlers
Definition: res_aeap.h:155
struct ast_aeap_message * ast_aeap_message_create_request(const struct ast_aeap_message_type *type, const char *name, const char *id, const void *params)
Create an Asterisk external application request object.
const struct ast_aeap_message_type * ast_aeap_message_type_json
Asterisk external application JSON message type.
Definition: message_json.c:191
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
Definition: aeap.c:47