test_xpub_manual_last_value.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. /*
  2. Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
  3. This file is part of libzmq, the ZeroMQ core engine in C++.
  4. libzmq is free software; you can redistribute it and/or modify it under
  5. the terms of the GNU Lesser General Public License (LGPL) as published
  6. by the Free Software Foundation; either version 3 of the License, or
  7. (at your option) any later version.
  8. As a special exception, the Contributors give you permission to link
  9. this library with independent modules to produce an executable,
  10. regardless of the license terms of these independent modules, and to
  11. copy and distribute the resulting executable under terms of your choice,
  12. provided that you also meet, for each linked independent module, the
  13. terms and conditions of the license of that module. An independent
  14. module is a module which is not derived from or based on this library.
  15. If you modify this library, you must extend this exception to your
  16. version of the library.
  17. libzmq is distributed in the hope that it will be useful, but WITHOUT
  18. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  19. FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
  20. License for more details.
  21. You should have received a copy of the GNU Lesser General Public License
  22. along with this program. If not, see <http://www.gnu.org/licenses/>.
  23. */
  24. #include "testutil.hpp"
  25. #include "testutil_unity.hpp"
  26. SETUP_TEARDOWN_TESTCONTEXT
  27. void test_basic ()
  28. {
  29. // Create a publisher
  30. void *pub = test_context_socket (ZMQ_XPUB);
  31. int manual = 1;
  32. TEST_ASSERT_SUCCESS_ERRNO (
  33. zmq_setsockopt (pub, ZMQ_XPUB_MANUAL_LAST_VALUE, &manual, 4));
  34. TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub, "inproc://soname"));
  35. // Create a subscriber
  36. void *sub = test_context_socket (ZMQ_XSUB);
  37. TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, "inproc://soname"));
  38. // Subscribe for A
  39. const char subscription[] = {1, 'A', 0};
  40. send_string_expect_success (sub, subscription, 0);
  41. // Receive subscriptions from subscriber
  42. recv_string_expect_success (pub, subscription, 0);
  43. // Subscribe socket for B instead
  44. TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_SUBSCRIBE, "B", 1));
  45. // Sending A message and B Message
  46. send_string_expect_success (pub, "A", 0);
  47. send_string_expect_success (pub, "B", 0);
  48. recv_string_expect_success (sub, "B", ZMQ_DONTWAIT);
  49. // Clean up.
  50. test_context_socket_close (pub);
  51. test_context_socket_close (sub);
  52. }
  53. void test_unsubscribe_manual ()
  54. {
  55. // Create a publisher
  56. void *pub = test_context_socket (ZMQ_XPUB);
  57. TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub, "inproc://soname"));
  58. // set pub socket options
  59. int manual = 1;
  60. TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_XPUB_MANUAL_LAST_VALUE,
  61. &manual, sizeof (manual)));
  62. // Create a subscriber
  63. void *sub = test_context_socket (ZMQ_XSUB);
  64. TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, "inproc://soname"));
  65. // Subscribe for A
  66. const uint8_t subscription1[] = {1, 'A'};
  67. send_array_expect_success (sub, subscription1, 0);
  68. // Subscribe for B
  69. const uint8_t subscription2[] = {1, 'B'};
  70. send_array_expect_success (sub, subscription2, 0);
  71. char buffer[3];
  72. // Receive subscription "A" from subscriber
  73. recv_array_expect_success (pub, subscription1, 0);
  74. // Subscribe socket for XA instead
  75. TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_SUBSCRIBE, "XA", 2));
  76. // Receive subscription "B" from subscriber
  77. recv_array_expect_success (pub, subscription2, 0);
  78. // Subscribe socket for XB instead
  79. TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_SUBSCRIBE, "XB", 2));
  80. // Unsubscribe from A
  81. const uint8_t unsubscription1[2] = {0, 'A'};
  82. send_array_expect_success (sub, unsubscription1, 0);
  83. // Receive unsubscription "A" from subscriber
  84. recv_array_expect_success (pub, unsubscription1, 0);
  85. // Unsubscribe socket from XA instead
  86. TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_UNSUBSCRIBE, "XA", 2));
  87. // Sending messages XA, XB
  88. send_string_expect_success (pub, "XA", 0);
  89. send_string_expect_success (pub, "XB", 0);
  90. // Subscriber should receive XB only
  91. recv_string_expect_success (sub, "XB", ZMQ_DONTWAIT);
  92. // Close subscriber
  93. test_context_socket_close (sub);
  94. // Receive unsubscription "B"
  95. const char unsubscription2[2] = {0, 'B'};
  96. TEST_ASSERT_EQUAL_INT (
  97. sizeof unsubscription2,
  98. TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (pub, buffer, sizeof buffer, 0)));
  99. TEST_ASSERT_EQUAL_INT8_ARRAY (unsubscription2, buffer,
  100. sizeof unsubscription2);
  101. // Unsubscribe socket from XB instead
  102. TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_UNSUBSCRIBE, "XB", 2));
  103. // Clean up.
  104. test_context_socket_close (pub);
  105. }
  106. void test_xpub_proxy_unsubscribe_on_disconnect ()
  107. {
  108. const uint8_t topic_buff[] = {"1"};
  109. const uint8_t payload_buff[] = {"X"};
  110. char my_endpoint_backend[MAX_SOCKET_STRING];
  111. char my_endpoint_frontend[MAX_SOCKET_STRING];
  112. int manual = 1;
  113. // proxy frontend
  114. void *xsub_proxy = test_context_socket (ZMQ_XSUB);
  115. bind_loopback_ipv4 (xsub_proxy, my_endpoint_frontend,
  116. sizeof my_endpoint_frontend);
  117. // proxy backend
  118. void *xpub_proxy = test_context_socket (ZMQ_XPUB);
  119. TEST_ASSERT_SUCCESS_ERRNO (
  120. zmq_setsockopt (xpub_proxy, ZMQ_XPUB_MANUAL_LAST_VALUE, &manual, 4));
  121. bind_loopback_ipv4 (xpub_proxy, my_endpoint_backend,
  122. sizeof my_endpoint_backend);
  123. // publisher
  124. void *pub = test_context_socket (ZMQ_PUB);
  125. TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (pub, my_endpoint_frontend));
  126. // first subscriber subscribes
  127. void *sub1 = test_context_socket (ZMQ_SUB);
  128. TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub1, my_endpoint_backend));
  129. TEST_ASSERT_SUCCESS_ERRNO (
  130. zmq_setsockopt (sub1, ZMQ_SUBSCRIBE, topic_buff, 1));
  131. // wait
  132. msleep (SETTLE_TIME);
  133. // proxy reroutes and confirms subscriptions
  134. const uint8_t subscription[2] = {1, *topic_buff};
  135. recv_array_expect_success (xpub_proxy, subscription, ZMQ_DONTWAIT);
  136. TEST_ASSERT_SUCCESS_ERRNO (
  137. zmq_setsockopt (xpub_proxy, ZMQ_SUBSCRIBE, topic_buff, 1));
  138. send_array_expect_success (xsub_proxy, subscription, 0);
  139. // second subscriber subscribes
  140. void *sub2 = test_context_socket (ZMQ_SUB);
  141. TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub2, my_endpoint_backend));
  142. TEST_ASSERT_SUCCESS_ERRNO (
  143. zmq_setsockopt (sub2, ZMQ_SUBSCRIBE, topic_buff, 1));
  144. // wait
  145. msleep (SETTLE_TIME);
  146. // proxy reroutes
  147. recv_array_expect_success (xpub_proxy, subscription, ZMQ_DONTWAIT);
  148. TEST_ASSERT_SUCCESS_ERRNO (
  149. zmq_setsockopt (xpub_proxy, ZMQ_SUBSCRIBE, topic_buff, 1));
  150. send_array_expect_success (xsub_proxy, subscription, 0);
  151. // wait
  152. msleep (SETTLE_TIME);
  153. // let publisher send a msg
  154. send_array_expect_success (pub, topic_buff, ZMQ_SNDMORE);
  155. send_array_expect_success (pub, payload_buff, 0);
  156. // wait
  157. msleep (SETTLE_TIME);
  158. // proxy reroutes data messages to subscribers
  159. recv_array_expect_success (xsub_proxy, topic_buff, ZMQ_DONTWAIT);
  160. recv_array_expect_success (xsub_proxy, payload_buff, ZMQ_DONTWAIT);
  161. // send 2 messages
  162. send_array_expect_success (xpub_proxy, topic_buff, ZMQ_SNDMORE);
  163. send_array_expect_success (xpub_proxy, payload_buff, 0);
  164. send_array_expect_success (xpub_proxy, topic_buff, ZMQ_SNDMORE);
  165. send_array_expect_success (xpub_proxy, payload_buff, 0);
  166. // wait
  167. msleep (SETTLE_TIME);
  168. // sub2 will get 2 messages because the last subscription is sub2.
  169. recv_array_expect_success (sub2, topic_buff, ZMQ_DONTWAIT);
  170. recv_array_expect_success (sub2, payload_buff, ZMQ_DONTWAIT);
  171. recv_array_expect_success (sub2, topic_buff, ZMQ_DONTWAIT);
  172. recv_array_expect_success (sub2, payload_buff, ZMQ_DONTWAIT);
  173. recv_array_expect_success (sub1, topic_buff, ZMQ_DONTWAIT);
  174. recv_array_expect_success (sub1, payload_buff, ZMQ_DONTWAIT);
  175. // Disconnect both subscribers
  176. test_context_socket_close (sub1);
  177. test_context_socket_close (sub2);
  178. // wait
  179. msleep (SETTLE_TIME);
  180. // unsubscribe messages are passed from proxy to publisher
  181. const uint8_t unsubscription[] = {0, *topic_buff};
  182. recv_array_expect_success (xpub_proxy, unsubscription, 0);
  183. TEST_ASSERT_SUCCESS_ERRNO (
  184. zmq_setsockopt (xpub_proxy, ZMQ_UNSUBSCRIBE, topic_buff, 1));
  185. send_array_expect_success (xsub_proxy, unsubscription, 0);
  186. // should receive another unsubscribe msg
  187. recv_array_expect_success (xpub_proxy, unsubscription, 0);
  188. TEST_ASSERT_SUCCESS_ERRNO (
  189. zmq_setsockopt (xpub_proxy, ZMQ_UNSUBSCRIBE, topic_buff, 1));
  190. send_array_expect_success (xsub_proxy, unsubscription, 0);
  191. // wait
  192. msleep (SETTLE_TIME);
  193. // let publisher send a msg
  194. send_array_expect_success (pub, topic_buff, ZMQ_SNDMORE);
  195. send_array_expect_success (pub, payload_buff, 0);
  196. // wait
  197. msleep (SETTLE_TIME);
  198. // nothing should come to the proxy
  199. char buffer[1];
  200. TEST_ASSERT_FAILURE_ERRNO (
  201. EAGAIN, zmq_recv (xsub_proxy, buffer, sizeof buffer, ZMQ_DONTWAIT));
  202. test_context_socket_close (pub);
  203. test_context_socket_close (xpub_proxy);
  204. test_context_socket_close (xsub_proxy);
  205. }
  206. void test_missing_subscriptions ()
  207. {
  208. const char *topic1 = "1";
  209. const char *topic2 = "2";
  210. const char *payload = "X";
  211. char my_endpoint_backend[MAX_SOCKET_STRING];
  212. char my_endpoint_frontend[MAX_SOCKET_STRING];
  213. int manual = 1;
  214. // proxy frontend
  215. void *xsub_proxy = test_context_socket (ZMQ_XSUB);
  216. bind_loopback_ipv4 (xsub_proxy, my_endpoint_frontend,
  217. sizeof my_endpoint_frontend);
  218. // proxy backend
  219. void *xpub_proxy = test_context_socket (ZMQ_XPUB);
  220. TEST_ASSERT_SUCCESS_ERRNO (
  221. zmq_setsockopt (xpub_proxy, ZMQ_XPUB_MANUAL_LAST_VALUE, &manual, 4));
  222. bind_loopback_ipv4 (xpub_proxy, my_endpoint_backend,
  223. sizeof my_endpoint_backend);
  224. // publisher
  225. void *pub = test_context_socket (ZMQ_PUB);
  226. TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (pub, my_endpoint_frontend));
  227. // Here's the problem: because subscribers subscribe in quick succession,
  228. // the proxy is unable to confirm the first subscription before receiving
  229. // the second. This causes the first subscription to get lost.
  230. // first subscriber
  231. void *sub1 = test_context_socket (ZMQ_SUB);
  232. TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub1, my_endpoint_backend));
  233. TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sub1, ZMQ_SUBSCRIBE, topic1, 1));
  234. // wait
  235. msleep (SETTLE_TIME);
  236. // proxy now reroutes and confirms subscriptions
  237. const uint8_t subscription1[] = {1, static_cast<uint8_t> (topic1[0])};
  238. recv_array_expect_success (xpub_proxy, subscription1, ZMQ_DONTWAIT);
  239. TEST_ASSERT_SUCCESS_ERRNO (
  240. zmq_setsockopt (xpub_proxy, ZMQ_SUBSCRIBE, topic1, 1));
  241. send_array_expect_success (xsub_proxy, subscription1, 0);
  242. // second subscriber
  243. void *sub2 = test_context_socket (ZMQ_SUB);
  244. TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub2, my_endpoint_backend));
  245. TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sub2, ZMQ_SUBSCRIBE, topic2, 1));
  246. // wait
  247. msleep (SETTLE_TIME);
  248. // proxy now reroutes and confirms subscriptions
  249. const uint8_t subscription2[] = {1, static_cast<uint8_t> (topic2[0])};
  250. recv_array_expect_success (xpub_proxy, subscription2, ZMQ_DONTWAIT);
  251. TEST_ASSERT_SUCCESS_ERRNO (
  252. zmq_setsockopt (xpub_proxy, ZMQ_SUBSCRIBE, topic2, 1));
  253. send_array_expect_success (xsub_proxy, subscription2, 0);
  254. // wait
  255. msleep (SETTLE_TIME);
  256. // let publisher send 2 msgs, each with its own topic_buff
  257. send_string_expect_success (pub, topic1, ZMQ_SNDMORE);
  258. send_string_expect_success (pub, payload, 0);
  259. send_string_expect_success (pub, topic2, ZMQ_SNDMORE);
  260. send_string_expect_success (pub, payload, 0);
  261. // wait
  262. msleep (SETTLE_TIME);
  263. // proxy reroutes data messages to subscribers
  264. recv_string_expect_success (xsub_proxy, topic1, ZMQ_DONTWAIT);
  265. recv_string_expect_success (xsub_proxy, payload, ZMQ_DONTWAIT);
  266. send_string_expect_success (xpub_proxy, topic1, ZMQ_SNDMORE);
  267. send_string_expect_success (xpub_proxy, payload, 0);
  268. recv_string_expect_success (xsub_proxy, topic2, ZMQ_DONTWAIT);
  269. recv_string_expect_success (xsub_proxy, payload, ZMQ_DONTWAIT);
  270. send_string_expect_success (xpub_proxy, topic2, ZMQ_SNDMORE);
  271. send_string_expect_success (xpub_proxy, payload, 0);
  272. // wait
  273. msleep (SETTLE_TIME);
  274. // only sub2 should now get a message
  275. recv_string_expect_success (sub2, topic2, ZMQ_DONTWAIT);
  276. recv_string_expect_success (sub2, payload, ZMQ_DONTWAIT);
  277. //recv_string_expect_success (sub1, topic1, ZMQ_DONTWAIT);
  278. //recv_string_expect_success (sub1, payload, ZMQ_DONTWAIT);
  279. // Clean up
  280. test_context_socket_close (sub1);
  281. test_context_socket_close (sub2);
  282. test_context_socket_close (pub);
  283. test_context_socket_close (xpub_proxy);
  284. test_context_socket_close (xsub_proxy);
  285. }
  286. void test_unsubscribe_cleanup ()
  287. {
  288. char my_endpoint[MAX_SOCKET_STRING];
  289. // Create a publisher
  290. void *pub = test_context_socket (ZMQ_XPUB);
  291. int manual = 1;
  292. TEST_ASSERT_SUCCESS_ERRNO (
  293. zmq_setsockopt (pub, ZMQ_XPUB_MANUAL_LAST_VALUE, &manual, 4));
  294. bind_loopback_ipv4 (pub, my_endpoint, sizeof my_endpoint);
  295. // Create a subscriber
  296. void *sub = test_context_socket (ZMQ_XSUB);
  297. TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, my_endpoint));
  298. // Subscribe for A
  299. const uint8_t subscription1[2] = {1, 'A'};
  300. send_array_expect_success (sub, subscription1, 0);
  301. // Receive subscriptions from subscriber
  302. recv_array_expect_success (pub, subscription1, 0);
  303. TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_SUBSCRIBE, "XA", 2));
  304. // send 2 messages
  305. send_string_expect_success (pub, "XA", 0);
  306. send_string_expect_success (pub, "XB", 0);
  307. // receive the single message
  308. recv_string_expect_success (sub, "XA", 0);
  309. // should be nothing left in the queue
  310. char buffer[2];
  311. TEST_ASSERT_FAILURE_ERRNO (
  312. EAGAIN, zmq_recv (sub, buffer, sizeof buffer, ZMQ_DONTWAIT));
  313. // close the socket
  314. test_context_socket_close (sub);
  315. // closing the socket will result in an unsubscribe event
  316. const uint8_t unsubscription[2] = {0, 'A'};
  317. recv_array_expect_success (pub, unsubscription, 0);
  318. // this doesn't really do anything
  319. // there is no last_pipe set it will just fail silently
  320. TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_UNSUBSCRIBE, "XA", 2));
  321. // reconnect
  322. sub = test_context_socket (ZMQ_XSUB);
  323. TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, my_endpoint));
  324. // send a subscription for B
  325. const uint8_t subscription2[2] = {1, 'B'};
  326. send_array_expect_success (sub, subscription2, 0);
  327. // receive the subscription, overwrite it to XB
  328. recv_array_expect_success (pub, subscription2, 0);
  329. TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_SUBSCRIBE, "XB", 2));
  330. // send 2 messages
  331. send_string_expect_success (pub, "XA", 0);
  332. send_string_expect_success (pub, "XB", 0);
  333. // receive the single message
  334. recv_string_expect_success (sub, "XB", 0);
  335. // should be nothing left in the queue
  336. TEST_ASSERT_FAILURE_ERRNO (
  337. EAGAIN, zmq_recv (sub, buffer, sizeof buffer, ZMQ_DONTWAIT));
  338. // Clean up.
  339. test_context_socket_close (pub);
  340. test_context_socket_close (sub);
  341. }
  342. void test_manual_last_value ()
  343. {
  344. // Create a publisher
  345. void *pub = test_context_socket (ZMQ_XPUB);
  346. int hwm = 2000;
  347. TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_SNDHWM, &hwm, 4));
  348. // set pub socket options
  349. int manual = 1;
  350. TEST_ASSERT_SUCCESS_ERRNO (
  351. zmq_setsockopt (pub, ZMQ_XPUB_MANUAL_LAST_VALUE, &manual, 4));
  352. TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub, "inproc://soname"));
  353. // Create a subscriber
  354. void *sub = test_context_socket (ZMQ_SUB);
  355. TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, "inproc://soname"));
  356. // Create another subscriber
  357. void *sub2 = test_context_socket (ZMQ_SUB);
  358. TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub2, "inproc://soname"));
  359. // Subscribe for "A".
  360. TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sub, ZMQ_SUBSCRIBE, "A", 1));
  361. const uint8_t subscription[2] = {1, 'A'};
  362. // we must wait for the subscription to be processed here, otherwise some
  363. // or all published messages might be lost
  364. recv_array_expect_success (pub, subscription, 0);
  365. // manual subscribe message
  366. TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_SUBSCRIBE, "A", 1));
  367. send_string_expect_success (pub, "A", 0);
  368. recv_string_expect_success (sub, "A", 0);
  369. // Subscribe for "A".
  370. TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sub2, ZMQ_SUBSCRIBE, "A", 1));
  371. recv_array_expect_success (pub, subscription, 0);
  372. TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (pub, ZMQ_SUBSCRIBE, "A", 1));
  373. send_string_expect_success (pub, "A", 0);
  374. recv_string_expect_success (sub2, "A", 0);
  375. char buffer[255];
  376. // sub won't get a message because the last subscription pipe is sub2.
  377. TEST_ASSERT_FAILURE_ERRNO (
  378. EAGAIN, zmq_recv (sub, buffer, sizeof (buffer), ZMQ_DONTWAIT));
  379. // Clean up.
  380. test_context_socket_close (pub);
  381. test_context_socket_close (sub);
  382. test_context_socket_close (sub2);
  383. }
  384. int main ()
  385. {
  386. setup_test_environment ();
  387. UNITY_BEGIN ();
  388. RUN_TEST (test_basic);
  389. RUN_TEST (test_unsubscribe_manual);
  390. RUN_TEST (test_xpub_proxy_unsubscribe_on_disconnect);
  391. RUN_TEST (test_missing_subscriptions);
  392. RUN_TEST (test_unsubscribe_cleanup);
  393. RUN_TEST (test_manual_last_value);
  394. return UNITY_END ();
  395. }