Asterisk - The Open Source Telephony Project GIT-master-f36a736
Functions | Variables
res_stasis_test.c File Reference

Test infrastructure for dealing with Stasis. More...

#include "asterisk.h"
#include "asterisk/astobj2.h"
#include "asterisk/module.h"
#include "asterisk/stasis_test.h"
Include dependency graph for res_stasis_test.c:

Go to the source code of this file.

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static int load_module (void)
 
static struct timespec make_deadline (int timeout_millis)
 
static void message_sink_cb (void *data, struct stasis_subscription *sub, struct stasis_message *message)
 Implementation of the stasis_message_sink_cb() callback. More...
 
stasis_subscription_cb stasis_message_sink_cb (void)
 Topic callback to receive messages. More...
 
struct stasis_message_sinkstasis_message_sink_create (void)
 Create a message sink. More...
 
static void stasis_message_sink_dtor (void *obj)
 
int stasis_message_sink_should_stay (struct stasis_message_sink *sink, int num_messages, int timeout_millis)
 Ensures that no new messages are received. More...
 
int stasis_message_sink_wait_for (struct stasis_message_sink *sink, int start, stasis_wait_cb cmp_cb, const void *data, int timeout_millis)
 Wait for a message that matches the given criteria. More...
 
int stasis_message_sink_wait_for_count (struct stasis_message_sink *sink, int num_messages, int timeout_millis)
 Wait for a sink's num_messages field to reach a certain level. More...
 
 STASIS_MESSAGE_TYPE_DEFN (stasis_test_message_type)
 
struct stasis_messagestasis_test_message_create (void)
 Creates a test message. More...
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "Stasis test utilities" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, }
 
static const struct ast_module_infoast_module_info = &__mod_info
 

Detailed Description

Test infrastructure for dealing with Stasis.

Author
David M. Lee, II dlee@.nosp@m.digi.nosp@m.um.co.nosp@m.m

Definition in file res_stasis_test.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 273 of file res_stasis_test.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 273 of file res_stasis_test.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 273 of file res_stasis_test.c.

◆ load_module()

static int load_module ( void  )
static

Definition at line 259 of file res_stasis_test.c.

260{
263 }
264
266}
struct stasis_message_type * stasis_test_message_type(void)
Gets the type of messages created by stasis_test_message_create().
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition: stasis.h:1493

References AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, STASIS_MESSAGE_TYPE_INIT, and stasis_test_message_type().

◆ make_deadline()

static struct timespec make_deadline ( int  timeout_millis)
static

Definition at line 63 of file res_stasis_test.c.

64{
65 struct timeval start = ast_tvnow();
66 struct timeval delta = {
67 .tv_sec = timeout_millis / 1000,
68 .tv_usec = (timeout_millis % 1000) * 1000,
69 };
70 struct timeval deadline_tv = ast_tvadd(start, delta);
71 struct timespec deadline = {
72 .tv_sec = deadline_tv.tv_sec,
73 .tv_nsec = 1000 * deadline_tv.tv_usec,
74 };
75
76 return deadline;
77}
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition: extconf.c:2282
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159

References ast_tvadd(), and ast_tvnow().

Referenced by stasis_message_sink_should_stay(), stasis_message_sink_wait_for(), and stasis_message_sink_wait_for_count().

◆ message_sink_cb()

static void message_sink_cb ( void *  data,
struct stasis_subscription sub,
struct stasis_message message 
)
static

Implementation of the stasis_message_sink_cb() callback.

Why the roundabout way of exposing this via stasis_message_sink_cb()? Well, it has to do with how we previously loaded modules, using RTLD_LAZY.

The stasis_message_sink_cb() function gave us a layer of indirection so that the initial lazy binding would still work as expected.

Definition at line 108 of file res_stasis_test.c.

110{
111 struct stasis_message_sink *sink = data;
112
113 SCOPED_MUTEX(lock, &sink->lock);
114
116 sink->is_done = 1;
117 ast_cond_signal(&sink->cond);
118 return;
119 }
120
122 /* Ignore subscription changes */
123 return;
124 }
125
126 if (sink->num_messages == sink->max_messages) {
127 size_t new_max_messages = sink->max_messages * 2;
128 struct stasis_message **new_messages = ast_realloc(
129 sink->messages,
130 sizeof(*new_messages) * new_max_messages);
131 if (!new_messages) {
132 return;
133 }
134 sink->max_messages = new_max_messages;
135 sink->messages = new_messages;
136 }
137
138 ao2_ref(message, +1);
139 sink->messages[sink->num_messages++] = message;
140 ast_cond_signal(&sink->cond);
141}
ast_mutex_t lock
Definition: app_sla.c:331
#define ast_realloc(p, len)
A wrapper for realloc()
Definition: astmm.h:226
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
struct stasis_message_type * stasis_subscription_change_type(void)
Gets the message type for subscription change notices.
#define SCOPED_MUTEX(varname, lock)
scoped lock specialization for mutexes
Definition: lock.h:589
#define ast_cond_signal(cond)
Definition: lock.h:203
struct stasis_forward * sub
Definition: res_corosync.c:240
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
int stasis_subscription_final_message(struct stasis_subscription *sub, struct stasis_message *msg)
Determine whether a message is the final message to be received on a subscription.
Definition: stasis.c:1175
Structure that collects messages from a topic.
Definition: stasis_test.h:44
struct stasis_message ** messages
Definition: stasis_test.h:57
ast_mutex_t lock
Definition: stasis_test.h:46

