|
@@ -0,0 +1,305 @@
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+#define DISPATCH_PRIVATE
|
|
|
+
|
|
|
+#include "test/test.h"
|
|
|
+
|
|
|
+#include "lib/dispatch/dispatch.h"
|
|
|
+#include "lib/dispatch/dispatch_naming.h"
|
|
|
+#include "lib/dispatch/dispatch_st.h"
|
|
|
+#include "lib/dispatch/msgtypes.h"
|
|
|
+#include "lib/pubsub/pubsub_flags.h"
|
|
|
+#include "lib/pubsub/pub_binding_st.h"
|
|
|
+#include "lib/pubsub/pubsub_build.h"
|
|
|
+#include "lib/pubsub/pubsub_builder_st.h"
|
|
|
+#include "lib/pubsub/pubsub_connect.h"
|
|
|
+#include "lib/pubsub/pubsub_publish.h"
|
|
|
+
|
|
|
+#include "lib/log/escape.h"
|
|
|
+#include "lib/malloc/malloc.h"
|
|
|
+#include "lib/string/printf.h"
|
|
|
+
|
|
|
+#include <stdio.h>
|
|
|
+#include <string.h>
|
|
|
+
|
|
|
+static char *
|
|
|
+ex_str_fmt(msg_aux_data_t aux)
|
|
|
+{
|
|
|
+ return esc_for_log(aux.ptr);
|
|
|
+}
|
|
|
+static void
|
|
|
+ex_str_free(msg_aux_data_t aux)
|
|
|
+{
|
|
|
+ tor_free_(aux.ptr);
|
|
|
+}
|
|
|
+static dispatch_typefns_t stringfns = {
|
|
|
+ .free_fn = ex_str_free,
|
|
|
+ .fmt_fn = ex_str_fmt
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+#define DECLARE_MESSAGE(suffix) \
|
|
|
+ static pub_binding_t pub_binding_##suffix; \
|
|
|
+ static int msg_received_##suffix = 0; \
|
|
|
+ static void recv_msg_##suffix(const msg_t *m) { \
|
|
|
+ (void)m; \
|
|
|
+ ++msg_received_##suffix; \
|
|
|
+ } \
|
|
|
+ EAT_SEMICOLON
|
|
|
+
|
|
|
+#define ADD_PUBLISH(binding_suffix, subsys, channel, msg, flags) \
|
|
|
+ STMT_BEGIN { \
|
|
|
+ con = pubsub_connector_for_subsystem(builder, \
|
|
|
+ get_subsys_id(#subsys)); \
|
|
|
+ pubsub_add_pub_(con, &pub_binding_##binding_suffix, \
|
|
|
+ get_channel_id(#channel), \
|
|
|
+ get_message_id(#msg), get_msg_type_id("string"), \
|
|
|
+ (flags), __FILE__, __LINE__); \
|
|
|
+ pubsub_connector_free(con); \
|
|
|
+ } STMT_END
|
|
|
+
|
|
|
+#define ADD_SUBSCRIBE(hook_suffix, subsys, channel, msg, flags) \
|
|
|
+ STMT_BEGIN { \
|
|
|
+ con = pubsub_connector_for_subsystem(builder, \
|
|
|
+ get_subsys_id(#subsys)); \
|
|
|
+ pubsub_add_sub_(con, recv_msg_##hook_suffix, \
|
|
|
+ get_channel_id(#channel), \
|
|
|
+ get_message_id(#msg), get_msg_type_id("string"), \
|
|
|
+ (flags), __FILE__, __LINE__); \
|
|
|
+ pubsub_connector_free(con); \
|
|
|
+ } STMT_END
|
|
|
+
|
|
|
+#define SEND(binding_suffix, val) \
|
|
|
+ STMT_BEGIN { \
|
|
|
+ msg_aux_data_t data_; \
|
|
|
+ data_.ptr = tor_strdup(val); \
|
|
|
+ pubsub_pub_(&pub_binding_##binding_suffix, data_); \
|
|
|
+ } STMT_END
|
|
|
+
|
|
|
+DECLARE_MESSAGE(msg1);
|
|
|
+DECLARE_MESSAGE(msg2);
|
|
|
+DECLARE_MESSAGE(msg3);
|
|
|
+DECLARE_MESSAGE(msg4);
|
|
|
+DECLARE_MESSAGE(msg5);
|
|
|
+
|
|
|
+static smartlist_t *strings_received = NULL;
|
|
|
+static void
|
|
|
+recv_msg_copy_string(const msg_t *m)
|
|
|
+{
|
|
|
+ const char *s = m->aux_data__.ptr;
|
|
|
+ smartlist_add(strings_received, tor_strdup(s));
|
|
|
+}
|
|
|
+
|
|
|
+static void *
|
|
|
+setup_dispatcher(const struct testcase_t *testcase)
|
|
|
+{
|
|
|
+ (void)testcase;
|
|
|
+ pubsub_builder_t *builder = pubsub_builder_new();
|
|
|
+ pubsub_connector_t *con;
|
|
|
+
|
|
|
+ {
|
|
|
+ con = pubsub_connector_for_subsystem(builder, get_subsys_id("types"));
|
|
|
+ pubsub_connector_define_type_(con,
|
|
|
+ get_msg_type_id("string"),
|
|
|
+ &stringfns,
|
|
|
+ "nowhere.c", 99);
|
|
|
+ pubsub_connector_free(con);
|
|
|
+ }
|
|
|
+
|
|
|
+ ADD_PUBLISH(msg1, sys1, main, message1, 0);
|
|
|
+ ADD_SUBSCRIBE(msg1, sys2, main, message1, 0);
|
|
|
+
|
|
|
+
|
|
|
+ ADD_PUBLISH(msg2, sys1, main, message2, 0);
|
|
|
+ ADD_SUBSCRIBE(msg2, sys2, main, message2, DISP_FLAG_STUB);
|
|
|
+
|
|
|
+
|
|
|
+ ADD_PUBLISH(msg3, sys1, main, message3, 0);
|
|
|
+ ADD_SUBSCRIBE(msg3, sys2, main, message3, 0);
|
|
|
+ ADD_SUBSCRIBE(msg3, sys3, main, message3, 0);
|
|
|
+ ADD_SUBSCRIBE(msg3, sys4, main, message3, 0);
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ ADD_PUBLISH(msg4, sys2, other, message4, 0);
|
|
|
+ ADD_SUBSCRIBE(msg4, sys1, other, message4, 0);
|
|
|
+ ADD_SUBSCRIBE(msg4, sys3, other, message4, 0);
|
|
|
+
|
|
|
+
|
|
|
+ ADD_PUBLISH(msg5, sys3, main, message5, 0);
|
|
|
+ ADD_SUBSCRIBE(msg5, sys4, main, message5, 0);
|
|
|
+ ADD_SUBSCRIBE(msg5, sys5, main, message5, 0);
|
|
|
+ ADD_SUBSCRIBE(msg5, sys6, main, message5, 0);
|
|
|
+ ADD_SUBSCRIBE(msg5, sys7, main, message5, 0);
|
|
|
+ ADD_SUBSCRIBE(msg5, sys8, main, message5, 0);
|
|
|
+ for (int i = 0; i < 1000-5; ++i) {
|
|
|
+ char *sys;
|
|
|
+ tor_asprintf(&sys, "xsys-%d", i);
|
|
|
+ con = pubsub_connector_for_subsystem(builder, get_subsys_id(sys));
|
|
|
+ pubsub_add_sub_(con, recv_msg_copy_string,
|
|
|
+ get_channel_id("main"),
|
|
|
+ get_message_id("message5"),
|
|
|
+ get_msg_type_id("string"), 0, "here", 100);
|
|
|
+ pubsub_connector_free(con);
|
|
|
+ tor_free(sys);
|
|
|
+ }
|
|
|
+
|
|
|
+ return pubsub_builder_finalize(builder);
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+cleanup_dispatcher(const struct testcase_t *testcase, void *dispatcher_)
|
|
|
+{
|
|
|
+ (void)testcase;
|
|
|
+ dispatch_t *dispatcher = dispatcher_;
|
|
|
+ dispatch_free(dispatcher);
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+static const struct testcase_setup_t dispatcher_setup = {
|
|
|
+ setup_dispatcher, cleanup_dispatcher
|
|
|
+};
|
|
|
+
|
|
|
+static void
|
|
|
+test_pubsub_msg_minimal(void *arg)
|
|
|
+{
|
|
|
+ dispatch_t *d = arg;
|
|
|
+
|
|
|
+ tt_int_op(0, OP_EQ, msg_received_msg1);
|
|
|
+ SEND(msg1, "hello world");
|
|
|
+ tt_int_op(0, OP_EQ, msg_received_msg1);
|
|
|
+
|
|
|
+ tt_int_op(0, OP_EQ, dispatch_flush(d, get_channel_id("main"), 1000));
|
|
|
+ tt_int_op(1, OP_EQ, msg_received_msg1);
|
|
|
+
|
|
|
+ done:
|
|
|
+ ;
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+test_pubsub_msg_send_to_stub(void *arg)
|
|
|
+{
|
|
|
+ dispatch_t *d = arg;
|
|
|
+
|
|
|
+ tt_int_op(0, OP_EQ, msg_received_msg2);
|
|
|
+ SEND(msg2, "hello silence");
|
|
|
+ tt_int_op(0, OP_EQ, msg_received_msg2);
|
|
|
+
|
|
|
+ tt_int_op(0, OP_EQ, dispatch_flush(d, get_channel_id("main"), 1000));
|
|
|
+ tt_int_op(0, OP_EQ, msg_received_msg2);
|
|
|
+
|
|
|
+ done:
|
|
|
+ ;
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+test_pubsub_msg_cancel_msgs(void *arg)
|
|
|
+{
|
|
|
+ dispatch_t *d = arg;
|
|
|
+
|
|
|
+ tt_int_op(0, OP_EQ, msg_received_msg1);
|
|
|
+ for (int i = 0; i < 100; ++i) {
|
|
|
+ SEND(msg1, "hello world");
|
|
|
+ }
|
|
|
+ tt_int_op(0, OP_EQ, msg_received_msg1);
|
|
|
+
|
|
|
+ tt_int_op(0, OP_EQ, dispatch_flush(d, get_channel_id("main"), 10));
|
|
|
+ tt_int_op(10, OP_EQ, msg_received_msg1);
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ done:
|
|
|
+ ;
|
|
|
+}
|
|
|
+
|
|
|
+struct alertfn_target {
|
|
|
+ dispatch_t *d;
|
|
|
+ channel_id_t ch;
|
|
|
+ int count;
|
|
|
+};
|
|
|
+static void
|
|
|
+alertfn_generic(dispatch_t *d, channel_id_t ch, void *arg)
|
|
|
+{
|
|
|
+ struct alertfn_target *t = arg;
|
|
|
+ tt_ptr_op(d, OP_EQ, t->d);
|
|
|
+ tt_int_op(ch, OP_EQ, t->ch);
|
|
|
+ ++t->count;
|
|
|
+ done:
|
|
|
+ ;
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+test_pubsub_msg_alertfns(void *arg)
|
|
|
+{
|
|
|
+ dispatch_t *d = arg;
|
|
|
+ struct alertfn_target ch1_a = { d, get_channel_id("main"), 0 };
|
|
|
+ struct alertfn_target ch2_a = { d, get_channel_id("other"), 0 };
|
|
|
+
|
|
|
+ tt_int_op(0, OP_EQ,
|
|
|
+ dispatch_set_alert_fn(d, get_channel_id("main"),
|
|
|
+ alertfn_generic, &ch1_a));
|
|
|
+ tt_int_op(0, OP_EQ,
|
|
|
+ dispatch_set_alert_fn(d, get_channel_id("other"),
|
|
|
+ alertfn_generic, &ch2_a));
|
|
|
+
|
|
|
+ SEND(msg3, "hello");
|
|
|
+ tt_int_op(ch1_a.count, OP_EQ, 1);
|
|
|
+ SEND(msg3, "world");
|
|
|
+ tt_int_op(ch1_a.count, OP_EQ, 1);
|
|
|
+ tt_int_op(ch2_a.count, OP_EQ, 0);
|
|
|
+
|
|
|
+ SEND(msg4, "worse things happen in C");
|
|
|
+ tt_int_op(ch2_a.count, OP_EQ, 1);
|
|
|
+
|
|
|
+
|
|
|
+ tt_int_op(0, OP_EQ, dispatch_flush(d, get_channel_id("main"), 1000));
|
|
|
+ tt_int_op(6, OP_EQ, msg_received_msg3);
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ tt_int_op(ch1_a.count, OP_EQ, 1);
|
|
|
+ SEND(msg1, "plover");
|
|
|
+ tt_int_op(ch1_a.count, OP_EQ, 2);
|
|
|
+ tt_int_op(ch2_a.count, OP_EQ, 1);
|
|
|
+
|
|
|
+ done:
|
|
|
+ ;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static void
|
|
|
+test_pubsub_msg_many_hooks(void *arg)
|
|
|
+{
|
|
|
+ dispatch_t *d = arg;
|
|
|
+ strings_received = smartlist_new();
|
|
|
+
|
|
|
+ tt_int_op(0, OP_EQ, msg_received_msg5);
|
|
|
+ SEND(msg5, "hello world");
|
|
|
+ tt_int_op(0, OP_EQ, msg_received_msg5);
|
|
|
+ tt_int_op(0, OP_EQ, smartlist_len(strings_received));
|
|
|
+
|
|
|
+ tt_int_op(0, OP_EQ, dispatch_flush(d, get_channel_id("main"), 100000));
|
|
|
+ tt_int_op(5, OP_EQ, msg_received_msg5);
|
|
|
+ tt_int_op(995, OP_EQ, smartlist_len(strings_received));
|
|
|
+
|
|
|
+ done:
|
|
|
+ SMARTLIST_FOREACH(strings_received, char *, s, tor_free(s));
|
|
|
+ smartlist_free(strings_received);
|
|
|
+}
|
|
|
+
|
|
|
+#define T(name) \
|
|
|
+ { #name, test_pubsub_msg_ ## name , TT_FORK, \
|
|
|
+ &dispatcher_setup, NULL }
|
|
|
+
|
|
|
+struct testcase_t pubsub_msg_tests[] = {
|
|
|
+ T(minimal),
|
|
|
+ T(send_to_stub),
|
|
|
+ T(cancel_msgs),
|
|
|
+ T(alertfns),
|
|
|
+ T(many_hooks),
|
|
|
+ END_OF_TESTCASES
|
|
|
+};
|