LCOV - code coverage report
Current view: top level - test - test_pubsub_build.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 305 320 95.3 %
Date: 2021-11-24 03:28:48 Functions: 14 20 70.0 %

          Line data    Source code
       1             : /* Copyright (c) 2018-2021, The Tor Project, Inc. */
       2             : /* See LICENSE for licensing information */
       3             : 
       4             : #define DISPATCH_PRIVATE
       5             : #define PUBSUB_PRIVATE
       6             : 
       7             : #include "test/test.h"
       8             : 
       9             : #include "lib/cc/torint.h"
      10             : #include "lib/dispatch/dispatch.h"
      11             : #include "lib/dispatch/dispatch_naming.h"
      12             : #include "lib/dispatch/dispatch_st.h"
      13             : #include "lib/dispatch/msgtypes.h"
      14             : #include "lib/pubsub/pubsub_macros.h"
      15             : #include "lib/pubsub/pubsub_build.h"
      16             : #include "lib/pubsub/pubsub_builder_st.h"
      17             : 
      18             : #include "lib/log/escape.h"
      19             : #include "lib/malloc/malloc.h"
      20             : #include "lib/string/printf.h"
      21             : 
      22             : #include "test/log_test_helpers.h"
      23             : 
      24             : #include <stdio.h>
      25             : #include <string.h>
      26             : 
      27             : static char *
      28           0 : ex_int_fmt(msg_aux_data_t aux)
      29             : {
      30           0 :   int val = (int) aux.u64;
      31           0 :   char *r=NULL;
      32           0 :   tor_asprintf(&r, "%d", val);
      33           0 :   return r;
      34             : }
      35             : 
      36             : static char *
      37           0 : ex_str_fmt(msg_aux_data_t aux)
      38             : {
      39           0 :   return esc_for_log(aux.ptr);
      40             : }
      41             : 
      42             : static void
      43           0 : ex_str_free(msg_aux_data_t aux)
      44             : {
      45           0 :   tor_free_(aux.ptr);
      46           0 : }
      47             : 
      48             : static dispatch_typefns_t intfns = {
      49             :   .fmt_fn = ex_int_fmt
      50             : };
      51             : 
      52             : static dispatch_typefns_t stringfns = {
      53             :   .free_fn = ex_str_free,
      54             :   .fmt_fn = ex_str_fmt
      55             : };
      56             : 
      57             : DECLARE_MESSAGE_INT(bunch_of_coconuts, int, int);
      58             : DECLARE_PUBLISH(bunch_of_coconuts);
      59           0 : DECLARE_SUBSCRIBE(bunch_of_coconuts, coconut_recipient_cb);
      60             : 
      61             : DECLARE_MESSAGE(yes_we_have_no, string, char *);
      62             : DECLARE_PUBLISH(yes_we_have_no);
      63           0 : DECLARE_SUBSCRIBE(yes_we_have_no, absent_item_cb);
      64             : 
      65             : static void
      66             : coconut_recipient_cb(const msg_t *m, int n_coconuts)
      67             : {
      68             :   (void)m;
      69             :   (void)n_coconuts;
      70             : }
      71             : 
      72             : static void
      73             : absent_item_cb(const msg_t *m, const char *fruitname)
      74             : {
      75             :   (void)m;
      76             :   (void)fruitname;
      77             : }
      78             : 
      79             : #define FLAG_SKIP 99999
      80             : 
      81             : static void
      82          12 : seed_dispatch_builder(pubsub_builder_t *b,
      83             :                       unsigned fl1, unsigned fl2, unsigned fl3, unsigned fl4)
      84             : {
      85          12 :   pubsub_connector_t *c = NULL;
      86             : 
      87             :   {
      88          12 :     c = pubsub_connector_for_subsystem(b, get_subsys_id("sys1"));
      89          12 :     DISPATCH_REGISTER_TYPE(c, int, &intfns);
      90          12 :     if (fl1 != FLAG_SKIP)
      91          12 :       DISPATCH_ADD_PUB_(c, main, bunch_of_coconuts, fl1);
      92          12 :     if (fl2 != FLAG_SKIP)
      93          12 :       DISPATCH_ADD_SUB_(c, main, yes_we_have_no, fl2);
      94          12 :     pubsub_connector_free(c);
      95             :   }
      96             : 
      97             :   {
      98          12 :     c = pubsub_connector_for_subsystem(b, get_subsys_id("sys2"));
      99          12 :     DISPATCH_REGISTER_TYPE(c, string, &stringfns);
     100          12 :     if (fl3 != FLAG_SKIP)
     101          11 :       DISPATCH_ADD_PUB_(c, main, yes_we_have_no, fl3);
     102          12 :     if (fl4 != FLAG_SKIP)
     103          11 :       DISPATCH_ADD_SUB_(c, main, bunch_of_coconuts, fl4);
     104          12 :     pubsub_connector_free(c);
     105             :   }
     106          12 : }
     107             : 
     108             : static void
     109           8 : seed_pubsub_builder_basic(pubsub_builder_t *b)
     110             : {
     111           8 :   seed_dispatch_builder(b, 0, 0, 0, 0);
     112           8 : }
     113             : 
     114             : /* Regular builder with valid types and messages.
     115             :  */
     116             : static void
     117           1 : test_pubsub_build_types_ok(void *arg)
     118             : {
     119           1 :   (void)arg;
     120           1 :   pubsub_builder_t *b = NULL;
     121           1 :   dispatch_t *dispatcher = NULL;
     122           1 :   pubsub_connector_t *c = NULL;
     123           1 :   pubsub_items_t *items = NULL;
     124             : 
     125           1 :   b = pubsub_builder_new();
     126           1 :   seed_pubsub_builder_basic(b);
     127             : 
     128           1 :   dispatcher = pubsub_builder_finalize(b, &items);
     129           1 :   b = NULL;
     130           1 :   tt_assert(dispatcher);
     131           1 :   tt_assert(items);
     132           1 :   tt_int_op(smartlist_len(items->items), OP_EQ, 4);
     133             : 
     134             :   // Make sure that the bindings got build correctly.
     135           5 :   SMARTLIST_FOREACH_BEGIN(items->items, pubsub_cfg_t *, item) {
     136           4 :     if (item->is_publish) {
     137           2 :       tt_assert(item->pub_binding);
     138           2 :       tt_ptr_op(item->pub_binding->dispatch_ptr, OP_EQ, dispatcher);
     139             :     }
     140           4 :   } SMARTLIST_FOREACH_END(item);
     141             : 
     142           1 :   tt_int_op(dispatcher->n_types, OP_GE, 2);
     143           1 :   tt_assert(dispatcher->typefns);
     144             : 
     145           1 :   tt_assert(dispatcher->typefns[get_msg_type_id("int")].fmt_fn == ex_int_fmt);
     146           1 :   tt_assert(dispatcher->typefns[get_msg_type_id("string")].fmt_fn ==
     147             :             ex_str_fmt);
     148             : 
     149             :   // Now clear the bindings, like we would do before freeing the
     150             :   // the dispatcher.
     151           1 :   pubsub_items_clear_bindings(items);
     152           5 :   SMARTLIST_FOREACH_BEGIN(items->items, pubsub_cfg_t *, item) {
     153           4 :     if (item->is_publish) {
     154           2 :       tt_assert(item->pub_binding);
     155           2 :       tt_ptr_op(item->pub_binding->dispatch_ptr, OP_EQ, NULL);
     156             :     }
     157           4 :   } SMARTLIST_FOREACH_END(item);
     158             : 
     159           1 :  done:
     160           1 :   pubsub_connector_free(c);
     161           1 :   pubsub_builder_free(b);
     162           1 :   dispatch_free(dispatcher);
     163           1 :   pubsub_items_free(items);
     164           1 : }
     165             : 
     166             : /* We fail if the same type is defined in two places with different functions.
     167             :  */
     168             : static void
     169           1 : test_pubsub_build_types_decls_conflict(void *arg)
     170             : {
     171           1 :   (void)arg;
     172           1 :   pubsub_builder_t *b = NULL;
     173           1 :   dispatch_t *dispatcher = NULL;
     174           1 :   pubsub_connector_t *c = NULL;
     175             : 
     176           1 :   b = pubsub_builder_new();
     177           1 :   seed_pubsub_builder_basic(b);
     178             :   {
     179           1 :     c = pubsub_connector_for_subsystem(b, get_subsys_id("sys3"));
     180             :     // Extra declaration of int: we don't allow this.
     181           1 :     DISPATCH_REGISTER_TYPE(c, int, &stringfns);
     182           1 :     pubsub_connector_free(c);
     183             :   }
     184             : 
     185           1 :   setup_full_capture_of_logs(LOG_WARN);
     186           1 :   dispatcher = pubsub_builder_finalize(b, NULL);
     187           1 :   b = NULL;
     188           1 :   tt_assert(dispatcher == NULL);
     189             :   // expect_log_msg_containing("(int) declared twice"); // XXXX
     190             : 
     191           1 :  done:
     192           1 :   pubsub_connector_free(c);
     193           1 :   pubsub_builder_free(b);
     194           1 :   dispatch_free(dispatcher);
     195           1 :   teardown_capture_of_logs();
     196           1 : }
     197             : 
     198             : /* If a message ID exists but nobody is publishing or subscribing to it,
     199             :  * that's okay. */
     200             : static void
     201           1 : test_pubsub_build_unused_message(void *arg)
     202             : {
     203           1 :   (void)arg;
     204           1 :   pubsub_builder_t *b = NULL;
     205           1 :   dispatch_t *dispatcher = NULL;
     206             : 
     207           1 :   b = pubsub_builder_new();
     208           1 :   seed_pubsub_builder_basic(b);
     209             : 
     210             :   // This message isn't actually generated by anyone, but that will be fine:
     211             :   // we just log it at info.
     212           1 :   get_message_id("unused");
     213           1 :   setup_capture_of_logs(LOG_INFO);
     214             : 
     215           1 :   dispatcher = pubsub_builder_finalize(b, NULL);
     216           1 :   b = NULL;
     217           1 :   tt_assert(dispatcher);
     218           1 :   expect_log_msg_containing(
     219           1 :      "Nobody is publishing or subscribing to message");
     220             : 
     221           1 :  done:
     222           1 :   pubsub_builder_free(b);
     223           1 :   dispatch_free(dispatcher);
     224           1 :   teardown_capture_of_logs();
     225           1 : }
     226             : 
     227             : /* Publishing or subscribing to a message with no subscribers / publishers
     228             :  * should fail and warn. */
     229             : static void
     230           1 : test_pubsub_build_missing_pubsub(void *arg)
     231             : {
     232           1 :   (void)arg;
     233           1 :   pubsub_builder_t *b = NULL;
     234           1 :   dispatch_t *dispatcher = NULL;
     235             : 
     236           1 :   b = pubsub_builder_new();
     237           1 :   seed_dispatch_builder(b, 0, 0, FLAG_SKIP, FLAG_SKIP);
     238             : 
     239           1 :   setup_full_capture_of_logs(LOG_WARN);
     240           1 :   dispatcher = pubsub_builder_finalize(b, NULL);
     241           1 :   b = NULL;
     242           1 :   tt_assert(dispatcher == NULL);
     243             : 
     244           1 :   expect_log_msg_containing(
     245           1 :        "Message \"bunch_of_coconuts\" has publishers, but no subscribers.");
     246           1 :   expect_log_msg_containing(
     247           1 :        "Message \"yes_we_have_no\" has subscribers, but no publishers.");
     248             : 
     249           1 :  done:
     250           1 :   pubsub_builder_free(b);
     251           1 :   dispatch_free(dispatcher);
     252           1 :   teardown_capture_of_logs();
     253           1 : }
     254             : 
     255             : /* Make sure that a stub publisher or subscriber prevents an error from
     256             :  * happening even if there are no other publishers/subscribers for a message
     257             :  */
     258             : static void
     259           1 : test_pubsub_build_stub_pubsub(void *arg)
     260             : {
     261           1 :   (void)arg;
     262           1 :   pubsub_builder_t *b = NULL;
     263           1 :   dispatch_t *dispatcher = NULL;
     264             : 
     265           1 :   b = pubsub_builder_new();
     266           1 :   seed_dispatch_builder(b, 0, 0, DISP_FLAG_STUB, DISP_FLAG_STUB);
     267             : 
     268           1 :   dispatcher = pubsub_builder_finalize(b, NULL);
     269           1 :   b = NULL;
     270           1 :   tt_assert(dispatcher);
     271             : 
     272             :   // 1 subscriber.
     273           1 :   tt_int_op(1, OP_EQ,
     274             :             dispatcher->table[get_message_id("yes_we_have_no")]->n_enabled);
     275             :   // no subscribers
     276           1 :   tt_ptr_op(NULL, OP_EQ,
     277             :             dispatcher->table[get_message_id("bunch_of_coconuts")]);
     278             : 
     279           1 :  done:
     280           1 :   pubsub_builder_free(b);
     281           1 :   dispatch_free(dispatcher);
     282           1 : }
     283             : 
     284             : /* Only one channel per msg id. */
     285             : static void
     286           1 : test_pubsub_build_channels_conflict(void *arg)
     287             : {
     288           1 :   (void)arg;
     289           1 :   pubsub_builder_t *b = NULL;
     290           1 :   dispatch_t *dispatcher = NULL;
     291           1 :   pubsub_connector_t *c = NULL;
     292             : 
     293           1 :   b = pubsub_builder_new();
     294           1 :   seed_pubsub_builder_basic(b);
     295           1 :   pub_binding_t btmp;
     296             : 
     297             :   {
     298           1 :     c = pubsub_connector_for_subsystem(b, get_subsys_id("problems"));
     299             :     /* Usually the DISPATCH_ADD_PUB macro would keep us from using
     300             :      * the wrong channel */
     301           1 :     pubsub_add_pub_(c, &btmp, get_channel_id("hithere"),
     302           1 :                     get_message_id("bunch_of_coconuts"),
     303           1 :                     get_msg_type_id("int"),
     304             :                     0 /* flags */,
     305             :                     "somewhere.c", 22);
     306           1 :     pubsub_connector_free(c);
     307           1 :   };
     308             : 
     309           1 :   setup_full_capture_of_logs(LOG_WARN);
     310           1 :   dispatcher = pubsub_builder_finalize(b, NULL);
     311           1 :   b = NULL;
     312           1 :   tt_assert(dispatcher == NULL);
     313             : 
     314           1 :   expect_log_msg_containing("Message \"bunch_of_coconuts\" is associated "
     315           1 :                             "with multiple inconsistent channels.");
     316             : 
     317           1 :  done:
     318           1 :   pubsub_builder_free(b);
     319           1 :   dispatch_free(dispatcher);
     320           1 :   teardown_capture_of_logs();
     321           1 : }
     322             : 
     323             : /* Only one type per msg id. */
     324             : static void
     325           1 : test_pubsub_build_types_conflict(void *arg)
     326             : {
     327           1 :   (void)arg;
     328           1 :   pubsub_builder_t *b = NULL;
     329           1 :   dispatch_t *dispatcher = NULL;
     330           1 :   pubsub_connector_t *c = NULL;
     331             : 
     332           1 :   b = pubsub_builder_new();
     333           1 :   seed_pubsub_builder_basic(b);
     334           1 :   pub_binding_t btmp;
     335             : 
     336             :   {
     337           1 :     c = pubsub_connector_for_subsystem(b, get_subsys_id("problems"));
     338             :     /* Usually the DISPATCH_ADD_PUB macro would keep us from using
     339             :      * the wrong channel */
     340           1 :     pubsub_add_pub_(c, &btmp, get_channel_id("hithere"),
     341           1 :                     get_message_id("bunch_of_coconuts"),
     342           1 :                     get_msg_type_id("string"),
     343             :                     0 /* flags */,
     344             :                     "somewhere.c", 22);
     345           1 :     pubsub_connector_free(c);
     346           1 :   };
     347             : 
     348           1 :   setup_full_capture_of_logs(LOG_WARN);
     349           1 :   dispatcher = pubsub_builder_finalize(b, NULL);
     350           1 :   b = NULL;
     351           1 :   tt_assert(dispatcher == NULL);
     352             : 
     353           1 :   expect_log_msg_containing("Message \"bunch_of_coconuts\" is associated "
     354           1 :                             "with multiple inconsistent message types.");
     355             : 
     356           1 :  done:
     357           1 :   pubsub_builder_free(b);
     358           1 :   dispatch_free(dispatcher);
     359           1 :   teardown_capture_of_logs();
     360           1 : }
     361             : 
     362             : /* The same module can't publish and subscribe the same message */
     363             : static void
     364           1 : test_pubsub_build_pubsub_same(void *arg)
     365             : {
     366           1 :   (void)arg;
     367           1 :   pubsub_builder_t *b = NULL;
     368           1 :   dispatch_t *dispatcher = NULL;
     369           1 :   pubsub_connector_t *c = NULL;
     370             : 
     371           1 :   b = pubsub_builder_new();
     372           1 :   seed_pubsub_builder_basic(b);
     373             : 
     374             :   {
     375           1 :     c = pubsub_connector_for_subsystem(b, get_subsys_id("sys1"));
     376             :     // already publishing this.
     377           1 :     DISPATCH_ADD_SUB(c, main, bunch_of_coconuts);
     378           1 :     pubsub_connector_free(c);
     379           1 :   };
     380             : 
     381           1 :   setup_full_capture_of_logs(LOG_WARN);
     382           1 :   dispatcher = pubsub_builder_finalize(b, NULL);
     383           1 :   b = NULL;
     384           1 :   tt_assert(dispatcher == NULL);
     385             : 
     386           1 :   expect_log_msg_containing("Message \"bunch_of_coconuts\" is published "
     387           1 :                             "and subscribed by the same subsystem \"sys1\".");
     388             : 
     389           1 :  done:
     390           1 :   pubsub_builder_free(b);
     391           1 :   dispatch_free(dispatcher);
     392           1 :   teardown_capture_of_logs();
     393           1 : }
     394             : 
     395             : /* More than one subsystem may publish or subscribe, and that's okay. */
     396             : static void
     397           1 : test_pubsub_build_pubsub_multi(void *arg)
     398             : {
     399           1 :   (void)arg;
     400           1 :   pubsub_builder_t *b = NULL;
     401           1 :   dispatch_t *dispatcher = NULL;
     402           1 :   pubsub_connector_t *c = NULL;
     403             : 
     404           1 :   b = pubsub_builder_new();
     405           1 :   seed_pubsub_builder_basic(b);
     406           1 :   pub_binding_t btmp;
     407             : 
     408             :   {
     409           1 :     c = pubsub_connector_for_subsystem(b, get_subsys_id("sys3"));
     410           1 :     DISPATCH_ADD_SUB(c, main, bunch_of_coconuts);
     411           1 :     pubsub_add_pub_(c, &btmp, get_channel_id("main"),
     412           1 :                     get_message_id("yes_we_have_no"),
     413           1 :                     get_msg_type_id("string"),
     414             :                     0 /* flags */,
     415             :                     "somewhere.c", 22);
     416           1 :     pubsub_connector_free(c);
     417           1 :   };
     418             : 
     419           1 :   dispatcher = pubsub_builder_finalize(b, NULL);
     420           1 :   b = NULL;
     421           1 :   tt_assert(dispatcher);
     422             : 
     423             :   // 1 subscribers
     424           1 :   tt_int_op(1, OP_EQ,
     425             :             dispatcher->table[get_message_id("yes_we_have_no")]->n_enabled);
     426             :   // 2 subscribers.
     427           2 :   dtbl_entry_t *ent =
     428           1 :     dispatcher->table[get_message_id("bunch_of_coconuts")];
     429           1 :   tt_int_op(2, OP_EQ, ent->n_enabled);
     430           1 :   tt_int_op(2, OP_EQ, ent->n_fns);
     431           1 :   tt_ptr_op(ent->rcv[0].fn, OP_EQ, recv_fn__bunch_of_coconuts);
     432           1 :   tt_ptr_op(ent->rcv[1].fn, OP_EQ, recv_fn__bunch_of_coconuts);
     433             : 
     434           1 :  done:
     435           1 :   pubsub_builder_free(b);
     436           1 :   dispatch_free(dispatcher);
     437           1 : }
     438             : 
     439             : static void
     440           0 : some_other_coconut_hook(const msg_t *m)
     441             : {
     442           0 :   (void)m;
     443           0 : }
     444             : 
     445             : /* Subscribe hooks should be build correctly when there are a bunch of
     446             :  * them. */
     447             : static void
     448           1 : test_pubsub_build_sub_many(void *arg)
     449             : {
     450           1 :   (void)arg;
     451           1 :   pubsub_builder_t *b = NULL;
     452           1 :   dispatch_t *dispatcher = NULL;
     453           1 :   pubsub_connector_t *c = NULL;
     454           1 :   char *sysname = NULL;
     455           1 :   b = pubsub_builder_new();
     456           1 :   seed_pubsub_builder_basic(b);
     457             : 
     458           1 :   int i;
     459         101 :   for (i = 1; i < 100; ++i) {
     460          99 :     tor_asprintf(&sysname, "system%d",i);
     461          99 :     c = pubsub_connector_for_subsystem(b, get_subsys_id(sysname));
     462          99 :     if (i % 7) {
     463          85 :       DISPATCH_ADD_SUB(c, main, bunch_of_coconuts);
     464             :     } else {
     465          14 :       pubsub_add_sub_(c, some_other_coconut_hook,
     466          14 :                       get_channel_id("main"),
     467          14 :                       get_message_id("bunch_of_coconuts"),
     468          14 :                       get_msg_type_id("int"),
     469             :                       0 /* flags */,
     470             :                       "somewhere.c", 22);
     471             :     }
     472          99 :     pubsub_connector_free(c);
     473          99 :     tor_free(sysname);
     474           1 :   };
     475             : 
     476           1 :   dispatcher = pubsub_builder_finalize(b, NULL);
     477           1 :   b = NULL;
     478           1 :   tt_assert(dispatcher);
     479             : 
     480           2 :   dtbl_entry_t *ent =
     481           1 :     dispatcher->table[get_message_id("bunch_of_coconuts")];
     482           1 :   tt_int_op(100, OP_EQ, ent->n_enabled);
     483           1 :   tt_int_op(100, OP_EQ, ent->n_fns);
     484           1 :   tt_ptr_op(ent->rcv[0].fn, OP_EQ, recv_fn__bunch_of_coconuts);
     485           1 :   tt_ptr_op(ent->rcv[1].fn, OP_EQ, recv_fn__bunch_of_coconuts);
     486           1 :   tt_ptr_op(ent->rcv[76].fn, OP_EQ, recv_fn__bunch_of_coconuts);
     487           1 :   tt_ptr_op(ent->rcv[77].fn, OP_EQ, some_other_coconut_hook);
     488           1 :   tt_ptr_op(ent->rcv[78].fn, OP_EQ, recv_fn__bunch_of_coconuts);
     489             : 
     490           1 :  done:
     491           1 :   pubsub_builder_free(b);
     492           1 :   dispatch_free(dispatcher);
     493           1 :   tor_free(sysname);
     494           1 : }
     495             : 
     496             : /* It's fine to declare the excl flag. */
     497             : static void
     498           1 : test_pubsub_build_excl_ok(void *arg)
     499             : {
     500           1 :   (void)arg;
     501           1 :   pubsub_builder_t *b = NULL;
     502           1 :   dispatch_t *dispatcher = NULL;
     503             : 
     504           1 :   b = pubsub_builder_new();
     505             :   // Try one excl/excl pair and one excl/non pair.
     506           1 :   seed_dispatch_builder(b, DISP_FLAG_EXCL, 0,
     507             :                         DISP_FLAG_EXCL, DISP_FLAG_EXCL);
     508             : 
     509           1 :   dispatcher = pubsub_builder_finalize(b, NULL);
     510           1 :   b = NULL;
     511           1 :   tt_assert(dispatcher);
     512             : 
     513             :   // 1 subscribers
     514           1 :   tt_int_op(1, OP_EQ,
     515             :             dispatcher->table[get_message_id("yes_we_have_no")]->n_enabled);
     516             :   // 1 subscriber.
     517           1 :   tt_int_op(1, OP_EQ,
     518             :             dispatcher->table[get_message_id("bunch_of_coconuts")]->n_enabled);
     519             : 
     520           1 :  done:
     521           1 :   pubsub_builder_free(b);
     522           1 :   dispatch_free(dispatcher);
     523           1 : }
     524             : 
     525             : /* but if you declare the excl flag, you need to mean it. */
     526             : static void
     527           1 : test_pubsub_build_excl_bad(void *arg)
     528             : {
     529           1 :   (void)arg;
     530           1 :   pubsub_builder_t *b = NULL;
     531           1 :   dispatch_t *dispatcher = NULL;
     532           1 :   pubsub_connector_t *c = NULL;
     533             : 
     534           1 :   b = pubsub_builder_new();
     535           1 :   seed_dispatch_builder(b, DISP_FLAG_EXCL, DISP_FLAG_EXCL,
     536             :                         0, 0);
     537             : 
     538             :   {
     539           1 :     c = pubsub_connector_for_subsystem(b, get_subsys_id("sys3"));
     540           1 :     DISPATCH_ADD_PUB_(c, main, bunch_of_coconuts, 0);
     541           1 :     DISPATCH_ADD_SUB_(c, main, yes_we_have_no, 0);
     542           1 :     pubsub_connector_free(c);
     543           1 :   };
     544             : 
     545           1 :   setup_full_capture_of_logs(LOG_WARN);
     546           1 :   dispatcher = pubsub_builder_finalize(b, NULL);
     547           1 :   b = NULL;
     548           1 :   tt_assert(dispatcher == NULL);
     549             : 
     550           1 :   expect_log_msg_containing("has multiple publishers, but at least one is "
     551           1 :                             "marked as exclusive.");
     552           1 :   expect_log_msg_containing("has multiple subscribers, but at least one is "
     553           1 :                             "marked as exclusive.");
     554             : 
     555           1 :  done:
     556           1 :   pubsub_builder_free(b);
     557           1 :   dispatch_free(dispatcher);
     558           1 :   teardown_capture_of_logs();
     559           1 : }
     560             : 
     561             : #define T(name, flags)                                          \
     562             :   { #name, test_pubsub_build_ ## name , (flags), NULL, NULL }
     563             : 
     564             : struct testcase_t pubsub_build_tests[] = {
     565             :   T(types_ok, TT_FORK),
     566             :   T(types_decls_conflict, TT_FORK),
     567             :   T(unused_message, TT_FORK),
     568             :   T(missing_pubsub, TT_FORK),
     569             :   T(stub_pubsub, TT_FORK),
     570             :   T(channels_conflict, TT_FORK),
     571             :   T(types_conflict, TT_FORK),
     572             :   T(pubsub_same, TT_FORK),
     573             :   T(pubsub_multi, TT_FORK),
     574             :   T(sub_many, TT_FORK),
     575             :   T(excl_ok, TT_FORK),
     576             :   T(excl_bad, TT_FORK),
     577             :   END_OF_TESTCASES
     578             : };

Generated by: LCOV version 1.14