References ao2_ref, ast_cond_signal, ast_realloc, stasis_message_sink::cond, stasis_message_sink::is_done, lock, stasis_message_sink::lock, stasis_message_sink::max_messages, stasis_message_sink::messages, stasis_message_sink::num_messages, SCOPED_MUTEX, stasis_message_type(), stasis_subscription_change_type(), stasis_subscription_final_message(), and sub.

Referenced by stasis_message_sink_cb().

◆ stasis_message_sink_cb()

stasis_subscription_cb stasis_message_sink_cb ( void  )

Topic callback to receive messages.

We return a function pointer instead of simply exposing the function because of the vagaries of dlopen(), RTLD_LAZY, and function pointers. See the comment on the implementation for details why.

Returns
Function pointer to stasis_message_sink's message handling function

Definition at line 143 of file res_stasis_test.c.

144{
145 return message_sink_cb;
146}
static void message_sink_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Implementation of the stasis_message_sink_cb() callback.

References message_sink_cb().

Referenced by AST_TEST_DEFINE().

◆ stasis_message_sink_create()

struct stasis_message_sink * stasis_message_sink_create ( void  )

Create a message sink.

This is an AO2 managed object, which you ao2_cleanup() when done. The destructor waits for an unsubscribe message to be received, to ensure the object isn't disposed of before the topic is finished.

Definition at line 79 of file res_stasis_test.c.

80{
82
83 sink = ao2_alloc(sizeof(*sink), stasis_message_sink_dtor);
84 if (!sink) {
85 return NULL;
86 }
87 ast_mutex_init(&sink->lock);
88 ast_cond_init(&sink->cond, NULL);
89 sink->max_messages = 4;
90 sink->messages =
91 ast_malloc(sizeof(*sink->messages) * sink->max_messages);
92 if (!sink->messages) {
93 return NULL;
94 }
95 ao2_ref(sink, +1);
96 return sink;
97}
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
#define ast_cond_init(cond, attr)
Definition: lock.h:201
#define ast_mutex_init(pmutex)
Definition: lock.h:186
static void stasis_message_sink_dtor(void *obj)
#define NULL
Definition: resample.c:96
#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

References ao2_alloc, ao2_cleanup, ao2_ref, ast_cond_init, ast_malloc, ast_mutex_init, NULL, RAII_VAR, and stasis_message_sink_dtor().

Referenced by AST_TEST_DEFINE().

◆ stasis_message_sink_dtor()

static void stasis_message_sink_dtor ( void *  obj)
static

Definition at line 39 of file res_stasis_test.c.

40{
41 struct stasis_message_sink *sink = obj;
42
43 {
44 SCOPED_MUTEX(lock, &sink->lock);
45 while (!sink->is_done) {
46 /* Normally waiting forever is bad, but if we're not
47 * done, we're not done. */
48 ast_cond_wait(&sink->cond, &sink->lock);
49 }
50 }
51
52 ast_mutex_destroy(&sink->lock);
53 ast_cond_destroy(&sink->cond);
54
55 while (sink->num_messages > 0) {
56 ao2_cleanup(sink->messages[--sink->num_messages]);
57 }
58 ast_free(sink->messages);
59 sink->messages = NULL;
60 sink->max_messages = 0;
61}
#define ast_free(a)
Definition: astmm.h:180
#define ast_cond_destroy(cond)
Definition: lock.h:202
#define ast_cond_wait(cond, mutex)
Definition: lock.h:205
#define ast_mutex_destroy(a)
Definition: lock.h:188

References ao2_cleanup, ast_cond_destroy, ast_cond_wait, ast_free, ast_mutex_destroy, stasis_message_sink::cond, stasis_message_sink::is_done, lock, stasis_message_sink::lock, stasis_message_sink::max_messages, stasis_message_sink::messages, NULL, stasis_message_sink::num_messages, and SCOPED_MUTEX.

Referenced by stasis_message_sink_create().

◆ stasis_message_sink_should_stay()

int stasis_message_sink_should_stay ( struct stasis_message_sink sink,
int  num_messages,
int  timeout_millis 
)

Ensures that no new messages are received.

The optional timeout prevents complete deadlock in a test.

Parameters
sinkSink to wait on.
num_messagesexpecte sink->num_messages.
timeout_millisNumber of milliseconds to wait for.
Returns
Actual sink->num_messages value at return. If this is < num_messages, then the timeout expired.

