mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-12-06 19:41:15 +01:00
203e9138d1
Having the numbers in those messages makes some of the unit test unstable, by causing them to depend on the initialization order of the naming objects.
622 lines
16 KiB
C
622 lines
16 KiB
C
/* Copyright (c) 2018, The Tor Project, Inc. */
|
|
/* See LICENSE for licensing information */
|
|
|
|
#define DISPATCH_PRIVATE
|
|
#define PUBSUB_PRIVATE
|
|
|
|
#include "test/test.h"
|
|
|
|
#include "lib/cc/torint.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_macros.h"
|
|
#include "lib/pubsub/pubsub_build.h"
|
|
#include "lib/pubsub/pubsub_builder_st.h"
|
|
|
|
#include "lib/log/escape.h"
|
|
#include "lib/malloc/malloc.h"
|
|
#include "lib/string/printf.h"
|
|
|
|
#include "test/log_test_helpers.h"
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
static char *
|
|
ex_int_fmt(msg_aux_data_t aux)
|
|
{
|
|
int val = (int) aux.u64;
|
|
char *r=NULL;
|
|
tor_asprintf(&r, "%d", val);
|
|
return r;
|
|
}
|
|
|
|
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 intfns = {
|
|
.fmt_fn = ex_int_fmt
|
|
};
|
|
|
|
static dispatch_typefns_t stringfns = {
|
|
.free_fn = ex_str_free,
|
|
.fmt_fn = ex_str_fmt
|
|
};
|
|
|
|
DECLARE_MESSAGE_INT(bunch_of_coconuts, int, int);
|
|
DECLARE_PUBLISH(bunch_of_coconuts);
|
|
DECLARE_SUBSCRIBE(bunch_of_coconuts, coconut_recipient_cb);
|
|
|
|
DECLARE_MESSAGE(yes_we_have_no, string, char *);
|
|
DECLARE_PUBLISH(yes_we_have_no);
|
|
DECLARE_SUBSCRIBE(yes_we_have_no, absent_item_cb);
|
|
|
|
static void
|
|
coconut_recipient_cb(const msg_t *m, int n_coconuts)
|
|
{
|
|
(void)m;
|
|
(void)n_coconuts;
|
|
}
|
|
|
|
static void
|
|
absent_item_cb(const msg_t *m, const char *fruitname)
|
|
{
|
|
(void)m;
|
|
(void)fruitname;
|
|
}
|
|
|
|
#define FLAG_SKIP 99999
|
|
|
|
static void
|
|
seed_dispatch_builder(pubsub_builder_t *b,
|
|
unsigned fl1, unsigned fl2, unsigned fl3, unsigned fl4)
|
|
{
|
|
pubsub_connector_t *c = NULL;
|
|
|
|
{
|
|
c = pubsub_connector_for_subsystem(b, get_subsys_id("sys1"));
|
|
DISPATCH_REGISTER_TYPE(c, int, &intfns);
|
|
if (fl1 != FLAG_SKIP)
|
|
DISPATCH_ADD_PUB_(c, main, bunch_of_coconuts, fl1);
|
|
if (fl2 != FLAG_SKIP)
|
|
DISPATCH_ADD_SUB_(c, main, yes_we_have_no, fl2);
|
|
pubsub_connector_free(c);
|
|
}
|
|
|
|
{
|
|
c = pubsub_connector_for_subsystem(b, get_subsys_id("sys2"));
|
|
DISPATCH_REGISTER_TYPE(c, string, &stringfns);
|
|
if (fl3 != FLAG_SKIP)
|
|
DISPATCH_ADD_PUB_(c, main, yes_we_have_no, fl3);
|
|
if (fl4 != FLAG_SKIP)
|
|
DISPATCH_ADD_SUB_(c, main, bunch_of_coconuts, fl4);
|
|
pubsub_connector_free(c);
|
|
}
|
|
}
|
|
|
|
static void
|
|
seed_pubsub_builder_basic(pubsub_builder_t *b)
|
|
{
|
|
seed_dispatch_builder(b, 0, 0, 0, 0);
|
|
}
|
|
|
|
/* Regular builder with valid types and messages.
|
|
*/
|
|
static void
|
|
test_pubsub_build_types_ok(void *arg)
|
|
{
|
|
(void)arg;
|
|
pubsub_builder_t *b = NULL;
|
|
dispatch_t *dispatcher = NULL;
|
|
pubsub_connector_t *c = NULL;
|
|
pubsub_items_t *items = NULL;
|
|
|
|
b = pubsub_builder_new();
|
|
seed_pubsub_builder_basic(b);
|
|
|
|
dispatcher = pubsub_builder_finalize(b, &items);
|
|
b = NULL;
|
|
tt_assert(dispatcher);
|
|
tt_assert(items);
|
|
tt_int_op(smartlist_len(items->items), OP_EQ, 4);
|
|
|
|
// Make sure that the bindings got build correctly.
|
|
SMARTLIST_FOREACH_BEGIN(items->items, pubsub_cfg_t *, item) {
|
|
if (item->is_publish) {
|
|
tt_assert(item->pub_binding);
|
|
tt_ptr_op(item->pub_binding->dispatch_ptr, OP_EQ, dispatcher);
|
|
}
|
|
} SMARTLIST_FOREACH_END(item);
|
|
|
|
tt_int_op(dispatcher->n_types, OP_GE, 2);
|
|
tt_assert(dispatcher->typefns);
|
|
|
|
tt_assert(dispatcher->typefns[get_msg_type_id("int")].fmt_fn == ex_int_fmt);
|
|
tt_assert(dispatcher->typefns[get_msg_type_id("string")].fmt_fn ==
|
|
ex_str_fmt);
|
|
|
|
// Now clear the bindings, like we would do before freeing the
|
|
// the dispatcher.
|
|
pubsub_items_clear_bindings(items);
|
|
SMARTLIST_FOREACH_BEGIN(items->items, pubsub_cfg_t *, item) {
|
|
if (item->is_publish) {
|
|
tt_assert(item->pub_binding);
|
|
tt_ptr_op(item->pub_binding->dispatch_ptr, OP_EQ, NULL);
|
|
}
|
|
} SMARTLIST_FOREACH_END(item);
|
|
|
|
done:
|
|
pubsub_connector_free(c);
|
|
pubsub_builder_free(b);
|
|
dispatch_free(dispatcher);
|
|
pubsub_items_free(items);
|
|
}
|
|
|
|
/* We fail if the same type is defined in two places with different functions.
|
|
*/
|
|
static void
|
|
test_pubsub_build_types_decls_conflict(void *arg)
|
|
{
|
|
(void)arg;
|
|
pubsub_builder_t *b = NULL;
|
|
dispatch_t *dispatcher = NULL;
|
|
pubsub_connector_t *c = NULL;
|
|
|
|
b = pubsub_builder_new();
|
|
seed_pubsub_builder_basic(b);
|
|
{
|
|
c = pubsub_connector_for_subsystem(b, get_subsys_id("sys3"));
|
|
// Extra declaration of int: we don't allow this.
|
|
DISPATCH_REGISTER_TYPE(c, int, &stringfns);
|
|
pubsub_connector_free(c);
|
|
}
|
|
|
|
setup_full_capture_of_logs(LOG_WARN);
|
|
dispatcher = pubsub_builder_finalize(b, NULL);
|
|
b = NULL;
|
|
tt_assert(dispatcher == NULL);
|
|
// expect_log_msg_containing("(int) declared twice"); // XXXX
|
|
|
|
done:
|
|
pubsub_connector_free(c);
|
|
pubsub_builder_free(b);
|
|
dispatch_free(dispatcher);
|
|
teardown_capture_of_logs();
|
|
}
|
|
|
|
/* If a message ID exists but nobody is publishing or subscribing to it,
|
|
* that's okay. */
|
|
static void
|
|
test_pubsub_build_unused_message(void *arg)
|
|
{
|
|
(void)arg;
|
|
pubsub_builder_t *b = NULL;
|
|
dispatch_t *dispatcher = NULL;
|
|
|
|
b = pubsub_builder_new();
|
|
seed_pubsub_builder_basic(b);
|
|
|
|
// This message isn't actually generated by anyone, but that will be fine:
|
|
// we just log it at info.
|
|
get_message_id("unused");
|
|
setup_capture_of_logs(LOG_INFO);
|
|
|
|
dispatcher = pubsub_builder_finalize(b, NULL);
|
|
b = NULL;
|
|
tt_assert(dispatcher);
|
|
expect_log_msg_containing(
|
|
"Nobody is publishing or subscribing to message");
|
|
|
|
done:
|
|
pubsub_builder_free(b);
|
|
dispatch_free(dispatcher);
|
|
teardown_capture_of_logs();
|
|
}
|
|
|
|
/* Publishing or subscribing to a message with no subscribers / publishers
|
|
* should fail and warn. */
|
|
static void
|
|
test_pubsub_build_missing_pubsub(void *arg)
|
|
{
|
|
(void)arg;
|
|
pubsub_builder_t *b = NULL;
|
|
dispatch_t *dispatcher = NULL;
|
|
|
|
b = pubsub_builder_new();
|
|
seed_dispatch_builder(b, 0, 0, FLAG_SKIP, FLAG_SKIP);
|
|
|
|
setup_full_capture_of_logs(LOG_WARN);
|
|
dispatcher = pubsub_builder_finalize(b, NULL);
|
|
b = NULL;
|
|
tt_assert(dispatcher == NULL);
|
|
|
|
expect_log_msg_containing(
|
|
"Message \"bunch_of_coconuts\" has publishers, but no subscribers.");
|
|
expect_log_msg_containing(
|
|
"Message \"yes_we_have_no\" has subscribers, but no publishers.");
|
|
|
|
done:
|
|
pubsub_builder_free(b);
|
|
dispatch_free(dispatcher);
|
|
teardown_capture_of_logs();
|
|
}
|
|
|
|
/* Make sure that a stub publisher or subscriber prevents an error from
|
|
* happening even if there are no other publishers/subscribers for a message
|
|
*/
|
|
static void
|
|
test_pubsub_build_stub_pubsub(void *arg)
|
|
{
|
|
(void)arg;
|
|
pubsub_builder_t *b = NULL;
|
|
dispatch_t *dispatcher = NULL;
|
|
|
|
b = pubsub_builder_new();
|
|
seed_dispatch_builder(b, 0, 0, DISP_FLAG_STUB, DISP_FLAG_STUB);
|
|
|
|
dispatcher = pubsub_builder_finalize(b, NULL);
|
|
b = NULL;
|
|
tt_assert(dispatcher);
|
|
|
|
// 1 subscriber.
|
|
tt_int_op(1, OP_EQ,
|
|
dispatcher->table[get_message_id("yes_we_have_no")]->n_enabled);
|
|
// no subscribers
|
|
tt_ptr_op(NULL, OP_EQ,
|
|
dispatcher->table[get_message_id("bunch_of_coconuts")]);
|
|
|
|
done:
|
|
pubsub_builder_free(b);
|
|
dispatch_free(dispatcher);
|
|
}
|
|
|
|
/* Only one channel per msg id. */
|
|
static void
|
|
test_pubsub_build_channels_conflict(void *arg)
|
|
{
|
|
(void)arg;
|
|
pubsub_builder_t *b = NULL;
|
|
dispatch_t *dispatcher = NULL;
|
|
pubsub_connector_t *c = NULL;
|
|
|
|
b = pubsub_builder_new();
|
|
seed_pubsub_builder_basic(b);
|
|
pub_binding_t btmp;
|
|
|
|
{
|
|
c = pubsub_connector_for_subsystem(b, get_subsys_id("problems"));
|
|
/* Usually the DISPATCH_ADD_PUB macro would keep us from using
|
|
* the wrong channel */
|
|
pubsub_add_pub_(c, &btmp, get_channel_id("hithere"),
|
|
get_message_id("bunch_of_coconuts"),
|
|
get_msg_type_id("int"),
|
|
0 /* flags */,
|
|
"somewhere.c", 22);
|
|
pubsub_connector_free(c);
|
|
};
|
|
|
|
setup_full_capture_of_logs(LOG_WARN);
|
|
dispatcher = pubsub_builder_finalize(b, NULL);
|
|
b = NULL;
|
|
tt_assert(dispatcher == NULL);
|
|
|
|
expect_log_msg_containing("Message \"bunch_of_coconuts\" is associated "
|
|
"with multiple inconsistent channels.");
|
|
|
|
done:
|
|
pubsub_builder_free(b);
|
|
dispatch_free(dispatcher);
|
|
teardown_capture_of_logs();
|
|
}
|
|
|
|
/* Only one type per msg id. */
|
|
static void
|
|
test_pubsub_build_types_conflict(void *arg)
|
|
{
|
|
(void)arg;
|
|
pubsub_builder_t *b = NULL;
|
|
dispatch_t *dispatcher = NULL;
|
|
pubsub_connector_t *c = NULL;
|
|
|
|
b = pubsub_builder_new();
|
|
seed_pubsub_builder_basic(b);
|
|
pub_binding_t btmp;
|
|
|
|
{
|
|
c = pubsub_connector_for_subsystem(b, get_subsys_id("problems"));
|
|
/* Usually the DISPATCH_ADD_PUB macro would keep us from using
|
|
* the wrong channel */
|
|
pubsub_add_pub_(c, &btmp, get_channel_id("hithere"),
|
|
get_message_id("bunch_of_coconuts"),
|
|
get_msg_type_id("string"),
|
|
0 /* flags */,
|
|
"somewhere.c", 22);
|
|
pubsub_connector_free(c);
|
|
};
|
|
|
|
setup_full_capture_of_logs(LOG_WARN);
|
|
dispatcher = pubsub_builder_finalize(b, NULL);
|
|
b = NULL;
|
|
tt_assert(dispatcher == NULL);
|
|
|
|
expect_log_msg_containing("Message \"bunch_of_coconuts\" is associated "
|
|
"with multiple inconsistent message types.");
|
|
|
|
done:
|
|
pubsub_builder_free(b);
|
|
dispatch_free(dispatcher);
|
|
teardown_capture_of_logs();
|
|
}
|
|
|
|
/* The same module can't publish and subscribe the same message */
|
|
static void
|
|
test_pubsub_build_pubsub_same(void *arg)
|
|
{
|
|
(void)arg;
|
|
pubsub_builder_t *b = NULL;
|
|
dispatch_t *dispatcher = NULL;
|
|
pubsub_connector_t *c = NULL;
|
|
|
|
b = pubsub_builder_new();
|
|
seed_pubsub_builder_basic(b);
|
|
|
|
{
|
|
c = pubsub_connector_for_subsystem(b, get_subsys_id("sys1"));
|
|
// already publishing this.
|
|
DISPATCH_ADD_SUB(c, main, bunch_of_coconuts);
|
|
pubsub_connector_free(c);
|
|
};
|
|
|
|
setup_full_capture_of_logs(LOG_WARN);
|
|
dispatcher = pubsub_builder_finalize(b, NULL);
|
|
b = NULL;
|
|
tt_assert(dispatcher == NULL);
|
|
|
|
expect_log_msg_containing("Message \"bunch_of_coconuts\" is published "
|
|
"and subscribed by the same subsystem \"sys1\".");
|
|
|
|
done:
|
|
pubsub_builder_free(b);
|
|
dispatch_free(dispatcher);
|
|
teardown_capture_of_logs();
|
|
}
|
|
|
|
/* More than one subsystem may publish or subscribe, and that's okay. */
|
|
static void
|
|
test_pubsub_build_pubsub_multi(void *arg)
|
|
{
|
|
(void)arg;
|
|
pubsub_builder_t *b = NULL;
|
|
dispatch_t *dispatcher = NULL;
|
|
pubsub_connector_t *c = NULL;
|
|
|
|
b = pubsub_builder_new();
|
|
seed_pubsub_builder_basic(b);
|
|
pub_binding_t btmp;
|
|
|
|
{
|
|
c = pubsub_connector_for_subsystem(b, get_subsys_id("sys3"));
|
|
DISPATCH_ADD_SUB(c, main, bunch_of_coconuts);
|
|
pubsub_add_pub_(c, &btmp, get_channel_id("main"),
|
|
get_message_id("yes_we_have_no"),
|
|
get_msg_type_id("string"),
|
|
0 /* flags */,
|
|
"somewhere.c", 22);
|
|
pubsub_connector_free(c);
|
|
};
|
|
|
|
dispatcher = pubsub_builder_finalize(b, NULL);
|
|
b = NULL;
|
|
tt_assert(dispatcher);
|
|
|
|
// 1 subscribers
|
|
tt_int_op(1, OP_EQ,
|
|
dispatcher->table[get_message_id("yes_we_have_no")]->n_enabled);
|
|
// 2 subscribers.
|
|
dtbl_entry_t *ent =
|
|
dispatcher->table[get_message_id("bunch_of_coconuts")];
|
|
tt_int_op(2, OP_EQ, ent->n_enabled);
|
|
tt_int_op(2, OP_EQ, ent->n_fns);
|
|
tt_ptr_op(ent->rcv[0].fn, OP_EQ, recv_fn__bunch_of_coconuts);
|
|
tt_ptr_op(ent->rcv[1].fn, OP_EQ, recv_fn__bunch_of_coconuts);
|
|
|
|
done:
|
|
pubsub_builder_free(b);
|
|
dispatch_free(dispatcher);
|
|
}
|
|
|
|
static void
|
|
some_other_coconut_hook(const msg_t *m)
|
|
{
|
|
(void)m;
|
|
}
|
|
|
|
/* Subscribe hooks should be build correctly when there are a bunch of
|
|
* them. */
|
|
static void
|
|
test_pubsub_build_sub_many(void *arg)
|
|
{
|
|
(void)arg;
|
|
pubsub_builder_t *b = NULL;
|
|
dispatch_t *dispatcher = NULL;
|
|
pubsub_connector_t *c = NULL;
|
|
char *sysname = NULL;
|
|
b = pubsub_builder_new();
|
|
seed_pubsub_builder_basic(b);
|
|
|
|
int i;
|
|
for (i = 1; i < 100; ++i) {
|
|
tor_asprintf(&sysname, "system%d",i);
|
|
c = pubsub_connector_for_subsystem(b, get_subsys_id(sysname));
|
|
if (i % 7) {
|
|
DISPATCH_ADD_SUB(c, main, bunch_of_coconuts);
|
|
} else {
|
|
pubsub_add_sub_(c, some_other_coconut_hook,
|
|
get_channel_id("main"),
|
|
get_message_id("bunch_of_coconuts"),
|
|
get_msg_type_id("int"),
|
|
0 /* flags */,
|
|
"somewhere.c", 22);
|
|
}
|
|
pubsub_connector_free(c);
|
|
tor_free(sysname);
|
|
};
|
|
|
|
dispatcher = pubsub_builder_finalize(b, NULL);
|
|
b = NULL;
|
|
tt_assert(dispatcher);
|
|
|
|
dtbl_entry_t *ent =
|
|
dispatcher->table[get_message_id("bunch_of_coconuts")];
|
|
tt_int_op(100, OP_EQ, ent->n_enabled);
|
|
tt_int_op(100, OP_EQ, ent->n_fns);
|
|
tt_ptr_op(ent->rcv[0].fn, OP_EQ, recv_fn__bunch_of_coconuts);
|
|
tt_ptr_op(ent->rcv[1].fn, OP_EQ, recv_fn__bunch_of_coconuts);
|
|
tt_ptr_op(ent->rcv[76].fn, OP_EQ, recv_fn__bunch_of_coconuts);
|
|
tt_ptr_op(ent->rcv[77].fn, OP_EQ, some_other_coconut_hook);
|
|
tt_ptr_op(ent->rcv[78].fn, OP_EQ, recv_fn__bunch_of_coconuts);
|
|
|
|
done:
|
|
pubsub_builder_free(b);
|
|
dispatch_free(dispatcher);
|
|
tor_free(sysname);
|
|
}
|
|
|
|
/* The same subsystem can only declare one publish or subscribe. */
|
|
static void
|
|
test_pubsub_build_pubsub_redundant(void *arg)
|
|
{
|
|
(void)arg;
|
|
pubsub_builder_t *b = NULL;
|
|
dispatch_t *dispatcher = NULL;
|
|
pubsub_connector_t *c = NULL;
|
|
|
|
b = pubsub_builder_new();
|
|
seed_pubsub_builder_basic(b);
|
|
pub_binding_t btmp;
|
|
|
|
{
|
|
c = pubsub_connector_for_subsystem(b, get_subsys_id("sys2"));
|
|
DISPATCH_ADD_SUB(c, main, bunch_of_coconuts);
|
|
pubsub_add_pub_(c, &btmp, get_channel_id("main"),
|
|
get_message_id("yes_we_have_no"),
|
|
get_msg_type_id("string"),
|
|
0 /* flags */,
|
|
"somewhere.c", 22);
|
|
pubsub_connector_free(c);
|
|
};
|
|
|
|
setup_full_capture_of_logs(LOG_WARN);
|
|
dispatcher = pubsub_builder_finalize(b, NULL);
|
|
b = NULL;
|
|
tt_assert(dispatcher == NULL);
|
|
|
|
expect_log_msg_containing(
|
|
"Message \"yes_we_have_no\" is configured to be published by "
|
|
"subsystem \"sys2\" more than once.");
|
|
expect_log_msg_containing(
|
|
"Message \"bunch_of_coconuts\" is configured to be subscribed by "
|
|
"subsystem \"sys2\" more than once.");
|
|
|
|
done:
|
|
pubsub_builder_free(b);
|
|
dispatch_free(dispatcher);
|
|
teardown_capture_of_logs();
|
|
}
|
|
|
|
/* It's fine to declare the excl flag. */
|
|
static void
|
|
test_pubsub_build_excl_ok(void *arg)
|
|
{
|
|
(void)arg;
|
|
pubsub_builder_t *b = NULL;
|
|
dispatch_t *dispatcher = NULL;
|
|
|
|
b = pubsub_builder_new();
|
|
// Try one excl/excl pair and one excl/non pair.
|
|
seed_dispatch_builder(b, DISP_FLAG_EXCL, 0,
|
|
DISP_FLAG_EXCL, DISP_FLAG_EXCL);
|
|
|
|
dispatcher = pubsub_builder_finalize(b, NULL);
|
|
b = NULL;
|
|
tt_assert(dispatcher);
|
|
|
|
// 1 subscribers
|
|
tt_int_op(1, OP_EQ,
|
|
dispatcher->table[get_message_id("yes_we_have_no")]->n_enabled);
|
|
// 1 subscriber.
|
|
tt_int_op(1, OP_EQ,
|
|
dispatcher->table[get_message_id("bunch_of_coconuts")]->n_enabled);
|
|
|
|
done:
|
|
pubsub_builder_free(b);
|
|
dispatch_free(dispatcher);
|
|
}
|
|
|
|
/* but if you declare the excl flag, you need to mean it. */
|
|
static void
|
|
test_pubsub_build_excl_bad(void *arg)
|
|
{
|
|
(void)arg;
|
|
pubsub_builder_t *b = NULL;
|
|
dispatch_t *dispatcher = NULL;
|
|
pubsub_connector_t *c = NULL;
|
|
|
|
b = pubsub_builder_new();
|
|
seed_dispatch_builder(b, DISP_FLAG_EXCL, DISP_FLAG_EXCL,
|
|
0, 0);
|
|
|
|
{
|
|
c = pubsub_connector_for_subsystem(b, get_subsys_id("sys3"));
|
|
DISPATCH_ADD_PUB_(c, main, bunch_of_coconuts, 0);
|
|
DISPATCH_ADD_SUB_(c, main, yes_we_have_no, 0);
|
|
pubsub_connector_free(c);
|
|
};
|
|
|
|
setup_full_capture_of_logs(LOG_WARN);
|
|
dispatcher = pubsub_builder_finalize(b, NULL);
|
|
b = NULL;
|
|
tt_assert(dispatcher == NULL);
|
|
|
|
expect_log_msg_containing("has multiple publishers, but at least one is "
|
|
"marked as exclusive.");
|
|
expect_log_msg_containing("has multiple subscribers, but at least one is "
|
|
"marked as exclusive.");
|
|
|
|
done:
|
|
pubsub_builder_free(b);
|
|
dispatch_free(dispatcher);
|
|
teardown_capture_of_logs();
|
|
}
|
|
|
|
#define T(name, flags) \
|
|
{ #name, test_pubsub_build_ ## name , (flags), NULL, NULL }
|
|
|
|
struct testcase_t pubsub_build_tests[] = {
|
|
T(types_ok, TT_FORK),
|
|
T(types_decls_conflict, TT_FORK),
|
|
T(unused_message, TT_FORK),
|
|
T(missing_pubsub, TT_FORK),
|
|
T(stub_pubsub, TT_FORK),
|
|
T(channels_conflict, TT_FORK),
|
|
T(types_conflict, TT_FORK),
|
|
T(pubsub_same, TT_FORK),
|
|
T(pubsub_multi, TT_FORK),
|
|
T(sub_many, TT_FORK),
|
|
T(pubsub_redundant, TT_FORK),
|
|
T(excl_ok, TT_FORK),
|
|
T(excl_bad, TT_FORK),
|
|
END_OF_TESTCASES
|
|
};
|