Definition at line 170 of file res_stasis_test.c.

172{
173 struct timespec deadline = make_deadline(timeout_millis);
174
175 SCOPED_MUTEX(lock, &sink->lock);
176 while (sink->num_messages == num_messages) {
177 int r = ast_cond_timedwait(&sink->cond, &sink->lock, &deadline);
178
179 if (r == ETIMEDOUT) {
180 break;
181 }
182 if (r != 0) {
183 ast_log(LOG_ERROR, "Unexpected condition error: %s\n",
184 strerror(r));
185 break;
186 }
187 }
188 return sink->num_messages;
189}
#define ast_log
Definition: astobj2.c:42
#define LOG_ERROR
#define ast_cond_timedwait(cond, mutex, time)
Definition: lock.h:206
static struct timespec make_deadline(int timeout_millis)

References ast_cond_timedwait, ast_log, stasis_message_sink::cond, lock, stasis_message_sink::lock, LOG_ERROR, make_deadline(), stasis_message_sink::num_messages, and SCOPED_MUTEX.

◆ stasis_message_sink_wait_for()

int stasis_message_sink_wait_for ( struct stasis_message_sink sink,
int  start,
stasis_wait_cb  cmp_cb,
const void *  data,
int  timeout_millis 
)

Wait for a message that matches the given criteria.

Parameters
sinkSink to wait on.
startIndex of message to start with.
cmp_cbcomparison function. This returns true (non-zero) on match and false (zero) on match.
data
timeout_millisNumber of milliseconds to wait.
Returns
Index of the matching message.
Negative for no match.

Definition at line 191 of file res_stasis_test.c.

193{
194 struct timespec deadline = make_deadline(timeout_millis);
195
196 SCOPED_MUTEX(lock, &sink->lock);
197
198 /* wait for the start */
199 while (sink->num_messages < start + 1) {
200 int r = ast_cond_timedwait(&sink->cond, &sink->lock, &deadline);
201
202 if (r == ETIMEDOUT) {
203 /* Timed out waiting for the start */
204 return -1;
205 }
206 if (r != 0) {
207 ast_log(LOG_ERROR, "Unexpected condition error: %s\n",
208 strerror(r));
209 return -2;
210 }
211 }
212
213
214 while (!cmp_cb(sink->messages[start], data)) {
215 ++start;
216
217 while (sink->num_messages < start + 1) {
218 int r = ast_cond_timedwait(&sink->cond,
219 &sink->lock, &deadline);
220
221 if (r == ETIMEDOUT) {
222 return -1;
223 }
224 if (r != 0) {
226 "Unexpected condition error: %s\n",
227 strerror(r));
228 return -2;
229 }
230 }
231 }
232
233 return start;
234}

References ast_cond_timedwait, ast_log, stasis_message_sink::cond, lock, stasis_message_sink::lock, LOG_ERROR, make_deadline(), stasis_message_sink::messages, stasis_message_sink::num_messages, and SCOPED_MUTEX.

Referenced by AST_TEST_DEFINE().

◆ stasis_message_sink_wait_for_count()

int stasis_message_sink_wait_for_count ( struct stasis_message_sink sink,
int  num_messages,
int  timeout_millis 
)

Wait for a sink's num_messages field to reach a certain level.

The optional timeout prevents complete deadlock in a test.

Parameters
sinkSink to wait on.
num_messagessink->num_messages value to wait for.
timeout_millisNumber of milliseconds to wait. -1 to wait forever.
Returns
Actual sink->num_messages value at return. If this is < num_messages, then the timeout expired.

Definition at line 149 of file res_stasis_test.c.

151{
152 struct timespec deadline = make_deadline(timeout_millis);
153
154 SCOPED_MUTEX(lock, &sink->lock);
155 while (sink->num_messages < num_messages) {
156 int r = ast_cond_timedwait(&sink->cond, &sink->lock, &deadline);
157
158 if (r == ETIMEDOUT) {
159 break;
160 }
161 if (r != 0) {
162 ast_log(LOG_ERROR, "Unexpected condition error: %s\n",
163 strerror(r));
164 break;
165 }
166 }
167 return sink->num_messages;
168}

References ast_cond_timedwait, ast_log, stasis_message_sink::cond, lock, stasis_message_sink::lock, LOG_ERROR, make_deadline(), stasis_message_sink::num_messages, and SCOPED_MUTEX.

Referenced by AST_TEST_DEFINE().

◆ STASIS_MESSAGE_TYPE_DEFN()

STASIS_MESSAGE_TYPE_DEFN ( stasis_test_message_type  )

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 253 of file res_stasis_test.c.

254{
256 return 0;
257}
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition: stasis.h:1515

References STASIS_MESSAGE_TYPE_CLEANUP, and stasis_test_message_type().

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "Stasis test utilities" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, }
static

Definition at line 273 of file res_stasis_test.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 273 of file res_stasis_test.c.