From 4ada50801d1373d8a4d579421dc6b7ae2ad6aaa7 Mon Sep 17 00:00:00 2001 From: darobs Date: Wed, 10 Aug 2016 09:08:29 -0700 Subject: [PATCH] Broker supports add/remove link, where links are valid module handles. --- CHANGELOG.md | 4 + bindings/nodejs/src/nodejs.cpp | 28 +- core/devdoc/broadcast_bus_requirements.md | 147 +-- core/devdoc/broker_hld.md | 76 +- core/devdoc/pubsub_bus_requirements.md | 70 +- core/inc/broker.h | 32 +- core/src/broadcast_broker.c | 155 +-- core/src/broker.c | 184 +++- core/src/gateway_ll.c | 71 +- .../broadcast_bus_ut/broadcast_bus_ut.cpp | 196 ++-- core/tests/broker_ut/broker_ut.cpp | 997 +++++++++++++++--- core/tests/broker_uwp_ut/broker_uwp_ut.cpp | 26 +- core/tests/gateway_e2e/gateway_e2e.cpp | 9 + core/tests/gateway_ll_ut/gateway_ll_ut.cpp | 17 + 14 files changed, 1543 insertions(+), 469 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..6846f2db --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,4 @@ + +# Features + +Added routing module to module in gateway JSON configuration. diff --git a/bindings/nodejs/src/nodejs.cpp b/bindings/nodejs/src/nodejs.cpp index 640b5671..eba9893d 100644 --- a/bindings/nodejs/src/nodejs.cpp +++ b/bindings/nodejs/src/nodejs.cpp @@ -44,19 +44,21 @@ #define DESTROY_WAIT_TIME_IN_SECS (5) -#define NODE_LOAD_SCRIPT(ss, main_path, module_id) ss << \ - "(function() {" \ - " try {" \ - " var path = require('path');" \ - " return gatewayHost.registerModule(" \ - " require(path.resolve('" << (main_path) << "')), " << \ - (module_id) << \ - " ); " \ - " } " \ - " catch(err) { " \ - " console.error(`ERROR: ${err.toString()}`);" \ - " return false;" \ - " }" \ +#define NODE_LOAD_SCRIPT(ss, main_path, module_id) ss << \ + "(function() {" \ + " try {" \ + " var path = require('path');" \ + " var main_path = path.resolve('" << (main_path) << "');" << \ + " delete require.cache[main_path]; " << \ + " return gatewayHost.registerModule(" \ + " require(main_path), " << \ + (module_id) << \ + " ); " \ + " } " \ + " catch(err) { " \ + " console.error(`ERROR: ${err.toString()}`);" \ + " return false;" \ + " }" \ "})();" static void on_module_start(NODEJS_MODULE_HANDLE_DATA* handle_data); diff --git a/core/devdoc/broadcast_bus_requirements.md b/core/devdoc/broadcast_bus_requirements.md index 3cfe2628..5a21518c 100644 --- a/core/devdoc/broadcast_bus_requirements.md +++ b/core/devdoc/broadcast_bus_requirements.md @@ -73,6 +73,8 @@ extern void Broker_DecRef(BROKER_HANDLE broker); extern BROKER_RESULT Broker_Publish(BROKER_HANDLE broker, MODULE_HANDLE source, MESSAGE_HANDLE message); extern BROKER_RESULT Broker_AddModule(BROKER_HANDLE broker, const MODULE* module); extern BROKER_RESULT Broker_RemoveModule(BROKER_HANDLE broker, const MODULE* module); +extern BROKER_RESULT Broker_AddLink(BROKER_HANDLE broker, const LINK_DATA* link); +extern BROKER_RESULT Broker_RemoveLink(BROKER_HANDLE broker, const LINK_DATA* link); extern void Broker_Destroy(BROKER_HANDLE broker); ``` @@ -81,9 +83,9 @@ extern void Broker_Destroy(BROKER_HANDLE broker); BROKER_HANDLE Broker_Create(void) ``` -**SRS_BROKER_13_001: [** This API shall yield a `BROKER_HANDLE` representing the newly created message broker. This handle value shall not be equal to `NULL` when the API call is successful. **]** +**SRS_BCAST_BROKER_13_001: [** This API shall yield a `BROKER_HANDLE` representing the newly created message broker. This handle value shall not be equal to `NULL` when the API call is successful. **]** -**SRS_BROKER_13_003: [** This function shall return `NULL` if an underlying API call to the platform causes an error. **]** +**SRS_BCAST_BROKER_13_003: [** This function shall return `NULL` if an underlying API call to the platform causes an error. **]** The message broker implementation shall use the following definition as the backing structure for the message broker handle: @@ -103,11 +105,11 @@ typedef struct BROKER_HANDLE_DATA_TAG }BROKER_HANDLE_DATA; ``` -**SRS_BROKER_13_067: [** `Broker_Create` shall `malloc` a new instance of `BROKER_HANDLE_DATA` and return `NULL` if it fails. **]** +**SRS_BCAST_BROKER_13_067: [** `Broker_Create` shall `malloc` a new instance of `BROKER_HANDLE_DATA`. **]** -**SRS_BROKER_13_007: [** `Broker_Create` shall initialize `BROKER_HANDLE_DATA::modules` with a valid `VECTOR_HANDLE`. **]** +**SRS_BCAST_BROKER_13_007: [** `Broker_Create` shall initialize `BROKER_HANDLE_DATA::modules` with a valid `VECTOR_HANDLE`. **]** -**SRS_BROKER_13_023: [** `Broker_Create` shall initialize `BROKER_HANDLE_DATA::modules_lock` with a valid `LOCK_HANDLE`. **]** +**SRS_BCAST_BROKER_13_023: [** `Broker_Create` shall initialize `BROKER_HANDLE_DATA::modules_lock` with a valid `LOCK_HANDLE`. **]** ## Broker_IncRef @@ -116,9 +118,9 @@ void Broker_IncRef(BROKER_HANDLE broker); ``` Broker_Clone creates a clone of the message broker handle. -**SRS_BROKER_13_108: [** If `broker` is `NULL` then `Broker_IncRef` shall do nothing. **]** +**SRS_BCAST_BROKER_13_108: [** If `broker` is `NULL` then `Broker_IncRef` shall do nothing. **]** -**SRS_BROKER_13_109: [** Otherwise, `Broker_IncRef` shall increment the internal ref count. **]** +**SRS_BCAST_BROKER_13_109: [** Otherwise, `Broker_IncRef` shall increment the internal ref count. **]** ## module_publish_worker @@ -126,33 +128,33 @@ Broker_Clone creates a clone of the message broker handle. static void module_publish_worker(void* user_data) ``` -**SRS_BROKER_13_026: [** This function shall assign `user_data` to a local variable called `module_info` of type `BROKER_MODULEINFO*`. **]** +**SRS_BCAST_BROKER_13_026: [** This function shall assign `user_data` to a local variable called `module_info` of type `BROKER_MODULEINFO*`. **]** -**SRS_BROKER_13_089: [** This function shall acquire the lock on `module_info->mq_lock`. **]** +**SRS_BCAST_BROKER_13_089: [** This function shall acquire the lock on `module_info->mq_lock`. **]** -**SRS_BROKER_02_004: [** If acquiring the lock fails, then module_publish_worker shall return. **]** +**SRS_BCAST_BROKER_02_004: [** If acquiring the lock fails, then module_publish_worker shall return. **]** -**SRS_BROKER_13_068: [** This function shall run a loop that keeps running while `module_info->quit_worker` is equal to `0`. **]** +**SRS_BCAST_BROKER_13_068: [** This function shall run a loop that keeps running while `module_info->quit_worker` is equal to `0`. **]** -**SRS_BROKER_04_001: [** This function shall immediately start processing messages when `module->mq` is not empty without waiting on `module->mq_cond`. **]** +**SRS_BCAST_BROKER_04_001: [** This function shall immediately start processing messages when `module->mq` is not empty without waiting on `module->mq_cond`. **]** -**SRS_BROKER_13_071: [** For every iteration of the loop the function will first wait on `module_info->mq_cond` using `module_info->mq_lock` as the corresponding mutex to be used by the condition variable. **]** +**SRS_BCAST_BROKER_13_071: [** For every iteration of the loop the function will first wait on `module_info->mq_cond` using `module_info->mq_lock` as the corresponding mutex to be used by the condition variable. **]** -**SRS_BROKER_13_090: [** When `module_info->mq_cond` has been signaled this function shall kick off another loop predicated on `module_info->quit_worker` being equal to `0` and `module_info->mq` not being empty. This thread has the lock on `module_info->mq_lock` at this point. **]** +**SRS_BCAST_BROKER_13_090: [** When `module_info->mq_cond` has been signaled this function shall kick off another loop predicated on `module_info->quit_worker` being equal to `0` and `module_info->mq` not being empty. This thread has the lock on `module_info->mq_lock` at this point. **]** -**SRS_BROKER_13_069: [** The function shall dequeue a message from the module's message queue. **]** +**SRS_BCAST_BROKER_13_069: [** The function shall dequeue a message from the module's message queue. **]** -**SRS_BROKER_13_091: [** The function shall unlock `module_info->mq_lock`. **]** +**SRS_BCAST_BROKER_13_091: [** The function shall unlock `module_info->mq_lock`. **]** -**SRS_BROKER_13_092: [** The function shall deliver the message to the module's callback function via `module_info->module_apis`. **]** +**SRS_BCAST_BROKER_13_092: [** The function shall deliver the message to the module's callback function via `module_info->module_apis`. **]** -**SRS_BROKER_13_093: [** The function shall destroy the message that was dequeued by calling `Message_Destroy`. **]** +**SRS_BCAST_BROKER_13_093: [** The function shall destroy the message that was dequeued by calling `Message_Destroy`. **]** -**SRS_BROKER_13_094: [** The function shall re-acquire the lock on `module_info->mq_lock`. **]** +**SRS_BCAST_BROKER_13_094: [** The function shall re-acquire the lock on `module_info->mq_lock`. **]** -**SRS_BROKER_13_095: [** When the function exits the outer loop predicated on `module_info->quit_worker` being `0` it shall unlock `module_info->mq_lock` before exiting from the function. **]** +**SRS_BCAST_BROKER_13_095: [** When the function exits the outer loop predicated on `module_info->quit_worker` being `0` it shall unlock `module_info->mq_lock` before exiting from the function. **]** -**SRS_BROKER_99_012: [** The function shall deliver the message to the module's Receive function via the `IInternalGatewayModule` interface. **]** +**SRS_BCAST_BROKER_99_012: [** The function shall deliver the message to the module's Receive function via the `IInternalGatewayModule` interface. **]** ## Broker_Publish @@ -164,25 +166,25 @@ BROKER_RESULT Broker_Publish( ); ``` -**SRS_BROKER_13_030: [** If `broker` or `message` is `NULL` the function shall return `BROKER_INVALIDARG`. **]** +**SRS_BCAST_BROKER_13_030: [** If `broker` or `message` is `NULL` the function shall return `BROKER_INVALIDARG`. **]** -**SRS_BROKER_13_031: [** `Broker_Publish` shall acquire the lock `BROKER_HANDLE_DATA::modules_lock`. **]** +**SRS_BCAST_BROKER_13_031: [** `Broker_Publish` shall acquire the lock `BROKER_HANDLE_DATA::modules_lock`. **]** -**SRS_BROKER_13_032: [** `Broker_Publish` shall start a processing loop for every module in `BROKER_HANDLE_DATA::modules`. **]** +**SRS_BCAST_BROKER_13_032: [** `Broker_Publish` shall start a processing loop for every module in `BROKER_HANDLE_DATA::modules`. **]** -**SRS_BROKER_17_002: [** If `source` is not NULL, `Broker_Publish` shall not publish the message to the `BROKER_MODULEINFO::module` which matches `source`. **]** +**SRS_BCAST_BROKER_17_002: [** If `source` is not NULL, `Broker_Publish` shall not publish the message to the `BROKER_MODULEINFO::module` which matches `source`. **]** -**SRS_BROKER_13_033: [** In the loop, the function shall first acquire the lock on `BROKER_MODULEINFO::mq_lock`. **]** +**SRS_BCAST_BROKER_13_033: [** In the loop, the function shall first acquire the lock on `BROKER_MODULEINFO::mq_lock`. **]** -**SRS_BROKER_13_034: [** The function shall then append `message` to `BROKER_MODULEINFO::mq` by calling `Message_Clone` and `VECTOR_push_back`. **]** +**SRS_BCAST_BROKER_13_034: [** The function shall then append `message` to `BROKER_MODULEINFO::mq` by calling `Message_Clone` and `VECTOR_push_back`. **]** -**SRS_BROKER_13_035: [** The function shall then release `BROKER_MODULEINFO::mq_lock`. **]** +**SRS_BCAST_BROKER_13_035: [** The function shall then release `BROKER_MODULEINFO::mq_lock`. **]** -**SRS_BROKER_13_096: [** The function shall then signal `BROKER_MODULEINFO::mq_cond`. **]** +**SRS_BCAST_BROKER_13_096: [** The function shall then signal `BROKER_MODULEINFO::mq_cond`. **]** -**SRS_BROKER_13_040: [** `Broker_Publish` shall release the lock `BROKER_HANDLE_DATA::modules_lock` after the loop. **]** +**SRS_BCAST_BROKER_13_040: [** `Broker_Publish` shall release the lock `BROKER_HANDLE_DATA::modules_lock` after the loop. **]** -**SRS_BROKER_13_037: [** This function shall return `BROKER_ERROR` if an underlying API call to the platform causes an error or `BROKER_OK` otherwise. **]** +**SRS_BCAST_BROKER_13_037: [** This function shall return `BROKER_ERROR` if an underlying API call to the platform causes an error or `BROKER_OK` otherwise. **]** ## Broker_AddModule @@ -190,31 +192,31 @@ BROKER_RESULT Broker_Publish( BROKER_RESULT Broker_AddModule(BROKER_HANDLE broker, const MODULE* module) ``` -**SRS_BROKER_99_013: [** If `broker` or `module` is `NULL` the function shall return `BROKER_INVALIDARG`. **]** +**SRS_BCAST_BROKER_99_013: [** If `broker` or `module` is `NULL` the function shall return `BROKER_INVALIDARG`. **]** -**SRS_BROKER_13_107: [** The function shall assign the `module` handle to `BROKER_MODULEINFO::module`. **]** +**SRS_BCAST_BROKER_13_107: [** The function shall assign the `module` handle to `BROKER_MODULEINFO::module`. **]** -**SRS_BROKER_13_098: [** The function shall initialize `BROKER_MODULEINFO::mq` with a valid vector handle. **]** +**SRS_BCAST_BROKER_13_098: [** The function shall initialize `BROKER_MODULEINFO::mq` with a valid vector handle. **]** -**SRS_BROKER_13_099: [** The function shall initialize `BROKER_MODULEINFO::mq_lock` with a valid lock handle. **]** +**SRS_BCAST_BROKER_13_099: [** The function shall initialize `BROKER_MODULEINFO::mq_lock` with a valid lock handle. **]** -**SRS_BROKER_13_100: [** The function shall initialize `BROKER_MODULEINFO::mq_cond` with a valid condition handle. **]** +**SRS_BCAST_BROKER_13_100: [** The function shall initialize `BROKER_MODULEINFO::mq_cond` with a valid condition handle. **]** -**SRS_BROKER_13_101: [** The function shall assign `0` to `BROKER_MODULEINFO::quit_worker`. **]** +**SRS_BCAST_BROKER_13_101: [** The function shall assign `0` to `BROKER_MODULEINFO::quit_worker`. **]** -**SRS_BROKER_13_102: [** The function shall create a new thread for the module by calling `ThreadAPI_Create` using `module_publish_worker` as the thread callback and using the newly allocated `BROKER_MODULEINFO` object as the thread context. **]** +**SRS_BCAST_BROKER_13_102: [** The function shall create a new thread for the module by calling `ThreadAPI_Create` using `module_publish_worker` as the thread callback and using the newly allocated `BROKER_MODULEINFO` object as the thread context. **]** -**SRS_BROKER_13_039: [** This function shall acquire the lock on `BROKER_HANDLE_DATA::modules_lock`. **]** +**SRS_BCAST_BROKER_13_039: [** This function shall acquire the lock on `BROKER_HANDLE_DATA::modules_lock`. **]** -**SRS_BROKER_13_045: [** `Broker_AddModule` shall append the new instance of `BROKER_MODULEINFO` to `BROKER_HANDLE_DATA::modules`. **]** +**SRS_BCAST_BROKER_13_045: [** `Broker_AddModule` shall append the new instance of `BROKER_MODULEINFO` to `BROKER_HANDLE_DATA::modules`. **]** -**SRS_BROKER_13_046: [** This function shall release the lock on `BROKER_HANDLE_DATA::modules_lock`. **]** +**SRS_BCAST_BROKER_13_046: [** This function shall release the lock on `BROKER_HANDLE_DATA::modules_lock`. **]** -**SRS_BROKER_13_047: [** This function shall return `BROKER_ERROR` if an underlying API call to the platform causes an error or `BROKER_OK` otherwise. **]** +**SRS_BCAST_BROKER_13_047: [** This function shall return `BROKER_ERROR` if an underlying API call to the platform causes an error or `BROKER_OK` otherwise. **]** -**SRS_BROKER_99_014: [** If `module_handle` or `module_apis` are `NULL` the function shall return `BROKER_INVALIDARG`. **]** +**SRS_BCAST_BROKER_99_014: [** If `module_handle` or `module_apis` are `NULL` the function shall return `BROKER_INVALIDARG`. **]** -**SRS_BROKER_99_015: [** If `module_instance` is `NULL` the function shall return `BROKER_INVALIDARG`. **]** +**SRS_BCAST_BROKER_99_015: [** If `module_instance` is `NULL` the function shall return `BROKER_INVALIDARG`. **]** ## Broker_RemoveModule @@ -223,35 +225,54 @@ BROKER_RESULT Broker_AddModule(BROKER_HANDLE broker, const MODULE* module) BROKER_RESULT Broker_RemoveModule(BROKER_HANDLE broker, const MODULE* module) ``` -**SRS_BROKER_13_048: [** If `broker` or `module` is `NULL` the function shall return `BROKER_INVALIDARG`. **]** +**SRS_BCAST_BROKER_13_048: [** If `broker` or `module` is `NULL` the function shall return `BROKER_INVALIDARG`. **]** -**SRS_BROKER_13_088: [** This function shall acquire the lock on `BROKER_HANDLE_DATA::modules_lock`. **]** +**SRS_BCAST_BROKER_13_088: [** This function shall acquire the lock on `BROKER_HANDLE_DATA::modules_lock`. **]** -**SRS_BROKER_13_049: [** `Broker_RemoveModule` shall perform a linear search for `module` in `BROKER_HANDLE_DATA::modules`. **]** +**SRS_BCAST_BROKER_13_049: [** `Broker_RemoveModule` shall perform a linear search for `module` in `BROKER_HANDLE_DATA::modules`. **]** -**SRS_BROKER_13_050: [** `Broker_RemoveModule` shall unlock `BROKER_HANDLE_DATA::modules_lock` and return `BROKER_ERROR` if the module is not found in `BROKER_HANDLE_DATA::modules`. **]** +**SRS_BCAST_BROKER_13_050: [** `Broker_RemoveModule` shall unlock `BROKER_HANDLE_DATA::modules_lock` and return `BROKER_ERROR` if the module is not found in `BROKER_HANDLE_DATA::modules`. **]** -**SRS_BROKER_13_052: [** The function shall remove the module from `BROKER_HANDLE_DATA::modules`. **]** +**SRS_BCAST_BROKER_13_052: [** The function shall remove the module from `BROKER_HANDLE_DATA::modules`. **]** -**SRS_BROKER_13_054: [** This function shall release the lock on `BROKER_HANDLE_DATA::modules_lock`. **]** +**SRS_BCAST_BROKER_13_054: [** This function shall release the lock on `BROKER_HANDLE_DATA::modules_lock`. **]** -**SRS_BROKER_02_001: [** Broker_RemoveModule shall lock `BROKER_MODULEINFO::mq_lock`. **]** +**SRS_BCAST_BROKER_02_001: [** Broker_RemoveModule shall lock `BROKER_MODULEINFO::mq_lock`. **]** -**SRS_BROKER_02_002: [** If locking fails, then terminating the thread shall not be attempted (signalling the condition and joining the thread). **]** +**SRS_BCAST_BROKER_02_002: [** If locking fails, then terminating the thread shall not be attempted (signalling the condition and joining the thread). **]** -**SRS_BROKER_13_103: [** The function shall assign `1` to `BROKER_MODULEINFO::quit_worker`. **]** +**SRS_BCAST_BROKER_13_103: [** The function shall assign `1` to `BROKER_MODULEINFO::quit_worker`. **]** -**SRS_BROKER_17_001: [**The function shall signal `BROKER_MODULEINFO::mq_cond` to release module from waiting.**]** +**SRS_BCAST_BROKER_17_001: [**The function shall signal `BROKER_MODULEINFO::mq_cond` to release module from waiting.**]** -**SRS_BROKER_02_003: [** After signaling the condition, Broker_RemoveModule shall unlock `BROKER_MODULEINFO::mq_lock`. **]** +**SRS_BCAST_BROKER_02_003: [** After signaling the condition, Broker_RemoveModule shall unlock `BROKER_MODULEINFO::mq_lock`. **]** -**SRS_BROKER_13_104: [** The function shall wait for the module's thread to exit by joining `BROKER_MODULEINFO::thread` via `ThreadAPI_Join`. **]** +**SRS_BCAST_BROKER_13_104: [** The function shall wait for the module's thread to exit by joining `BROKER_MODULEINFO::thread` via `ThreadAPI_Join`. **]** -**SRS_BROKER_13_056: [** If `BROKER_MODULEINFO::mq` is not empty then this function shall call `Message_Destroy` on every message still left in the collection. **]** +**SRS_BCAST_BROKER_13_056: [** If `BROKER_MODULEINFO::mq` is not empty then this function shall call `Message_Destroy` on every message still left in the collection. **]** -**SRS_BROKER_13_057: [** The function shall free all members of the `BROKER_MODULEINFO` object. **]** +**SRS_BCAST_BROKER_13_057: [** The function shall free all members of the `BROKER_MODULEINFO` object. **]** -**SRS_BROKER_13_053: [** This function shall return `BROKER_ERROR` if an underlying API call to the platform causes an error or `BROKER_OK` otherwise. **]** +**SRS_BCAST_BROKER_13_053: [** This function shall return `BROKER_ERROR` if an underlying API call to the platform causes an error or `BROKER_OK` otherwise. **]** + +## Broker_AddLink +```c +extern BROKER_RESULT Broker_AddLink(BROKER_HANDLE broker, const LINK_DATA* link); +``` + +Add a router link to the Broker. + +**SRS_BCAST_BROKER_17_003: [** `Broker_AddLink` shall return BROKER_OK. **]** + + +## Broker_RemoveLink +```c +extern BROKER_RESULT Broker_RemoveLink(BROKER_HANDLE broker, const LINK_DATA* link); +``` + +Remove a router link from the Broker. + +**SRS_BCAST_BROKER_17_004: [** `Broker_RemoveLink` shall return BROKER_OK. **]** ## Broker_Destroy @@ -259,11 +280,11 @@ BROKER_RESULT Broker_RemoveModule(BROKER_HANDLE broker, const MODULE* module) void Broker_Destroy(BROKER_HANDLE broker) ``` -**SRS_BROKER_13_058: [** If `broker` is `NULL` the function shall do nothing. **]** +**SRS_BCAST_BROKER_13_058: [** If `broker` is `NULL` the function shall do nothing. **]** -**SRS_BROKER_13_111: [** Otherwise, Broker_Destroy shall decrement the internal ref count of the message. **]** +**SRS_BCAST_BROKER_13_111: [** Otherwise, Broker_Destroy shall decrement the internal ref count of the message. **]** -**SRS_BROKER_13_112: [** If the ref count is zero then the allocated resources are freed. **]** +**SRS_BCAST_BROKER_13_112: [** If the ref count is zero then the allocated resources are freed. **]** ## Broker_DecRef @@ -271,4 +292,4 @@ void Broker_Destroy(BROKER_HANDLE broker) void Broker_DecRef(BROKER_HANDLE broker) ``` -**SRS_BROKER_13_113: [** This function shall implement all the requirements of the `Broker_Destroy` API. **]** +**SRS_BCAST_BROKER_13_113: [** This function shall implement all the requirements of the `Broker_Destroy` API. **]** diff --git a/core/devdoc/broker_hld.md b/core/devdoc/broker_hld.md index 2ff045a9..17d87266 100644 --- a/core/devdoc/broker_hld.md +++ b/core/devdoc/broker_hld.md @@ -1,4 +1,4 @@ -Message Broker +Message Broker (PubSub) ============== High level design @@ -65,7 +65,7 @@ typedef struct MODULE_INFO_TAG ### Attaching a Module to the Broker -When a new module is added to the broker a worker thread is created to receive messages for that module. The worker thread will wait on `receive_socket` and deliver messages to the module's receive callback function. If `quit_worker` is equal to `1` then the worker thread will quit and return. +When a new module is added to the broker a worker thread is created to receive messages for that module. The worker thread will wait on `receive_socket` and deliver messages to the module's receive callback function. If the buffer received is equal to the `quit_message_guid`, then the loop will terminate. ### Publishing A Message @@ -73,23 +73,27 @@ Using a messaging system like nanomsg strongly encourages the broker to pass mes Nanomsg sockets are considered thread-safe, which means we can avoid locking during a publish unless we need access to critical module data. +In published messages, the topic is always the value of `source` as a `MODULE_HANDLE` type. This will be copied into the message in the platform-specific serialization of the type. + **Message publishing pseudo code** ```c 01: MESSAGE_HANDLE msg = Message_Clone(message) -02: unsigned char* serial_message = Message_ToByteArray( msg, &size) -03: void* nn_msg = nn_allocmsg(size, 0) -04: memcpy(nn_msg, serial_message, size) -05: int nbytes = nn_send(broker_data->publish_socket, nn_msg, NN_MSG, 0) -06: free(serial_message) -07: Message_Destroy(msg) +02: message_size = Message_ToByteArray(msg, NULL, 0) +03: buffer_size = message_size + sizeof(MODULE_HANDLE) +04: void* nn_msg = nn_allocmsg(buffer_size, 0) +05: memcpy (nn_msg, source, sizeof(MODULE_HANDLE)) +06: Message_ToByteArray(msg, nn_msg+sizeof(MODULE_HANDLE), message_size) +07: int nbytes = nn_send(broker_data->publish_socket, nn_msg, NN_MSG, 0) +08: free(nn_msg) +09: Message_Destroy(msg) ``` -The call to nn_alloc creates a buffer managed by nanomsg. THis allows for zero copy message passing as well as memory management inside nanomsg. This buffer will be destroyed after a successful call. +The call to `nn_allocmsg` creates a buffer managed by nanomsg. This allows for zero copy message passing as well as memory management inside nanomsg. This buffer will be destroyed after a successful call. -### Module Publish Worker +### Module Worker -The `module_publish_worker` function is passed in a pointer to the relevant `MODULE_INFO` object as it's thread context parameter. The function's job is to basically wait on the receive socket and process messages when received. Here's the pseudo-code implementation of what it does: +The `module_worker` function is passed in a pointer to the relevant `MODULE_INFO` object as it's thread context parameter. The function's job is to basically wait on the receive socket and process messages when received. Here's the pseudo-code implementation of what it does: **Code Segment 2** ```c @@ -107,18 +111,19 @@ The `module_publish_worker` function is passed in a pointer to the relevant `MOD 11: should_continue = false 12: } 13: else -14: { -15: MESSAGE_HANDLE msg = Message_CreateFromByteArray(buf, nbytes) -16: Deliver msg to module_info.module -17: Destroy msg -18: } -19: nn_freemsg(buf) -20: } -21: else -22: { -23: should_continue = false; -24: } -25: } +14: { +15: Strip off topic from received buffer. +16: MESSAGE_HANDLE msg = Message_CreateFromByteArray(buf, nbytes) +17: Deliver msg to module_info.module +18: Destroy msg +19: } +20: nn_freemsg(buf) +21: } +22: else +23: { +24: should_continue = false; +25: } +26: } ``` Why do we need the `socket_lock`? Helgrind and drd found a race condition between `nn_recv` and `nn_close` on the internal socket data. The socket lock prevents this race condition. @@ -138,3 +143,28 @@ The following is pseudo-code for stopping the Module Publish Worker thread: ``` If for any reason the send fails, closing the socket will guarantee the next read will fail, and the thread will terminate. + +### Routing + +The broker will receive a series of links, each with a valid source module handle and a valid sink module handle. The link entry specifies that the source will publish a message expected to be consumed by the sink. Therefore, a sink will subscribe to a source. + +As described above in *Publishing A Message*, the PubSub Broker will always publish the message using the `MODULE_HANDLE` as the topic. For each link pair sent to the Broker, the sink will subscribe to the source `MODULE_HANDLE`. + +The following is pseudo-code for Broker_AddLink: +```c +01: Lock modules_lock +02: Locate module_info for sink module. +03: nn_setsockopt(sink->receive_socket, NN_SUB, NN_SUB_SUBSCRIBE, &source,sizeof(MODULE_HANDLE)); +04: Unlock modules_lock +``` + +When removing the link, the Broker will unsubscribe to the source `MODULE_HANDLE`. The following is pseudo-code for Broker_RemoveLink: +```c +01: Lock modules_lock +02: Locate module_info for sink module. +03: nn_setsockopt(sink->receive_socket, NN_SUB, NN_SUB_UNSUBSCRIBE, &source,sizeof(MODULE_HANDLE)); +04: Unlock modules_lock +``` + +The MODULE_HANDLE was chosen over the module name simply because the handle is a fixed size, making it quick and easy to strip off of the received buffer. + diff --git a/core/devdoc/pubsub_bus_requirements.md b/core/devdoc/pubsub_bus_requirements.md index 108e672c..b111e156 100644 --- a/core/devdoc/pubsub_bus_requirements.md +++ b/core/devdoc/pubsub_bus_requirements.md @@ -69,6 +69,8 @@ extern void Broker_DecRef(BROKER_HANDLE broker); extern BROKER_RESULT Broker_Publish(BROKER_HANDLE broker, MODULE_HANDLE source, MESSAGE_HANDLE message); extern BROKER_RESULT Broker_AddModule(BROKER_HANDLE broker, const MODULE* module); extern BROKER_RESULT Broker_RemoveModule(BROKER_HANDLE broker, const MODULE* module); +extern BROKER_RESULT Broker_AddLink(BROKER_HANDLE broker, const LINK_DATA* link); +extern BROKER_RESULT Broker_RemoveLink(BROKER_HANDLE broker, const LINK_DATA* link); extern void Broker_Destroy(BROKER_HANDLE broker); ``` @@ -109,7 +111,7 @@ typedef struct BROKER_HANDLE_DATA_TAG }BROKER_HANDLE_DATA; ``` -**SRS_BROKER_13_067: [** `Broker_Create` shall `malloc` a new instance of `BROKER_HANDLE_DATA` and return `NULL` if it fails. **]** +**SRS_BROKER_13_067: [** `Broker_Create` shall `malloc` a new instance of `BROKER_HANDLE_DATA`. **]** **SRS_BROKER_13_007: [** `Broker_Create` shall initialize `BROKER_HANDLE_DATA::modules` with a valid `VECTOR_HANDLE`. **]** @@ -134,28 +136,30 @@ Broker_Clone creates a clone of the message broker handle. **SRS_BROKER_13_109: [** Otherwise, `Broker_IncRef` shall increment the internal ref count. **]** -## module_publish_worker +## module_worker ```C -static void module_publish_worker(void* user_data) +static void module_worker(void* user_data) ``` **SRS_BROKER_13_026: [** This function shall assign `user_data` to a local variable called `module_info` of type `BROKER_MODULEINFO*`. **]** **SRS_BROKER_13_089: [** This function shall acquire the lock on `module_info->socket_lock`. **]** -**SRS_BROKER_02_004: [** If acquiring the lock fails, then module_publish_worker shall return. **]** +**SRS_BROKER_02_004: [** If acquiring the lock fails, then `module_worker` shall return. **]** **SRS_BROKER_13_068: [** This function shall run a loop that keeps running until `module_info->quit_message_guid` is sent to the thread. **]** **SRS_BROKER_13_091: [** The function shall unlock `module_info->socket_lock`. **]** -**SRS_BROKER_17_016: [** If releasing the lock fails, then module_publish_worker shall return. **]** +**SRS_BROKER_17_016: [** If releasing the lock fails, then `module_worker` shall return. **]** **SRS_BROKER_17_005: [** For every iteration of the loop, the function shall wait on the `receive_socket` for messages. **]** **SRS_BROKER_17_006: [** An error on receiving a message shall terminate the loop. **]** +**SRS_BROKER_17_024: [** The function shall strip off the topic from the message. **]** + **SRS_BROKER_17_017: [** The function shall deserialize the message received. **]** **SRS_BROKER_17_018: [** If the deserialization is not successful, the message loop shall continue. **]** @@ -178,7 +182,7 @@ BROKER_RESULT Broker_Publish( ); ``` -**SRS_BROKER_13_030: [** If `broker` or `message` is `NULL` the function shall return `BROKER_INVALIDARG`. **]** +**SRS_BROKER_13_030: [** If `broker`, `source`, or `message` is `NULL` the function shall return `BROKER_INVALIDARG`. **]** **SRS_BROKER_17_022: [** `Broker_Publish` shall Lock the modules lock. **]** @@ -186,7 +190,11 @@ BROKER_RESULT Broker_Publish( **SRS_BROKER_17_008: [** `Broker_Publish` shall serialize the `message`. **]** -**SRS_BROKER_17_009: [** `Broker_Publish` shall allocate a nanomsg buffer and copy the serialized message into it. **]** +**SRS_BROKER_17_025: [** `Broker_Publish` shall allocate a nanomsg buffer the size of the serialized message + `sizeof(MODULE_HANDLE)`. **]** + +**SRS_BROKER_17_026: [** `Broker_Publish` shall copy `source` into the beginning of the nanomsg buffer. **]** + +**SRS_BROKER_17_027: [** `Broker_Publish` shall serialize the `message` into the remainder of the nanomsg buffer. **]** **SRS_BROKER_17_010: [** `Broker_Publish` shall send a message on the `publish_socket`. **]** @@ -216,7 +224,9 @@ BROKER_RESULT Broker_AddModule(BROKER_HANDLE broker, const MODULE* module) **SRS_BROKER_17_020: [** The function shall create a unique ID used as a quit signal. **]** -**SRS_BROKER_13_102: [** The function shall create a new thread for the module by calling `ThreadAPI_Create` using `module_publish_worker` as the thread callback and using the newly allocated `BROKER_MODULEINFO` object as the thread context. **]** +**SRS_BROKER_17_028: [** The function shall subscribe `BROKER_MODULEINFO::receive_socket` to the quit signal GUID. **]** + +**SRS_BROKER_13_102: [** The function shall create a new thread for the module by calling `ThreadAPI_Create` using `module_worker` as the thread callback and using the newly allocated `BROKER_MODULEINFO` object as the thread context. **]** **SRS_BROKER_13_039: [** This function shall acquire the lock on `BROKER_HANDLE_DATA::modules_lock`. **]** @@ -263,6 +273,50 @@ BROKER_RESULT Broker_RemoveModule(BROKER_HANDLE broker, const MODULE* module) **SRS_BROKER_13_053: [** This function shall return `BROKER_ERROR` if an underlying API call to the platform causes an error or `BROKER_OK` otherwise. **]** + +## Broker_AddLink +```c +extern BROKER_RESULT Broker_AddLink(BROKER_HANDLE broker, const LINK_DATA* link); +``` + +Add a router link to the Broker. + +**SRS_BROKER_17_029: [** If `broker`, `link`, `link->module_source_handle` or `link->module_sink_handle` are NULL, `Broker_AddLink` shall return `BROKER_INVALIDARG`. **]** + +**SRS_BROKER_17_030: [** `Broker_AddLink` shall lock the `modules_lock`. **]** + +**SRS_BROKER_17_031: [** `Broker_AddLink` shall find the `BROKER_HANDLE_DATA::module_info` for `link->module_sink_handle`. **]** + +**SRS_BROKER_17_041: [** `Broker_AddLink` shall find the `BROKER_HANDLE_DATA::module_info` for `link->module_source_handle`. **]** + +**SRS_BROKER_17_032: [** `Broker_AddLink` shall subscribe `module_info->receive_socket` to the `link->module_source_handle` module handle. **]** + +**SRS_BROKER_17_033: [** `Broker_AddLink` shall unlock the `modules_lock`. **]** + +**SRS_BROKER_17_034: [** Upon an error, `Broker_AddLink` shall return `BROKER_ADD_LINK_ERROR` **]** + + +## Broker_RemoveLink +```c +extern BROKER_RESULT Broker_RemoveLink(BROKER_HANDLE broker, const LINK_DATA* link); +``` + +Remove a router link from the Broker. + +**SRS_BROKER_17_035: [** If `broker`, `link`, `link->module_source_handle` or `link->module_sink_handle` are NULL, `Broker_RemoveLink` shall return `BROKER_INVALIDARG`. **]** + +**SRS_BROKER_17_036: [** `Broker_RemoveLink` shall lock the `modules_lock`. **]** + +**SRS_BROKER_17_037: [** `Broker_RemoveLink` shall find the `module_info` for `link->module_sink_handle`. **]** + +**SRS_BROKER_17_042: [** `Broker_RemoveLink` shall find the `module_info` for `link->module_source_handle`. **]** + +**SRS_BROKER_17_038: [** `Broker_RemoveLink` shall unsubscribe `module_info->receive_socket` from the `link->module_source_handle` module handle. **]** + +**SRS_BROKER_17_039: [** `Broker_RemoveLink` shall unlock the `modules_lock`. **]** + +**SRS_BROKER_17_040: [** Upon an error, `Broker_RemoveLink` shall return `BROKER_REMOVE_LINK_ERROR`. **]** + ## Broker_Destroy ```C diff --git a/core/inc/broker.h b/core/inc/broker.h index 432b6998..e76e531b 100644 --- a/core/inc/broker.h +++ b/core/inc/broker.h @@ -29,10 +29,16 @@ extern "C" #include #endif +typedef struct BROKER_LINK_DATA_TAG { + MODULE_HANDLE module_source_handle; + MODULE_HANDLE module_sink_handle; +} BROKER_LINK_DATA; + #define BROKER_RESULT_VALUES \ BROKER_OK, \ BROKER_ERROR, \ BROKER_ADD_LINK_ERROR, \ + BROKER_REMOVE_LINK_ERROR, \ BROKER_INVALIDARG /** @brief Enumeration describing the result of ::Broker_Publish, @@ -83,7 +89,7 @@ extern void Broker_DecRef(BROKER_HANDLE broker); */ extern BROKER_RESULT Broker_Publish(BROKER_HANDLE broker, MODULE_HANDLE source, MESSAGE_HANDLE message); -/** @brief Sends a message to the message broker. +/** @brief Adds a module to the message broker. * * @details For details about threading with regard to the message broker * and modules connected to it, see @@ -107,6 +113,30 @@ extern BROKER_RESULT Broker_AddModule(BROKER_HANDLE broker, const MODULE* module */ extern BROKER_RESULT Broker_RemoveModule(BROKER_HANDLE broker, const MODULE* module); +/** @brief Adds a route to the message broker. +* +* @details For details about threading with regard to the message broker +* and modules connected to it, see +* Broker High Level Design Documentation. +* +* @param broker The #BROKER_HANDLE onto which the module will be +* added. +* @param route The #BROKER_LINK_DATA for the route that will be added +* to this message broker. +* +* @return A #BROKER_RESULT describing the result of the function. +*/ +extern BROKER_RESULT Broker_AddLink(BROKER_HANDLE broker, const BROKER_LINK_DATA* link); + +/** @brief Removes a route from the message broker. +* +* @param broker The #BROKER_HANDLE from which the module will be removed. +* @param route The #BROKER_LINK_DATA of the module to be removed. +* +* @return A #BROKER_RESULT describing the result of the function. +*/ +extern BROKER_RESULT Broker_RemoveLink(BROKER_HANDLE broker, const BROKER_LINK_DATA* link); + /** @brief Disposes of resources allocated by a message broker. * * @param broker The #BROKER_HANDLE to be destroyed. diff --git a/core/src/broadcast_broker.c b/core/src/broadcast_broker.c index 0fabac15..b9c1a4bc 100644 --- a/core/src/broadcast_broker.c +++ b/core/src/broadcast_broker.c @@ -73,7 +73,7 @@ BROKER_HANDLE Broker_Create(void) { BROKER_HANDLE_DATA* result; - /*Codes_SRS_BROKER_13_067: [Broker_Create shall malloc a new instance of BROKER_HANDLE_DATA and return NULL if it fails.]*/ + /*Codes_SRS_BCAST_BROKER_13_067: [Broker_Create shall malloc a new instance of BROKER_HANDLE_DATA and return NULL if it fails.]*/ result = REFCOUNT_TYPE_CREATE(BROKER_HANDLE_DATA); if (result == NULL) { @@ -82,22 +82,22 @@ BROKER_HANDLE Broker_Create(void) } else { - /*Codes_SRS_BROKER_13_007: [Broker_Create shall initialize BROKER_HANDLE_DATA::modules with a valid VECTOR_HANDLE.]*/ + /*Codes_SRS_BCAST_BROKER_13_007: [Broker_Create shall initialize BROKER_HANDLE_DATA::modules with a valid VECTOR_HANDLE.]*/ result->modules = list_create(); if (result->modules == NULL) { - /*Codes_SRS_BROKER_13_003: [This function shall return NULL if an underlying API call to the platform causes an error.]*/ + /*Codes_SRS_BCAST_BROKER_13_003: [This function shall return NULL if an underlying API call to the platform causes an error.]*/ LogError("VECTOR_create failed"); free(result); result = NULL; } else { - /*Codes_SRS_BROKER_13_023: [Broker_Create shall initialize BROKER_HANDLE_DATA::modules_lock with a valid LOCK_HANDLE.]*/ + /*Codes_SRS_BCAST_BROKER_13_023: [Broker_Create shall initialize BROKER_HANDLE_DATA::modules_lock with a valid LOCK_HANDLE.]*/ result->modules_lock = Lock_Init(); if (result->modules_lock == NULL) { - /*Codes_SRS_BROKER_13_003: [This function shall return NULL if an underlying API call to the platform causes an error.]*/ + /*Codes_SRS_BCAST_BROKER_13_003: [This function shall return NULL if an underlying API call to the platform causes an error.]*/ LogError("Lock_Init failed"); list_destroy(result->modules); free(result); @@ -106,20 +106,20 @@ BROKER_HANDLE Broker_Create(void) } } - /*Codes_SRS_BROKER_13_001: [This API shall yield a BROKER_HANDLE representing the newly created message broker. This handle value shall not be equal to NULL when the API call is successful.]*/ + /*Codes_SRS_BCAST_BROKER_13_001: [This API shall yield a BROKER_HANDLE representing the newly created message broker. This handle value shall not be equal to NULL when the API call is successful.]*/ return result; } void Broker_IncRef(BROKER_HANDLE broker) { - /*Codes_SRS_BROKER_13_108: [If `broker` is NULL then Broker_IncRef shall do nothing.]*/ + /*Codes_SRS_BCAST_BROKER_13_108: [If `broker` is NULL then Broker_IncRef shall do nothing.]*/ if (broker == NULL) { LogError("invalid arg: broker is NULL"); } else { - /*Codes_SRS_BROKER_13_109: [Otherwise, Broker_IncRef shall increment the internal ref count.]*/ + /*Codes_SRS_BCAST_BROKER_13_109: [Otherwise, Broker_IncRef shall increment the internal ref count.]*/ INC_REF(BROKER_HANDLE_DATA, broker); } } @@ -133,42 +133,42 @@ void Broker_IncRef(BROKER_HANDLE broker) */ static int module_publish_worker(void * user_data) { - /*Codes_SRS_BROKER_13_026: [This function shall assign `user_data` to a local variable called `module_info` of type `BROKER_MODULEINFO*`.]*/ + /*Codes_SRS_BCAST_BROKER_13_026: [This function shall assign `user_data` to a local variable called `module_info` of type `BROKER_MODULEINFO*`.]*/ BROKER_MODULEINFO* module_info = (BROKER_MODULEINFO*)user_data; - /*Codes_SRS_BROKER_13_089: [This function shall acquire the lock on module_info->mq_lock.]*/ + /*Codes_SRS_BCAST_BROKER_13_089: [This function shall acquire the lock on module_info->mq_lock.]*/ if (Lock(module_info->mq_lock) != LOCK_OK) { - /*Codes_SRS_BROKER_02_004: [ If acquiring the lock fails, then module_publish_worker shall return. ]*/ + /*Codes_SRS_BCAST_BROKER_02_004: [ If acquiring the lock fails, then module_publish_worker shall return. ]*/ LogError("unable to lock"); } else { - /*Codes_SRS_BROKER_13_068: [This function shall run a loop that keeps running while module_info->quit_worker is equal to 0.]*/ + /*Codes_SRS_BCAST_BROKER_13_068: [This function shall run a loop that keeps running while module_info->quit_worker is equal to 0.]*/ while (module_info->quit_worker == 0) { - /*Codes_SRS_BROKER_13_071: [For every iteration of the loop the function will first wait on module_info->mq_cond using module_info->mq_lock as the corresponding mutex to be used by the condition variable.]*/ - /*Codes_SRS_BROKER_04_001: [This function shall immediately start processing messages when `module->mq` is not empty without waiting on `module->mq_cond`.] */ + /*Codes_SRS_BCAST_BROKER_13_071: [For every iteration of the loop the function will first wait on module_info->mq_cond using module_info->mq_lock as the corresponding mutex to be used by the condition variable.]*/ + /*Codes_SRS_BCAST_BROKER_04_001: [This function shall immediately start processing messages when `module->mq` is not empty without waiting on `module->mq_cond`.] */ /*this condition accounts for the case where the message has been enqueued in the past, and the condition has been signalled in the past, and this thread */ /*is still at static int module_publish_worker(void * user_data), that is, didn't get to execute Lock(...)*/ if ((VECTOR_size(module_info->mq) > 0) || (Condition_Wait(module_info->mq_cond, module_info->mq_lock, 0) == COND_OK)) { - /*Codes_SRS_BROKER_13_090: [When module_info->mq_cond has been signaled this function shall kick off another loop predicated on module_info->quit_worker being equal to 0 and module_info->mq not being empty.This thread has the lock on module_info->mq_lock at this point.]*/ + /*Codes_SRS_BCAST_BROKER_13_090: [When module_info->mq_cond has been signaled this function shall kick off another loop predicated on module_info->quit_worker being equal to 0 and module_info->mq not being empty.This thread has the lock on module_info->mq_lock at this point.]*/ LOCK_RESULT lock_result = LOCK_OK; while ((module_info->quit_worker == 0) && VECTOR_size(module_info->mq) > 0) { - /*Codes_SRS_BROKER_13_069: [The function shall dequeue a message from the module's message queue. ]*/ + /*Codes_SRS_BCAST_BROKER_13_069: [The function shall dequeue a message from the module's message queue. ]*/ MESSAGE_HANDLE *pmsg = (MESSAGE_HANDLE*)VECTOR_front(module_info->mq); MESSAGE_HANDLE msg = *pmsg; VECTOR_erase(module_info->mq, pmsg, 1); - /*Codes_SRS_BROKER_13_091: [The function shall unlock module_info->mq_lock.]*/ + /*Codes_SRS_BCAST_BROKER_13_091: [The function shall unlock module_info->mq_lock.]*/ if (Unlock(module_info->mq_lock) != LOCK_OK) { LogError("unable to unlock"); - /*Codes_SRS_BROKER_13_093: [The function shall destroy the message that was dequeued by calling Message_Destroy.]*/ + /*Codes_SRS_BCAST_BROKER_13_093: [The function shall destroy the message that was dequeued by calling Message_Destroy.]*/ Message_Destroy(msg); continue; @@ -176,17 +176,17 @@ static int module_publish_worker(void * user_data) else { #ifdef UWP_BINDING - /*Codes_SRS_BROKER_99_012: [The function shall deliver the message to the module's Receive function via the IInternalGatewayModule interface. ]*/ + /*Codes_SRS_BCAST_BROKER_99_012: [The function shall deliver the message to the module's Receive function via the IInternalGatewayModule interface. ]*/ module_info->module->module_instance->Module_Receive(msg); #else - /*Codes_SRS_BROKER_13_092: [The function shall deliver the message to the module's callback function via module_info->module_apis. ]*/ + /*Codes_SRS_BCAST_BROKER_13_092: [The function shall deliver the message to the module's callback function via module_info->module_apis. ]*/ module_info->module->module_apis->Module_Receive(module_info->module->module_handle, msg); #endif // UWP_BINDING - /*Codes_SRS_BROKER_13_093: [The function shall destroy the message that was dequeued by calling Message_Destroy.]*/ + /*Codes_SRS_BCAST_BROKER_13_093: [The function shall destroy the message that was dequeued by calling Message_Destroy.]*/ Message_Destroy(msg); - /*Codes_SRS_BROKER_13_094: [The function shall re - acquire the lock on module_info->mq_lock.]*/ + /*Codes_SRS_BCAST_BROKER_13_094: [The function shall re - acquire the lock on module_info->mq_lock.]*/ if ((lock_result = Lock(module_info->mq_lock)) != LOCK_OK) { LogError("unable to lock"); @@ -202,7 +202,7 @@ static int module_publish_worker(void * user_data) } } - /*Codes_SRS_BROKER_13_095: [When the function exits the outer loop predicated on module_info->quit_worker being 0 it shall unlock module_info->mq_lock before exiting from the function.]*/ + /*Codes_SRS_BCAST_BROKER_13_095: [When the function exits the outer loop predicated on module_info->quit_worker being 0 it shall unlock module_info->mq_lock before exiting from the function.]*/ if (Unlock(module_info->mq_lock) != LOCK_OK) { LogError("unable to unlock - module worker was terminating"); @@ -218,7 +218,7 @@ static BROKER_RESULT init_module(BROKER_MODULEINFO* module_info, const MODULE* m { BROKER_RESULT result; - /*Codes_SRS_BROKER_13_107: The function shall assign the `module` handle to `BROKER_MODULEINFO::module`.*/ + /*Codes_SRS_BCAST_BROKER_13_107: The function shall assign the `module` handle to `BROKER_MODULEINFO::module`.*/ module_info->module = (MODULE*)malloc(sizeof(MODULE)); if (module_info->module == NULL) { @@ -234,7 +234,7 @@ static BROKER_RESULT init_module(BROKER_MODULEINFO* module_info, const MODULE* m module_info->module->module_handle = module->module_handle; #endif // UWP_BINDING - /*Codes_SRS_BROKER_13_098: [The function shall initialize BROKER_MODULEINFO::mq with a valid vector handle.]*/ + /*Codes_SRS_BCAST_BROKER_13_098: [The function shall initialize BROKER_MODULEINFO::mq with a valid vector handle.]*/ module_info->mq = VECTOR_create(sizeof(MESSAGE_HANDLE)); if (module_info->mq == NULL) { @@ -243,7 +243,7 @@ static BROKER_RESULT init_module(BROKER_MODULEINFO* module_info, const MODULE* m } else { - /*Codes_SRS_BROKER_13_099: [The function shall initialize BROKER_MODULEINFO::mq_lock with a valid lock handle.]*/ + /*Codes_SRS_BCAST_BROKER_13_099: [The function shall initialize BROKER_MODULEINFO::mq_lock with a valid lock handle.]*/ module_info->mq_lock = Lock_Init(); if (module_info->mq_lock == NULL) { @@ -253,7 +253,7 @@ static BROKER_RESULT init_module(BROKER_MODULEINFO* module_info, const MODULE* m } else { - /*Codes_SRS_BROKER_13_100: [The function shall initialize BROKER_MODULEINFO::mq_cond with a valid condition handle.]*/ + /*Codes_SRS_BCAST_BROKER_13_100: [The function shall initialize BROKER_MODULEINFO::mq_cond with a valid condition handle.]*/ module_info->mq_cond = Condition_Init(); if (module_info->mq_cond == NULL) { @@ -264,7 +264,7 @@ static BROKER_RESULT init_module(BROKER_MODULEINFO* module_info, const MODULE* m } else { - /*Codes_SRS_BROKER_13_101: [The function shall assign 0 to BROKER_MODULEINFO::quit_worker.]*/ + /*Codes_SRS_BCAST_BROKER_13_101: [The function shall assign 0 to BROKER_MODULEINFO::quit_worker.]*/ module_info->quit_worker = 0; result = BROKER_OK; } @@ -277,7 +277,7 @@ static BROKER_RESULT init_module(BROKER_MODULEINFO* module_info, const MODULE* m static void deinit_module(BROKER_MODULEINFO* module_info) { - /*Codes_SRS_BROKER_13_057: [The function shall free all members of the MODULE_INFO object.]*/ + /*Codes_SRS_BCAST_BROKER_13_057: [The function shall free all members of the MODULE_INFO object.]*/ VECTOR_destroy(module_info->mq); Condition_Deinit(module_info->mq_cond); Lock_Deinit(module_info->mq_lock); @@ -288,7 +288,7 @@ static BROKER_RESULT start_module(BROKER_MODULEINFO* module_info) { BROKER_RESULT result; - /*Codes_SRS_BROKER_13_102: [The function shall create a new thread for the module by calling ThreadAPI_Create using module_publish_worker as the thread callback and using the newly allocated BROKER_MODULEINFO object as the thread context.*/ + /*Codes_SRS_BCAST_BROKER_13_102: [The function shall create a new thread for the module by calling ThreadAPI_Create using module_publish_worker as the thread callback and using the newly allocated BROKER_MODULEINFO object as the thread context.*/ if (ThreadAPI_Create( &(module_info->thread), module_publish_worker, @@ -312,19 +312,19 @@ static int stop_module(BROKER_MODULEINFO* module_info) { int thread_result, result; size_t len, i; - /*Codes_SRS_BROKER_02_001: [ Broker_RemoveModule shall lock `BROKER_MODULEINFO::mq_lock`. ]*/ + /*Codes_SRS_BCAST_BROKER_02_001: [ Broker_RemoveModule shall lock `BROKER_MODULEINFO::mq_lock`. ]*/ if (Lock(module_info->mq_lock) != LOCK_OK) { module_info->quit_worker = 1; /*at the cost of a data race, still try to stop the module*/ - /*Codes_SRS_BROKER_02_002: [ If locking fails, then terminating the thread shall not be attempted (signalling the condition and joining the thread). ]*/ + /*Codes_SRS_BCAST_BROKER_02_002: [ If locking fails, then terminating the thread shall not be attempted (signalling the condition and joining the thread). ]*/ LogError("unable to lock mq_lock"); } else { - /*Codes_SRS_BROKER_13_103: [The function shall assign 1 to BROKER_MODULEINFO::quit_worker.]*/ + /*Codes_SRS_BCAST_BROKER_13_103: [The function shall assign 1 to BROKER_MODULEINFO::quit_worker.]*/ module_info->quit_worker = 1; - /*Codes_SRS_BROKER_17_001: [The function shall signal BROKER_MODULEINFO::mq_cond to release module from waiting.]*/ + /*Codes_SRS_BCAST_BROKER_17_001: [The function shall signal BROKER_MODULEINFO::mq_cond to release module from waiting.]*/ if (Condition_Post(module_info->mq_cond) != COND_OK) { LogError("Condition_Post failed for module at item [%p] failed", module_info); @@ -334,14 +334,14 @@ static int stop_module(BROKER_MODULEINFO* module_info) /*all is fine, thread will eventually stop and be joined*/ } - /*Codes_SRS_BROKER_02_003: [ After signaling the condition, Broker_RemoveModule shall unlock BROKER_MODULEINFO::mq_lock. ]*/ + /*Codes_SRS_BCAST_BROKER_02_003: [ After signaling the condition, Broker_RemoveModule shall unlock BROKER_MODULEINFO::mq_lock. ]*/ if (Unlock(module_info->mq_lock) != LOCK_OK) { LogError("unable to unlock mq_lock"); } } - /*Codes_SRS_BROKER_13_104: [The function shall wait for the module's thread to exit by joining BROKER_MODULEINFO::thread via ThreadAPI_Join. ]*/ + /*Codes_SRS_BCAST_BROKER_13_104: [The function shall wait for the module's thread to exit by joining BROKER_MODULEINFO::thread via ThreadAPI_Join. ]*/ if (ThreadAPI_Join(module_info->thread, &thread_result) != THREADAPI_OK) { result = __LINE__; @@ -352,7 +352,7 @@ static int stop_module(BROKER_MODULEINFO* module_info) result = 0; } - /*Codes_SRS_BROKER_13_056: [If BROKER_MODULEINFO::mq is not empty then this function shall call Message_Destroy on every message still left in the collection.]*/ + /*Codes_SRS_BCAST_BROKER_13_056: [If BROKER_MODULEINFO::mq is not empty then this function shall call Message_Destroy on every message still left in the collection.]*/ len = VECTOR_size(module_info->mq); for (i = 0; i < len; i++) { @@ -367,21 +367,21 @@ BROKER_RESULT Broker_AddModule(BROKER_HANDLE broker, const MODULE* module) { BROKER_RESULT result; - /*Codes_SRS_BROKER_99_013: [If `broker` or `module` is NULL the function shall return BROKER_INVALIDARG.]*/ + /*Codes_SRS_BCAST_BROKER_99_013: [If `broker` or `module` is NULL the function shall return BROKER_INVALIDARG.]*/ if (broker == NULL || module == NULL) { result = BROKER_INVALIDARG; LogError("invalid parameter (NULL)."); } #ifdef UWP_BINDING - /*Codes_SRS_BROKER_99_015: [If `module_instance` is `NULL` the function shall return `BROKER_INVALIDARG`.]*/ + /*Codes_SRS_BCAST_BROKER_99_015: [If `module_instance` is `NULL` the function shall return `BROKER_INVALIDARG`.]*/ else if (module->module_instance == NULL) { result = BROKER_INVALIDARG; LogError("invalid parameter (NULL)."); } #else - /*Codes_SRS_BROKER_99_014: [If `module_handle` or `module_apis` are `NULL` the function shall return `BROKER_INVALIDARG`.]*/ + /*Codes_SRS_BCAST_BROKER_99_014: [If `module_handle` or `module_apis` are `NULL` the function shall return `BROKER_INVALIDARG`.]*/ else if (module->module_apis == NULL || module->module_handle == NULL) { result = BROKER_INVALIDARG; @@ -400,7 +400,7 @@ BROKER_RESULT Broker_AddModule(BROKER_HANDLE broker, const MODULE* module) { if (init_module(module_info, module) != BROKER_OK) { - /*Codes_SRS_BROKER_13_047: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.]*/ + /*Codes_SRS_BCAST_BROKER_13_047: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.]*/ LogError("start_module failed"); free(module_info->module); free(module_info); @@ -408,11 +408,11 @@ BROKER_RESULT Broker_AddModule(BROKER_HANDLE broker, const MODULE* module) } else { - /*Codes_SRS_BROKER_13_039: [This function shall acquire the lock on BROKER_HANDLE_DATA::modules_lock.]*/ + /*Codes_SRS_BCAST_BROKER_13_039: [This function shall acquire the lock on BROKER_HANDLE_DATA::modules_lock.]*/ BROKER_HANDLE_DATA* broker_data = (BROKER_HANDLE_DATA*)broker; if (Lock(broker_data->modules_lock) != LOCK_OK) { - /*Codes_SRS_BROKER_13_047: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.]*/ + /*Codes_SRS_BCAST_BROKER_13_047: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.]*/ LogError("Lock on broker_data->modules_lock failed"); deinit_module(module_info); free(module_info); @@ -420,11 +420,11 @@ BROKER_RESULT Broker_AddModule(BROKER_HANDLE broker, const MODULE* module) } else { - /*Codes_SRS_BROKER_13_045: [Broker_AddModule shall append the new instance of BROKER_MODULEINFO to BROKER_HANDLE_DATA::modules.]*/ + /*Codes_SRS_BCAST_BROKER_13_045: [Broker_AddModule shall append the new instance of BROKER_MODULEINFO to BROKER_HANDLE_DATA::modules.]*/ LIST_ITEM_HANDLE moduleListItem = list_add(broker_data->modules, module_info); if (moduleListItem == NULL) { - /*Codes_SRS_BROKER_13_047: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.]*/ + /*Codes_SRS_BCAST_BROKER_13_047: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.]*/ LogError("list_add failed"); deinit_module(module_info); free(module_info); @@ -442,12 +442,12 @@ BROKER_RESULT Broker_AddModule(BROKER_HANDLE broker, const MODULE* module) } else { - /*Codes_SRS_BROKER_13_047: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.]*/ + /*Codes_SRS_BCAST_BROKER_13_047: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.]*/ result = BROKER_OK; } } - /*Codes_SRS_BROKER_13_046: [This function shall release the lock on BROKER_HANDLE_DATA::modules_lock.]*/ + /*Codes_SRS_BCAST_BROKER_13_046: [This function shall release the lock on BROKER_HANDLE_DATA::modules_lock.]*/ Unlock(broker_data->modules_lock); } } @@ -470,7 +470,7 @@ static bool find_module_predicate(LIST_ITEM_HANDLE list_item, const void* value) BROKER_RESULT Broker_RemoveModule(BROKER_HANDLE broker, const MODULE* module) { - /*Codes_SRS_BROKER_13_048: [If `broker` or `module` is NULL the function shall return BROKER_INVALIDARG.]*/ + /*Codes_SRS_BCAST_BROKER_13_048: [If `broker` or `module` is NULL the function shall return BROKER_INVALIDARG.]*/ BROKER_RESULT result; if (broker == NULL || module == NULL) { @@ -479,22 +479,22 @@ BROKER_RESULT Broker_RemoveModule(BROKER_HANDLE broker, const MODULE* module) } else { - /*Codes_SRS_BROKER_13_088: [This function shall acquire the lock on BROKER_HANDLE_DATA::modules_lock.]*/ + /*Codes_SRS_BCAST_BROKER_13_088: [This function shall acquire the lock on BROKER_HANDLE_DATA::modules_lock.]*/ BROKER_HANDLE_DATA* broker_data = (BROKER_HANDLE_DATA*)broker; if (Lock(broker_data->modules_lock) != LOCK_OK) { - /*Codes_SRS_BROKER_13_053: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.]*/ + /*Codes_SRS_BCAST_BROKER_13_053: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.]*/ LogError("Lock on broker_data->modules_lock failed"); result = BROKER_ERROR; } else { - /*Codes_SRS_BROKER_13_049: [Broker_RemoveModule shall perform a linear search for module in BROKER_HANDLE_DATA::modules.]*/ + /*Codes_SRS_BCAST_BROKER_13_049: [Broker_RemoveModule shall perform a linear search for module in BROKER_HANDLE_DATA::modules.]*/ LIST_ITEM_HANDLE module_info_item = list_find(broker_data->modules, find_module_predicate, module); if (module_info_item == NULL) { - /*Codes_SRS_BROKER_13_050: [Broker_RemoveModule shall unlock BROKER_HANDLE_DATA::modules_lock and return BROKER_ERROR if the module is not found in BROKER_HANDLE_DATA::modules.]*/ + /*Codes_SRS_BCAST_BROKER_13_050: [Broker_RemoveModule shall unlock BROKER_HANDLE_DATA::modules_lock and return BROKER_ERROR if the module is not found in BROKER_HANDLE_DATA::modules.]*/ LogError("Supplied module was not found on the broker"); result = BROKER_ERROR; } @@ -510,15 +510,15 @@ BROKER_RESULT Broker_RemoveModule(BROKER_HANDLE broker, const MODULE* module) LogError("unable to stop module"); } - /*Codes_SRS_BROKER_13_052: [The function shall remove the module from BROKER_HANDLE_DATA::modules.]*/ + /*Codes_SRS_BCAST_BROKER_13_052: [The function shall remove the module from BROKER_HANDLE_DATA::modules.]*/ list_remove(broker_data->modules, module_info_item); free(module_info); - /*Codes_SRS_BROKER_13_053: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.]*/ + /*Codes_SRS_BCAST_BROKER_13_053: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.]*/ result = BROKER_OK; } - /*Codes_SRS_BROKER_13_054: [This function shall release the lock on BROKER_HANDLE_DATA::modules_lock.]*/ + /*Codes_SRS_BCAST_BROKER_13_054: [This function shall release the lock on BROKER_HANDLE_DATA::modules_lock.]*/ Unlock(broker_data->modules_lock); } } @@ -528,11 +528,11 @@ BROKER_RESULT Broker_RemoveModule(BROKER_HANDLE broker, const MODULE* module) static void broker_decrement_ref(BROKER_HANDLE broker) { - /*Codes_SRS_BROKER_13_058: [If `broker` is NULL the function shall do nothing.]*/ + /*Codes_SRS_BCAST_BROKER_13_058: [If `broker` is NULL the function shall do nothing.]*/ if (broker != NULL) { - /*Codes_SRS_BROKER_13_111: [Otherwise, Broker_Destroy shall decrement the internal ref count of the message.]*/ - /*Codes_SRS_BROKER_13_112: [If the ref count is zero then the allocated resources are freed.]*/ + /*Codes_SRS_BCAST_BROKER_13_111: [Otherwise, Broker_Destroy shall decrement the internal ref count of the message.]*/ + /*Codes_SRS_BCAST_BROKER_13_112: [If the ref count is zero then the allocated resources are freed.]*/ if (DEC_REF(BROKER_HANDLE_DATA, broker) == DEC_RETURN_ZERO) { BROKER_HANDLE_DATA* broker_data = (BROKER_HANDLE_DATA*)broker; @@ -551,6 +551,17 @@ static void broker_decrement_ref(BROKER_HANDLE broker) LogError("broker handle is NULL"); } } +BROKER_RESULT Broker_AddLink(BROKER_HANDLE broker, const BROKER_LINK_DATA* link) +{ + /*Codes_SRS_BCAST_BROKER_17_003: [ Broker_AddLink shall return BROKER_OK. ]*/ + return BROKER_OK; +} + +BROKER_RESULT Broker_RemoveLink(BROKER_HANDLE broker, const BROKER_LINK_DATA* link) +{ + /*Codes_SRS_BCAST_BROKER_17_004: [ Broker_RemoveLink shall return BROKER_OK. ]*/ + return BROKER_OK; +} extern void Broker_Destroy(BROKER_HANDLE broker) { @@ -559,14 +570,14 @@ extern void Broker_Destroy(BROKER_HANDLE broker) extern void Broker_DecRef(BROKER_HANDLE broker) { - /*Codes_SRS_BROKER_13_113: [This function shall implement all the requirements of the Broker_Destroy API.]*/ + /*Codes_SRS_BCAST_BROKER_13_113: [This function shall implement all the requirements of the Broker_Destroy API.]*/ broker_decrement_ref(broker); } BROKER_RESULT Broker_Publish(BROKER_HANDLE broker, MODULE_HANDLE source, MESSAGE_HANDLE message) { BROKER_RESULT result; - /*Codes_SRS_BROKER_13_030: [If broker or message is NULL the function shall return BROKER_INVALIDARG.]*/ + /*Codes_SRS_BCAST_BROKER_13_030: [If broker or message is NULL the function shall return BROKER_INVALIDARG.]*/ if (broker == NULL || message == NULL) { result = BROKER_INVALIDARG; @@ -574,7 +585,7 @@ BROKER_RESULT Broker_Publish(BROKER_HANDLE broker, MODULE_HANDLE source, MESSAGE } else { - /*Codes_SRS_BROKER_13_031: [Broker_Publish shall acquire the lock BROKER_HANDLE_DATA::modules_lock.]*/ + /*Codes_SRS_BCAST_BROKER_13_031: [Broker_Publish shall acquire the lock BROKER_HANDLE_DATA::modules_lock.]*/ BROKER_HANDLE_DATA* broker_data = (BROKER_HANDLE_DATA*)broker; if (Lock(broker_data->modules_lock) != LOCK_OK) { @@ -583,9 +594,9 @@ BROKER_RESULT Broker_Publish(BROKER_HANDLE broker, MODULE_HANDLE source, MESSAGE } else { - /*Codes_SRS_BROKER_13_032: [Broker_Publish shall start a processing loop for every module in BROKER_HANDLE_DATA::modules.]*/ + /*Codes_SRS_BCAST_BROKER_13_032: [Broker_Publish shall start a processing loop for every module in BROKER_HANDLE_DATA::modules.]*/ - /*Codes_SRS_BROKER_13_037: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.]*/ + /*Codes_SRS_BCAST_BROKER_13_037: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.]*/ result = BROKER_OK; // NOTE: This is a best-effort delivery bus which means that we offer no @@ -600,27 +611,27 @@ BROKER_RESULT Broker_Publish(BROKER_HANDLE broker, MODULE_HANDLE source, MESSAGE BROKER_MODULEINFO* module_info = (BROKER_MODULEINFO*)list_item_get_value(current_module); - /*Codes_SRS_BROKER_17_002: [ If source is not NULL, Broker_Publish shall not publish the message to the BROKER_MODULEINFO::module which matches source. ]*/ + /*Codes_SRS_BCAST_BROKER_17_002: [ If source is not NULL, Broker_Publish shall not publish the message to the BROKER_MODULEINFO::module which matches source. ]*/ #ifdef UWP_BINDING if (source == NULL || module_info->module->module_instance != source) #else if (source == NULL || module_info->module->module_handle != source) #endif // UWP_BINDING { - /*Codes_SRS_BROKER_13_033: [In the loop, the function shall first acquire the lock on BROKER_MODULEINFO::mq_lock.]*/ + /*Codes_SRS_BCAST_BROKER_13_033: [In the loop, the function shall first acquire the lock on BROKER_MODULEINFO::mq_lock.]*/ if (Lock(module_info->mq_lock) != LOCK_OK) { - /*Codes_SRS_BROKER_13_037: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.]*/ + /*Codes_SRS_BCAST_BROKER_13_037: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.]*/ LogError("Lock on module_info->mq_lock for module at item [%p] failed", current_module); result = BROKER_ERROR; } else { - /*Codes_SRS_BROKER_13_034: [The function shall then append message to BROKER_MODULEINFO::mq by calling Message_Clone and VECTOR_push_back.]*/ + /*Codes_SRS_BCAST_BROKER_13_034: [The function shall then append message to BROKER_MODULEINFO::mq by calling Message_Clone and VECTOR_push_back.]*/ MESSAGE_HANDLE msg = Message_Clone(message); if (VECTOR_push_back(module_info->mq, &msg, 1) != 0) { - /*Codes_SRS_BROKER_13_037: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.]*/ + /*Codes_SRS_BCAST_BROKER_13_037: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.]*/ LogError("VECTOR_push_back failed for module at item [%p] failed", current_module); Message_Destroy(msg); Unlock(module_info->mq_lock); @@ -628,15 +639,15 @@ BROKER_RESULT Broker_Publish(BROKER_HANDLE broker, MODULE_HANDLE source, MESSAGE } else { - /*Codes_SRS_BROKER_13_096: [The function shall then signal BROKER_MODULEINFO::mq_cond.]*/ + /*Codes_SRS_BCAST_BROKER_13_096: [The function shall then signal BROKER_MODULEINFO::mq_cond.]*/ if (Condition_Post(module_info->mq_cond) != COND_OK) { - /*Codes_SRS_BROKER_13_037: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.]*/ + /*Codes_SRS_BCAST_BROKER_13_037: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.]*/ LogError("Condition_Post failed for module at item [%p] failed", current_module); result = BROKER_ERROR; } - /*Codes_SRS_BROKER_13_035: [The function shall then release BROKER_MODULEINFO::mq_lock.]*/ + /*Codes_SRS_BCAST_BROKER_13_035: [The function shall then release BROKER_MODULEINFO::mq_lock.]*/ if (Unlock(module_info->mq_lock) != LOCK_OK) { LogError("unable to unlock"); @@ -646,7 +657,7 @@ BROKER_RESULT Broker_Publish(BROKER_HANDLE broker, MODULE_HANDLE source, MESSAGE } } - /*Codes_SRS_BROKER_13_040: [Broker_Publish shall release the lock BROKER_HANDLE_DATA::modules_lock after the loop.]*/ + /*Codes_SRS_BCAST_BROKER_13_040: [Broker_Publish shall release the lock BROKER_HANDLE_DATA::modules_lock after the loop.]*/ Unlock(broker_data->modules_lock); } } diff --git a/core/src/broker.c b/core/src/broker.c index b8db194b..9be74807 100644 --- a/core/src/broker.c +++ b/core/src/broker.c @@ -209,13 +209,13 @@ void Broker_IncRef(BROKER_HANDLE broker) } /** -* This is the worker function that runs for each module. The module_publish_worker +* This is the worker function that runs for each module. The module_worker * function is passed in a pointer to the relevant MODULE_INFO object as it's * thread context parameter. The function's job is to basically wait on the * mq_cond condition variable and process messages in module.mq when the * condition is signaled. */ -static int module_publish_worker(void * user_data) +static int module_worker(void * user_data) { /*Codes_SRS_BROKER_13_026: [This function shall assign `user_data` to a local variable called `module_info` of type `BROKER_MODULEINFO*`.]*/ BROKER_MODULEINFO* module_info = (BROKER_MODULEINFO*)user_data; @@ -226,7 +226,7 @@ static int module_publish_worker(void * user_data) /*Codes_SRS_BROKER_13_089: [ This function shall acquire the lock on module_info->socket_lock. ]*/ if (Lock(module_info->socket_lock)) { - /*Codes_SRS_BROKER_02_004: [ If acquiring the lock fails, then module_publish_worker shall return. ]*/ + /*Codes_SRS_BROKER_02_004: [ If acquiring the lock fails, then module_worker shall return. ]*/ LogError("unable to Lock"); should_continue = 0; break; @@ -240,7 +240,7 @@ static int module_publish_worker(void * user_data) /*Codes_SRS_BROKER_13_091: [ The function shall unlock module_info->socket_lock. ]*/ if (Unlock(module_info->socket_lock) != LOCK_OK) { - /*Codes_SRS_BROKER_17_016: [ If releasing the lock fails, then module_publish_worker shall return. ]*/ + /*Codes_SRS_BROKER_17_016: [ If releasing the lock fails, then module_worker shall return. ]*/ should_continue = 0; if (nbytes > 0) { @@ -266,8 +266,11 @@ static int module_publish_worker(void * user_data) } else { + /*Codes_SRS_BROKER_17_024: [ The function shall strip off the topic from the message. ]*/ + const unsigned char*buf_bytes = (const unsigned char*)buf; + buf_bytes += sizeof(MODULE_HANDLE); /*Codes_SRS_BROKER_17_017: [ The function shall deserialize the message received. ]*/ - MESSAGE_HANDLE msg = Message_CreateFromByteArray((const unsigned char*)buf, nbytes); + MESSAGE_HANDLE msg = Message_CreateFromByteArray(buf_bytes, nbytes - sizeof(MODULE_HANDLE)); /*Codes_SRS_BROKER_17_018: [ If the deserialization is not successful, the message loop shall continue. ]*/ if (msg != NULL) { @@ -388,9 +391,9 @@ static BROKER_RESULT start_module(BROKER_MODULEINFO* module_info, STRING_HANDLE } else { - /* We may want to subscribe to quit message guid, we may have to for topic subscriptions */ + /* Codes_SRS_BROKER_17_028: [ The function shall subscribe BROKER_MODULEINFO::receive_socket to the quit signal GUID. ]*/ if (nn_setsockopt( - module_info->receive_socket, NN_SUB, NN_SUB_SUBSCRIBE, "", 0) < 0) + module_info->receive_socket, NN_SUB, NN_SUB_SUBSCRIBE, STRING_c_str(module_info->quit_message_guid), STRING_length(module_info->quit_message_guid)) < 0) { /*Codes_SRS_BROKER_13_047: [ This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise. ]*/ LogError("nn_setsockopt failed"); @@ -400,10 +403,10 @@ static BROKER_RESULT start_module(BROKER_MODULEINFO* module_info, STRING_HANDLE } else { - /*Codes_SRS_BROKER_13_102: [The function shall create a new thread for the module by calling ThreadAPI_Create using module_publish_worker as the thread callback and using the newly allocated BROKER_MODULEINFO object as the thread context.*/ + /*Codes_SRS_BROKER_13_102: [The function shall create a new thread for the module by calling ThreadAPI_Create using module_worker as the thread callback and using the newly allocated BROKER_MODULEINFO object as the thread context.*/ if (ThreadAPI_Create( &(module_info->thread), - module_publish_worker, + module_worker, (void*)module_info ) != THREADAPI_OK) { @@ -644,6 +647,150 @@ BROKER_RESULT Broker_RemoveModule(BROKER_HANDLE broker, const MODULE* module) return result; } +BROKER_MODULEINFO* broker_locate_handle(BROKER_HANDLE_DATA* broker_data, MODULE_HANDLE handle) +{ + BROKER_MODULEINFO* result; + MODULE module; + module.module_apis = NULL; + module.module_handle = handle; + + LIST_ITEM_HANDLE module_info_item = list_find(broker_data->modules, find_module_predicate, &module); + if (module_info_item == NULL) + { + result = NULL; + } + else + { + result = (BROKER_MODULEINFO*)list_item_get_value(module_info_item); + } + return result; +} + +BROKER_RESULT Broker_AddLink(BROKER_HANDLE broker, const BROKER_LINK_DATA* link) +{ + BROKER_RESULT result; + /*Codes_SRS_BROKER_17_029: [ If broker or link are NULL, Broker_AddLink shall return BROKER_INVALIDARG. ]*/ + if (broker == NULL || link == NULL || link->module_sink_handle == NULL || link->module_source_handle == NULL) + { + LogError("Broker_AddLink, input is NULL."); + result = BROKER_INVALIDARG; + } + else + { + BROKER_HANDLE_DATA* broker_data = (BROKER_HANDLE_DATA*)broker; + /*Codes_SRS_BROKER_17_030: [ Broker_AddLink shall lock the modules_lock. ]*/ + if (Lock(broker_data->modules_lock) != LOCK_OK) + { + /*Codes_SRS_BROKER_17_034: [ Upon an error, Broker_AddLink shall return BROKER_ADD_LINK_ERROR ]*/ + LogError("Broker_AddLink, Lock on broker_data->modules_lock failed"); + result = BROKER_ADD_LINK_ERROR; + } + else + { + /*Codes_SRS_BROKER_17_031: [ Broker_AddLink shall find the BROKER_HANDLE_DATA::module_info for link->sink. ]*/ + BROKER_MODULEINFO* module_info = broker_locate_handle(broker_data, link->module_sink_handle); + + if (module_info == NULL) + { + /*Codes_SRS_BROKER_17_034: [ Upon an error, Broker_AddLink shall return BROKER_ADD_LINK_ERROR ]*/ + LogError("Link->sink is not attached to the broker"); + result = BROKER_ADD_LINK_ERROR; + } + else + { + /*Codes_SRS_BROKER_17_041: [ Broker_AddLink shall find the BROKER_HANDLE_DATA::module_info for link->module_source_handle. ]*/ + BROKER_MODULEINFO* source_module = broker_locate_handle(broker_data, link->module_source_handle); + + if (source_module == NULL) + { + LogError("Link->source is not attached to the broker"); + result = BROKER_ADD_LINK_ERROR; + } + else + { + /*Codes_SRS_BROKER_17_032: [ Broker_AddLink shall subscribe module_info->receive_socket to the link->source module handle. ]*/ + if (nn_setsockopt( + module_info->receive_socket, NN_SUB, NN_SUB_SUBSCRIBE, &(link->module_source_handle), sizeof(MODULE_HANDLE)) < 0) + { + /*Codes_SRS_BROKER_17_034: [ Upon an error, Broker_AddLink shall return BROKER_ADD_LINK_ERROR ]*/ + LogError("Unable to make link in Broker"); + result = BROKER_ADD_LINK_ERROR; + } + else + { + result = BROKER_OK; + } + } + } + /*Codes_SRS_BROKER_17_033: [ Broker_AddLink shall unlock the modules_lock. ]*/ + Unlock(broker_data->modules_lock); + } + } + return result; +} + +BROKER_RESULT Broker_RemoveLink(BROKER_HANDLE broker, const BROKER_LINK_DATA* link) +{ + BROKER_RESULT result; + /*Codes_SRS_BROKER_17_035: [ If broker, link, link->module_source_handle or link->module_sink_handle are NULL, Broker_RemoveLink shall return BROKER_INVALIDARG. ]*/ + if (broker == NULL || link == NULL || link->module_sink_handle == NULL || link->module_source_handle == NULL) + { + LogError("Broker_AddLink, input is NULL."); + result = BROKER_INVALIDARG; + } + else + { + BROKER_HANDLE_DATA* broker_data = (BROKER_HANDLE_DATA*)broker; + /*Codes_SRS_BROKER_17_036: [ Broker_RemoveLink shall lock the modules_lock. ]*/ + if (Lock(broker_data->modules_lock) != LOCK_OK) + { + /*Codes_SRS_BROKER_17_040: [ Upon an error, Broker_RemoveLink shall return BROKER_REMOVE_LINK_ERROR. ]*/ + LogError("Broker_AddLink, Lock on broker_data->modules_lock failed"); + result = BROKER_REMOVE_LINK_ERROR; + } + else + { + /*Codes_SRS_BROKER_17_037: [ Broker_RemoveLink shall find the module_info for link->module_sink_handle. ]*/ + BROKER_MODULEINFO* module_info = broker_locate_handle(broker_data, link->module_sink_handle); + + if (module_info == NULL) + { + /*Codes_SRS_BROKER_17_040: [ Upon an error, Broker_RemoveLink shall return BROKER_REMOVE_LINK_ERROR. ]*/ + LogError("Link->sink is not attached to the broker"); + result = BROKER_REMOVE_LINK_ERROR; + } + else + { + /*Codes_SRS_BROKER_17_042: [ Broker_RemoveLink shall find the module_info for link->module_source_handle. ]*/ + BROKER_MODULEINFO* source_module_info = broker_locate_handle(broker_data, link->module_source_handle); + if (source_module_info == NULL) + { + LogError("Link->source is not attached to the broker"); + result = BROKER_REMOVE_LINK_ERROR; + } + else + { + /*Codes_SRS_BROKER_17_038: [ Broker_RemoveLink shall unsubscribe module_info->receive_socket from the link->module_source_handle module handle. ]*/ + if (nn_setsockopt( + module_info->receive_socket, NN_SUB, NN_SUB_UNSUBSCRIBE, &(link->module_source_handle), sizeof(MODULE_HANDLE)) < 0) + { + /*Codes_SRS_BROKER_17_040: [ Upon an error, Broker_RemoveLink shall return BROKER_REMOVE_LINK_ERROR. ]*/ + LogError("Unable to make link in Broker"); + result = BROKER_REMOVE_LINK_ERROR; + } + else + { + result = BROKER_OK; + } + } + } + /*Codes_SRS_BROKER_17_039: [ Broker_RemoveLink shall unlock the modules_lock. ]*/ + Unlock(broker_data->modules_lock); + } + } + return result; +} + static void broker_decrement_ref(BROKER_HANDLE broker) { /*Codes_SRS_BROKER_13_058: [If `broker` is NULL the function shall do nothing.]*/ @@ -687,10 +834,10 @@ BROKER_RESULT Broker_Publish(BROKER_HANDLE broker, MODULE_HANDLE source, MESSAGE { BROKER_RESULT result; /*Codes_SRS_BROKER_13_030: [If broker or message is NULL the function shall return BROKER_INVALIDARG.]*/ - if (broker == NULL || message == NULL) + if (broker == NULL || source == NULL || message == NULL) { result = BROKER_INVALIDARG; - LogError("Broker handle and/or message handle is NULL"); + LogError("Broker handle, source, and/or message handle is NULL"); } else { @@ -705,6 +852,7 @@ BROKER_RESULT Broker_Publish(BROKER_HANDLE broker, MODULE_HANDLE source, MESSAGE else { int32_t msg_size; + int32_t buf_size; /*Codes_SRS_BROKER_17_007: [ Broker_Publish shall clone the message. ]*/ MESSAGE_HANDLE msg = Message_Clone(message); /*Codes_SRS_BROKER_17_008: [ Broker_Publish shall serialize the message. ]*/ @@ -718,8 +866,9 @@ BROKER_RESULT Broker_Publish(BROKER_HANDLE broker, MODULE_HANDLE source, MESSAGE } else { - /*Codes_SRS_BROKER_17_009: [ Broker_Publish shall allocate a nanomsg buffer and copy the serialized message into it. ]*/ - void* nn_msg = nn_allocmsg(msg_size, 0); + /*Codes_SRS_BROKER_17_025: [ Broker_Publish shall allocate a nanomsg buffer the size of the serialized message + sizeof(MODULE_HANDLE). ]*/ + buf_size = msg_size + sizeof(MODULE_HANDLE); + void* nn_msg = nn_allocmsg(buf_size, 0); if (nn_msg == NULL) { /*Codes_SRS_BROKER_13_053: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.]*/ @@ -728,11 +877,16 @@ BROKER_RESULT Broker_Publish(BROKER_HANDLE broker, MODULE_HANDLE source, MESSAGE } else { - Message_ToByteArray(message, nn_msg, msg_size); + /*Codes_SRS_BROKER_17_026: [ Broker_Publish shall copy source into the beginning of the nanomsg buffer. ]*/ + unsigned char *nn_msg_bytes = (unsigned char *)nn_msg; + memcpy(nn_msg_bytes, &source, sizeof(MODULE_HANDLE)); + /*Codes_SRS_BROKER_17_027: [ Broker_Publish shall serialize the message into the remainder of the nanomsg buffer. ]*/ + nn_msg_bytes += sizeof(MODULE_HANDLE); + Message_ToByteArray(message, nn_msg_bytes, msg_size); /*Codes_SRS_BROKER_17_010: [ Broker_Publish shall send a message on the publish_socket. ]*/ int nbytes = nn_send(broker_data->publish_socket, &nn_msg, NN_MSG, 0); - if (nbytes != msg_size) + if (nbytes != buf_size) { /*Codes_SRS_BROKER_13_053: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.]*/ LogError("unable to send a message [%p]", msg); diff --git a/core/src/gateway_ll.c b/core/src/gateway_ll.c index a0f4f701..cebcfb2c 100644 --- a/core/src/gateway_ll.c +++ b/core/src/gateway_ll.c @@ -43,9 +43,10 @@ typedef struct MODULE_DATA_TAG { } MODULE_DATA; #ifndef UWP_BINDING + typedef struct LINK_DATA_TAG { - MODULE_HANDLE module_source_handle; - MODULE_HANDLE module_sink_handle; + MODULE_DATA* module_source; + MODULE_DATA* module_sink; } LINK_DATA; static MODULE_HANDLE gateway_addmodule_internal(GATEWAY_HANDLE_DATA* gateway_handle, const char* module_path, const void* module_configuration, const char* module_name); @@ -507,7 +508,7 @@ static bool link_data_find(const void* element, const void* linkEntry) { GATEWAY_LINK_ENTRY* link_entry_casted = (GATEWAY_LINK_ENTRY*)linkEntry; - return (strcmp(((MODULE_DATA*)((LINK_DATA*)element)->module_source_handle)->module_name, link_entry_casted->module_source) == 0 && strcmp(((MODULE_DATA*)((LINK_DATA*)element)->module_sink_handle)->module_name, link_entry_casted->module_sink) == 0); + return (strcmp(((MODULE_DATA*)((LINK_DATA*)element)->module_source)->module_name, link_entry_casted->module_source) == 0 && strcmp(((MODULE_DATA*)((LINK_DATA*)element)->module_sink)->module_name, link_entry_casted->module_sink) == 0); } static void gateway_destroy_internal(GATEWAY_HANDLE gw) @@ -527,6 +528,17 @@ static void gateway_destroy_internal(GATEWAY_HANDLE gw) gateway_handle->event_system = NULL; } + if (gateway_handle->links != NULL) + { + /*Codes_SRS_GATEWAY_LL_04_014: [ The function shall remove each link in GATEWAY_HANDLE_DATA's links vector and destroy GATEWAY_HANDLE_DATA's link. ]*/ + while (VECTOR_size(gateway_handle->links) > 0) + { + LINK_DATA* link_data = (LINK_DATA*)VECTOR_front(gateway_handle->links); + gateway_removelink_internal(gateway_handle, link_data); + } + VECTOR_destroy(gateway_handle->links); + } + if (gateway_handle->modules != NULL) { /*Codes_SRS_GATEWAY_LL_14_028: [The function shall remove each module in GATEWAY_HANDLE_DATA's modules vector and destroy GATEWAY_HANDLE_DATA's modules.]*/ @@ -541,17 +553,6 @@ static void gateway_destroy_internal(GATEWAY_HANDLE gw) VECTOR_destroy(gateway_handle->modules); } - if (gateway_handle->links != NULL) - { - /*Codes_SRS_GATEWAY_LL_04_014: [ The function shall remove each link in GATEWAY_HANDLE_DATA's links vector and destroy GATEWAY_HANDLE_DATA's link. ]*/ - while (VECTOR_size(gateway_handle->links) > 0) - { - LINK_DATA* link_data = (LINK_DATA*)VECTOR_front(gateway_handle->links); - gateway_removelink_internal(gateway_handle, link_data); - } - VECTOR_destroy(gateway_handle->links); - } - if (gateway_handle->broker != NULL) { /*Codes_SRS_GATEWAY_LL_14_006: [The function shall destroy the GATEWAY_HANDLE_DATA's `broker` `BROKER_HANDLE`. ]*/ @@ -624,23 +625,36 @@ static bool gateway_addlink_internal(GATEWAY_HANDLE_DATA* gateway_handle, const } else { - //Todo: Add the link to message broker, since it's already validated. - LINK_DATA link_data = + BROKER_LINK_DATA broker_data = { - module_source_handle, - module_sink_handle + module_source_handle->module, + module_sink_handle->module }; - - /*Codes_SRS_GATEWAY_LL_04_012: [ This function shall add the entryLink to the gw->links ] */ - if (VECTOR_push_back(gateway_handle->links, &link_data, 1) != 0) + + if (Broker_AddLink(gateway_handle->broker, &broker_data) != BROKER_OK) { - LogError("Unable to add LINK_DATA* to the gateway links vector."); + LogError("Unable to add link to Broker."); result = false; - //TODO: failed to add link to the links vector, remove it from Message broker when we have this api. } else { - result = true; + LINK_DATA link_data = + { + module_source_handle, + module_sink_handle + }; + + /*Codes_SRS_GATEWAY_LL_04_012: [ This function shall add the entryLink to the gw->links ] */ + if (VECTOR_push_back(gateway_handle->links, &link_data, 1) != 0) + { + LogError("Unable to add LINK_DATA* to the gateway links vector."); + Broker_RemoveLink(gateway_handle->broker, &broker_data); + result = false; + } + else + { + result = true; + } } } } @@ -657,8 +671,15 @@ static bool gateway_addlink_internal(GATEWAY_HANDLE_DATA* gateway_handle, const static void gateway_removelink_internal(GATEWAY_HANDLE_DATA* gateway_handle, LINK_DATA* link_data) { - //TODO: Remove Link from message broker, as soon as the Broker API is in place. /*Codes_SRS_GATEWAY_LL_04_007: [The functional shall remove that LINK_DATA from GATEWAY_HANDLE_DATA's links. ]*/ + BROKER_LINK_DATA broker_data = + { + link_data->module_source->module, + link_data->module_sink->module + }; + + Broker_RemoveLink(gateway_handle->broker, &broker_data); + VECTOR_erase(gateway_handle->links, link_data, 1); } #else diff --git a/core/tests/broadcast_bus_ut/broadcast_bus_ut.cpp b/core/tests/broadcast_bus_ut/broadcast_bus_ut.cpp index 1f806fe8..7155124b 100644 --- a/core/tests/broadcast_bus_ut/broadcast_bus_ut.cpp +++ b/core/tests/broadcast_bus_ut/broadcast_bus_ut.cpp @@ -634,9 +634,9 @@ TEST_FUNCTION_CLEANUP(TestMethodCleanup) } } -//Tests_SRS_BROKER_13_001: [This API shall yield a BROKER_HANDLE representing the newly created message broker. This handle value shall not be equal to NULL when the API call is successful.] -//Tests_SRS_BROKER_13_007: [Broker_Create shall initialize BROKER_HANDLE_DATA::modules with a valid VECTOR_HANDLE.] -//Tests_SRS_BROKER_13_023: [Broker_Create shall initialize BROKER_HANDLE_DATA::modules_lock with a valid LOCK_HANDLE.] +//Tests_SRS_BCAST_BROKER_13_001: [This API shall yield a BROKER_HANDLE representing the newly created message broker. This handle value shall not be equal to NULL when the API call is successful.] +//Tests_SRS_BCAST_BROKER_13_007: [Broker_Create shall initialize BROKER_HANDLE_DATA::modules with a valid VECTOR_HANDLE.] +//Tests_SRS_BCAST_BROKER_13_023: [Broker_Create shall initialize BROKER_HANDLE_DATA::modules_lock with a valid LOCK_HANDLE.] TEST_FUNCTION(Broker_Create_succeeds) { ///arrange @@ -658,8 +658,8 @@ TEST_FUNCTION(Broker_Create_succeeds) Broker_Destroy(r); } -//Tests_SRS_BROKER_13_003: [This function shall return NULL if an underlying API call to the platform causes an error.] -/*Tests_SRS_BROKER_13_067: [ Broker_Create shall malloc a new instance of BROKER_HANDLE_DATA and return NULL if it fails. ]*/ +//Tests_SRS_BCAST_BROKER_13_003: [This function shall return NULL if an underlying API call to the platform causes an error.] +/*Tests_SRS_BCAST_BROKER_13_067: [ Broker_Create shall malloc a new instance of BROKER_HANDLE_DATA and return NULL if it fails. ]*/ TEST_FUNCTION(Broker_Create_fails_when_malloc_fails) { ///arrange @@ -679,7 +679,7 @@ TEST_FUNCTION(Broker_Create_fails_when_malloc_fails) ///cleanup } -//Tests_SRS_BROKER_13_003: [This function shall return NULL if an underlying API call to the platform causes an error.] +//Tests_SRS_BCAST_BROKER_13_003: [This function shall return NULL if an underlying API call to the platform causes an error.] TEST_FUNCTION(Broker_Create_fails_when_list_create_fails) { ///arrange @@ -727,7 +727,7 @@ TEST_FUNCTION(Broker_Create_fails_when_Lock_Init_fails) ///cleanup } -//Tests_SRS_BROKER_99_013: [If `broker` or `module` is `NULL` the function shall return `BROKER_INVALIDARG`.] +//Tests_SRS_BCAST_BROKER_99_013: [If `broker` or `module` is `NULL` the function shall return `BROKER_INVALIDARG`.] TEST_FUNCTION(Broker_AddModule_fails_with_null_broker) { ///arrange @@ -743,7 +743,7 @@ TEST_FUNCTION(Broker_AddModule_fails_with_null_broker) ///cleanup } -//Tests_SRS_BROKER_99_013: [If `broker` or `module` is `NULL` the function shall return `BROKER_INVALIDARG`.] +//Tests_SRS_BCAST_BROKER_99_013: [If `broker` or `module` is `NULL` the function shall return `BROKER_INVALIDARG`.] TEST_FUNCTION(Broker_AddModule_fails_with_null_module) { ///arrange @@ -759,7 +759,7 @@ TEST_FUNCTION(Broker_AddModule_fails_with_null_module) ///cleanup } -//Tests_SRS_BROKER_99_014: [If `module_handle` or `module_apis` are `NULL` the function shall return `BROKER_INVALIDARG`.] +//Tests_SRS_BCAST_BROKER_99_014: [If `module_handle` or `module_apis` are `NULL` the function shall return `BROKER_INVALIDARG`.] TEST_FUNCTION(Broker_AddModule_fails_with_null_module_apis) { ///arrange @@ -781,7 +781,7 @@ TEST_FUNCTION(Broker_AddModule_fails_with_null_module_apis) ///cleanup } -//Tests_SRS_BROKER_99_014: [If `module_handle` or `module_apis` are `NULL` the function shall return `BROKER_INVALIDARG`.] +//Tests_SRS_BCAST_BROKER_99_014: [If `module_handle` or `module_apis` are `NULL` the function shall return `BROKER_INVALIDARG`.] TEST_FUNCTION(Broker_AddModule_fails_with_null_module_handle) { ///arrange @@ -803,7 +803,7 @@ TEST_FUNCTION(Broker_AddModule_fails_with_null_module_handle) ///cleanup } -//Tests_SRS_BROKER_13_047: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.] +//Tests_SRS_BCAST_BROKER_13_047: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.] TEST_FUNCTION(Broker_AddModule_fails_when_alloc_module_info_fails) { ///arrange @@ -859,7 +859,7 @@ TEST_FUNCTION(Broker_AddModule_fails_when_VECTOR_create_fails) Broker_Destroy(broker); } -//Tests_SRS_BROKER_13_047: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.] +//Tests_SRS_BCAST_BROKER_13_047: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.] TEST_FUNCTION(Broker_AddModule_fails_when_Lock_Init_fails) { ///arrange @@ -894,7 +894,7 @@ TEST_FUNCTION(Broker_AddModule_fails_when_Lock_Init_fails) Broker_Destroy(broker); } -//Tests_SRS_BROKER_13_047: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.] +//Tests_SRS_BCAST_BROKER_13_047: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.] TEST_FUNCTION(Broker_AddModule_fails_when_Condition_Init_fails) { ///arrange @@ -932,7 +932,7 @@ TEST_FUNCTION(Broker_AddModule_fails_when_Condition_Init_fails) Broker_Destroy(broker); } -//Tests_SRS_BROKER_13_047: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.] +//Tests_SRS_BCAST_BROKER_13_047: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.] TEST_FUNCTION(Broker_AddModule_fails_when_list_add_fails) { ///arrange @@ -978,7 +978,7 @@ TEST_FUNCTION(Broker_AddModule_fails_when_list_add_fails) Broker_Destroy(broker); } -//Tests_SRS_BROKER_13_047: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.] +//Tests_SRS_BCAST_BROKER_13_047: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.] TEST_FUNCTION(Broker_AddModule_fails_when_ThreadAPI_Create_fails) { ///arrange @@ -1028,7 +1028,7 @@ TEST_FUNCTION(Broker_AddModule_fails_when_ThreadAPI_Create_fails) Broker_Destroy(broker); } -//Tests_SRS_BROKER_13_047: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.] +//Tests_SRS_BCAST_BROKER_13_047: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.] TEST_FUNCTION(Broker_AddModule_fails_when_lock_on_modules_lock_fails) { ///arrange @@ -1072,16 +1072,16 @@ TEST_FUNCTION(Broker_AddModule_fails_when_lock_on_modules_lock_fails) -//Tests_SRS_BROKER_13_107 : [The function shall assign the module handle to BROKER_MODULEINFO::module.] -//Tests_SRS_BROKER_13_098 : [The function shall initialize BROKER_MODULEINFO::mq with a valid vector handle.] -//Tests_SRS_BROKER_13_099 : [The function shall initialize BROKER_MODULEINFO::mq_lock with a valid lock handle.] -//Tests_SRS_BROKER_13_100 : [The function shall initialize BROKER_MODULEINFO::mq_cond with a valid condition handle.] -//Tests_SRS_BROKER_13_101 : [ The function shall assign 0 to BROKER_MODULEINFO::quit_worker. ] -//Tests_SRS_BROKER_13_102 : [The function shall create a new thread for the module by calling ThreadAPI_Create using module_publish_worker as the thread callback and using the newly allocated BROKER_MODULEINFO object as the thread context.] -//Tests_SRS_BROKER_13_039 : [This function shall acquire the lock on BROKER_HANDLE_DATA::modules_lock.] -//Tests_SRS_BROKER_13_045 : [Broker_AddModule shall append the new instance of BROKER_MODULEINFO to BROKER_HANDLE_DATA::modules.] -//Tests_SRS_BROKER_13_046 : [This function shall release the lock on BROKER_HANDLE_DATA::modules_lock.] -//Tests_SRS_BROKER_13_047 : [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.] +//Tests_SRS_BCAST_BROKER_13_107 : [The function shall assign the module handle to BROKER_MODULEINFO::module.] +//Tests_SRS_BCAST_BROKER_13_098 : [The function shall initialize BROKER_MODULEINFO::mq with a valid vector handle.] +//Tests_SRS_BCAST_BROKER_13_099 : [The function shall initialize BROKER_MODULEINFO::mq_lock with a valid lock handle.] +//Tests_SRS_BCAST_BROKER_13_100 : [The function shall initialize BROKER_MODULEINFO::mq_cond with a valid condition handle.] +//Tests_SRS_BCAST_BROKER_13_101 : [ The function shall assign 0 to BROKER_MODULEINFO::quit_worker. ] +//Tests_SRS_BCAST_BROKER_13_102 : [The function shall create a new thread for the module by calling ThreadAPI_Create using module_publish_worker as the thread callback and using the newly allocated BROKER_MODULEINFO object as the thread context.] +//Tests_SRS_BCAST_BROKER_13_039 : [This function shall acquire the lock on BROKER_HANDLE_DATA::modules_lock.] +//Tests_SRS_BCAST_BROKER_13_045 : [Broker_AddModule shall append the new instance of BROKER_MODULEINFO to BROKER_HANDLE_DATA::modules.] +//Tests_SRS_BCAST_BROKER_13_046 : [This function shall release the lock on BROKER_HANDLE_DATA::modules_lock.] +//Tests_SRS_BCAST_BROKER_13_047 : [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.] TEST_FUNCTION(Broker_AddModule_succeeds) { ///arrange @@ -1154,18 +1154,18 @@ static COND_RESULT module_publish_worker_calls_module_receive_Condition_Wait(voi return COND_OK; } -// Tests_SRS_BROKER_13_089: [ This function shall acquire the lock on module_info->mq_lock. ] -// Tests_SRS_BROKER_13_068: [ This function shall run a loop that keeps running while module_info->quit_worker is equal to 0. ] -// Tests_SRS_BROKER_13_071: [ For every iteration of the loop the function will first wait on module_info->mq_cond using module_info->mq_lock as the corresponding mutex to be used by the condition variable. ] -// Tests_SRS_BROKER_13_090: [ When module_info->mq_cond has been signaled this function shall kick off another loop predicated on module_info->quit_worker being equal to 0 and module_info->mq not being empty. This thread has the lock on module_info->mq_lock at this point. ] -// Tests_SRS_BROKER_13_069: [ The function shall dequeue a message from the module's message queue. ] -// Tests_SRS_BROKER_13_091: [ The function shall unlock module_info->mq_lock. ] -// Tests_SRS_BROKER_13_092: [ The function shall deliver the message to the module's callback function via module_info->module_apis. ] -// Tests_SRS_BROKER_13_093: [ The function shall destroy the message that was dequeued by calling Message_Destroy. ] -// Tests_SRS_BROKER_13_094: [ The function shall re-acquire the lock on module_info->mq_lock. ] -// Tests_SRS_BROKER_13_095: [ When the function exits the outer loop predicated on module_info->quit_worker being 0 it shall unlock module_info->mq_lock before exiting from the function. ] -// Tests_SRS_BROKER_13_026: [ This function shall assign user_data to a local variable called module_info of type BROKER_MODULEINFO*. ] -// Tests_SRS_BROKER_04_001: [** This function shall immediately start processing messages when `module->mq` is not empty without waiting on `module->mq_cond`.] +// Tests_SRS_BCAST_BROKER_13_089: [ This function shall acquire the lock on module_info->mq_lock. ] +// Tests_SRS_BCAST_BROKER_13_068: [ This function shall run a loop that keeps running while module_info->quit_worker is equal to 0. ] +// Tests_SRS_BCAST_BROKER_13_071: [ For every iteration of the loop the function will first wait on module_info->mq_cond using module_info->mq_lock as the corresponding mutex to be used by the condition variable. ] +// Tests_SRS_BCAST_BROKER_13_090: [ When module_info->mq_cond has been signaled this function shall kick off another loop predicated on module_info->quit_worker being equal to 0 and module_info->mq not being empty. This thread has the lock on module_info->mq_lock at this point. ] +// Tests_SRS_BCAST_BROKER_13_069: [ The function shall dequeue a message from the module's message queue. ] +// Tests_SRS_BCAST_BROKER_13_091: [ The function shall unlock module_info->mq_lock. ] +// Tests_SRS_BCAST_BROKER_13_092: [ The function shall deliver the message to the module's callback function via module_info->module_apis. ] +// Tests_SRS_BCAST_BROKER_13_093: [ The function shall destroy the message that was dequeued by calling Message_Destroy. ] +// Tests_SRS_BCAST_BROKER_13_094: [ The function shall re-acquire the lock on module_info->mq_lock. ] +// Tests_SRS_BCAST_BROKER_13_095: [ When the function exits the outer loop predicated on module_info->quit_worker being 0 it shall unlock module_info->mq_lock before exiting from the function. ] +// Tests_SRS_BCAST_BROKER_13_026: [ This function shall assign user_data to a local variable called module_info of type BROKER_MODULEINFO*. ] +// Tests_SRS_BCAST_BROKER_04_001: [** This function shall immediately start processing messages when `module->mq` is not empty without waiting on `module->mq_cond`.] TEST_FUNCTION(module_publish_worker_calls_module_receive) { /** @@ -1327,7 +1327,7 @@ TEST_FUNCTION(module_publish_worker_calls_module_receive) Broker_Destroy(broker); } -/*Tests_SRS_BROKER_02_004: [ If acquiring the lock fails, then module_publish_worker shall return. ]*/ +/*Tests_SRS_BCAST_BROKER_02_004: [ If acquiring the lock fails, then module_publish_worker shall return. ]*/ TEST_FUNCTION(module_publish_worker_fails_when_first_lock_fails) { ///arrange @@ -1381,7 +1381,7 @@ TEST_FUNCTION(module_publish_worker_fails_when_first_lock_fails) } -// Tests_SRS_BROKER_04_001: [** This function shall immediately start processing messages when `module->mq` is not empty without waiting on `module->mq_cond`.] +// Tests_SRS_BCAST_BROKER_04_001: [** This function shall immediately start processing messages when `module->mq` is not empty without waiting on `module->mq_cond`.] TEST_FUNCTION(module_publish_worker_clean_message_queue_before_waiting_for_condition) { //This test follow the same guideline of test: module_publish_worker_calls_module_receive, with the exception that @@ -1505,7 +1505,7 @@ TEST_FUNCTION(module_publish_worker_clean_message_queue_before_waiting_for_condi } -//Tests_SRS_BROKER_13_048: [If broker or module is NULL the function shall return BROKER_INVALIDARG.] +//Tests_SRS_BCAST_BROKER_13_048: [If broker or module is NULL the function shall return BROKER_INVALIDARG.] TEST_FUNCTION(Broker_RemoveModule_fails_with_null_broker) { ///arrange @@ -1521,7 +1521,7 @@ TEST_FUNCTION(Broker_RemoveModule_fails_with_null_broker) ///cleanup } -//Tests_SRS_BROKER_13_048: [If broker or module is NULL the function shall return BROKER_INVALIDARG.] +//Tests_SRS_BCAST_BROKER_13_048: [If broker or module is NULL the function shall return BROKER_INVALIDARG.] TEST_FUNCTION(Broker_RemoveModule_fails_with_null_module) { ///arrange @@ -1537,7 +1537,7 @@ TEST_FUNCTION(Broker_RemoveModule_fails_with_null_module) ///cleanup } -//Tests_SRS_BROKER_13_053: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.] +//Tests_SRS_BCAST_BROKER_13_053: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.] TEST_FUNCTION(Broker_RemoveModule_fails_when_Lock_fails) { ///arrange @@ -1563,7 +1563,7 @@ TEST_FUNCTION(Broker_RemoveModule_fails_when_Lock_fails) Broker_Destroy(broker); } -//Tests_SRS_BROKER_13_050: [Broker_RemoveModule shall unlock BROKER_HANDLE_DATA::modules_lock and return BROKER_ERROR if the module is not found in BROKER_HANDLE_DATA::modules.] +//Tests_SRS_BCAST_BROKER_13_050: [Broker_RemoveModule shall unlock BROKER_HANDLE_DATA::modules_lock and return BROKER_ERROR if the module is not found in BROKER_HANDLE_DATA::modules.] TEST_FUNCTION(Broker_RemoveModule_fails_when_list_find_fails) { ///arrange @@ -1594,8 +1594,8 @@ TEST_FUNCTION(Broker_RemoveModule_fails_when_list_find_fails) Broker_Destroy(broker); } -/*Tests_SRS_BROKER_02_002: [ If locking fails, then terminating the thread shall not be attempted (signalling the condition and joining the thread). ]*/ -//Tests_SRS_BROKER_13_050: [Broker_RemoveModule shall unlock BROKER_HANDLE_DATA::modules_lock and return BROKER_ERROR if the module is not found in BROKER_HANDLE_DATA::modules.] +/*Tests_SRS_BCAST_BROKER_02_002: [ If locking fails, then terminating the thread shall not be attempted (signalling the condition and joining the thread). ]*/ +//Tests_SRS_BCAST_BROKER_13_050: [Broker_RemoveModule shall unlock BROKER_HANDLE_DATA::modules_lock and return BROKER_ERROR if the module is not found in BROKER_HANDLE_DATA::modules.] TEST_FUNCTION(Broker_RemoveModule_fails_when_lock_mq_lock_fails) { { @@ -1649,18 +1649,18 @@ TEST_FUNCTION(Broker_RemoveModule_fails_when_lock_mq_lock_fails) Broker_Destroy(broker); } } -//Tests_SRS_BROKER_13_088 : [This function shall acquire the lock on BROKER_HANDLE_DATA::modules_lock.] -//Tests_SRS_BROKER_13_049 : [Broker_RemoveModule shall perform a linear search for module in BROKER_HANDLE_DATA::modules.] -//Tests_SRS_BROKER_13_050 : [Broker_RemoveModule shall unlock BROKER_HANDLE_DATA::modules_lock and return BROKER_ERROR if the module is not found in BROKER_HANDLE_DATA::modules.] -//Tests_SRS_BROKER_13_052 : [The function shall remove the module from BROKER_HANDLE_DATA::modules.] -//Tests_SRS_BROKER_13_054 : [This function shall release the lock on BROKER_HANDLE_DATA::modules_lock.] -/*Tests_SRS_BROKER_02_001: [ Broker_RemoveModule shall lock `BROKER_MODULEINFO::mq_lock`. ]*/ -/*Tests_SRS_BROKER_02_003: [ After signaling the condition, Broker_RemoveModule shall unlock BROKER_MODULEINFO::mq_lock. ]*/ -//Tests_SRS_BROKER_13_103 : [The function shall assign 1 to BROKER_MODULEINFO::quit_worker.] -//Tests_SRS_BROKER_17_001: [The function shall signal BROKER_MODULEINFO::mq_cond to release module from waiting.] -//Tests_SRS_BROKER_13_104 : [The function shall wait for the module's thread to exit by joining BROKER_MODULEINFO::thread via ThreadAPI_Join. ] -//Tests_SRS_BROKER_13_057 : [The function shall free all members of the BROKER_MODULEINFO object.] -//Tests_SRS_BROKER_13_053 : [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.] +//Tests_SRS_BCAST_BROKER_13_088 : [This function shall acquire the lock on BROKER_HANDLE_DATA::modules_lock.] +//Tests_SRS_BCAST_BROKER_13_049 : [Broker_RemoveModule shall perform a linear search for module in BROKER_HANDLE_DATA::modules.] +//Tests_SRS_BCAST_BROKER_13_050 : [Broker_RemoveModule shall unlock BROKER_HANDLE_DATA::modules_lock and return BROKER_ERROR if the module is not found in BROKER_HANDLE_DATA::modules.] +//Tests_SRS_BCAST_BROKER_13_052 : [The function shall remove the module from BROKER_HANDLE_DATA::modules.] +//Tests_SRS_BCAST_BROKER_13_054 : [This function shall release the lock on BROKER_HANDLE_DATA::modules_lock.] +/*Tests_SRS_BCAST_BROKER_02_001: [ Broker_RemoveModule shall lock `BROKER_MODULEINFO::mq_lock`. ]*/ +/*Tests_SRS_BCAST_BROKER_02_003: [ After signaling the condition, Broker_RemoveModule shall unlock BROKER_MODULEINFO::mq_lock. ]*/ +//Tests_SRS_BCAST_BROKER_13_103 : [The function shall assign 1 to BROKER_MODULEINFO::quit_worker.] +//Tests_SRS_BCAST_BROKER_17_001: [The function shall signal BROKER_MODULEINFO::mq_cond to release module from waiting.] +//Tests_SRS_BCAST_BROKER_13_104 : [The function shall wait for the module's thread to exit by joining BROKER_MODULEINFO::thread via ThreadAPI_Join. ] +//Tests_SRS_BCAST_BROKER_13_057 : [The function shall free all members of the BROKER_MODULEINFO object.] +//Tests_SRS_BCAST_BROKER_13_053 : [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.] TEST_FUNCTION(Broker_RemoveModule_succeeds) { ///arrange @@ -1717,7 +1717,39 @@ TEST_FUNCTION(Broker_RemoveModule_succeeds) Broker_Destroy(broker); } -/*Tests_SRS_BROKER_13_056: [If BROKER_MODULEINFO::mq is not empty then this function shall call Message_Destroy on every message still left in the collection.]*/ +//Tests_SRS_BCAST_BROKER_17_003: [ Broker_AddLink shall return BROKER_OK. ] +TEST_FUNCTION(Broker_AddLink_Returns_OK) +{ + ///arrange + CBrokerMocks mocks; + + ///act + auto r1 = Broker_AddLink(NULL, NULL); + + ///assert + ASSERT_ARE_EQUAL(BROKER_RESULT, r1, BROKER_OK); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup +} + +//Tests_SRS_BCAST_BROKER_17_004: [ Broker_RemoveLink shall return BROKER_OK. ] +TEST_FUNCTION(Broker_RemoveLink_Returns_OK) +{ + ///arrange + CBrokerMocks mocks; + + ///act + auto r1 = Broker_RemoveLink(NULL, NULL); + + ///assert + ASSERT_ARE_EQUAL(BROKER_RESULT, r1, BROKER_OK); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup +} + +/*Tests_SRS_BCAST_BROKER_13_056: [If BROKER_MODULEINFO::mq is not empty then this function shall call Message_Destroy on every message still left in the collection.]*/ TEST_FUNCTION(Broker_RemoveModule_with_msg_succeeds) { ///arrange @@ -1783,7 +1815,7 @@ TEST_FUNCTION(Broker_RemoveModule_with_msg_succeeds) Broker_Destroy(broker); } -//Tests_SRS_BROKER_13_108: [If broker is NULL then Broker_IncRef shall do nothing.] +//Tests_SRS_BCAST_BROKER_13_108: [If broker is NULL then Broker_IncRef shall do nothing.] TEST_FUNCTION(Broker_IncRef_does_nothing_with_null_input) { ///arrange @@ -1798,7 +1830,7 @@ TEST_FUNCTION(Broker_IncRef_does_nothing_with_null_input) ///cleanup } -//Tests_SRS_BROKER_13_109: [Otherwise, `Broker_IncRef` shall increment the internal ref count.] +//Tests_SRS_BCAST_BROKER_13_109: [Otherwise, `Broker_IncRef` shall increment the internal ref count.] TEST_FUNCTION(Broker_IncRef_increments_ref_count_1) { ///arrange @@ -1817,7 +1849,7 @@ TEST_FUNCTION(Broker_IncRef_increments_ref_count_1) Broker_Destroy(broker); } -//Tests_SRS_BROKER_13_111: [ Otherwise, Broker_Destroy shall decrement the internal ref count of the message. ] +//Tests_SRS_BCAST_BROKER_13_111: [ Otherwise, Broker_Destroy shall decrement the internal ref count of the message. ] TEST_FUNCTION(Broker_IncRef_increments_ref_count_1_destroy) { ///arrange @@ -1836,7 +1868,7 @@ TEST_FUNCTION(Broker_IncRef_increments_ref_count_1_destroy) Broker_Destroy(broker); } -//Tests_SRS_BROKER_13_058: [If broker is NULL the function shall do nothing.] +//Tests_SRS_BCAST_BROKER_13_058: [If broker is NULL the function shall do nothing.] TEST_FUNCTION(Broker_Destroy_does_nothing_with_null_input) { ///arrange @@ -1851,7 +1883,7 @@ TEST_FUNCTION(Broker_Destroy_does_nothing_with_null_input) ///cleanup } -//Tests_SRS_BROKER_13_058: [If broker is NULL the function shall do nothing.] +//Tests_SRS_BCAST_BROKER_13_058: [If broker is NULL the function shall do nothing.] TEST_FUNCTION(Broker_DecRef_does_nothing_with_null_input) { ///arrange @@ -1866,7 +1898,7 @@ TEST_FUNCTION(Broker_DecRef_does_nothing_with_null_input) ///cleanup } -//Tests_SRS_BROKER_13_112: [If the ref count is zero then the allocated resources are freed.] +//Tests_SRS_BCAST_BROKER_13_112: [If the ref count is zero then the allocated resources are freed.] TEST_FUNCTION(Broker_Destroy_works) { ///arrange @@ -1893,8 +1925,8 @@ TEST_FUNCTION(Broker_Destroy_works) ///cleanup } -//Tests_SRS_BROKER_13_112: [If the ref count is zero then the allocated resources are freed.] -//Tests_SRS_BROKER_13_113: [ This function shall implement all the requirements of the Broker_Destroy API. ] +//Tests_SRS_BCAST_BROKER_13_112: [If the ref count is zero then the allocated resources are freed.] +//Tests_SRS_BCAST_BROKER_13_113: [ This function shall implement all the requirements of the Broker_Destroy API. ] TEST_FUNCTION(Broker_DecRef_works) { ///arrange @@ -1921,7 +1953,7 @@ TEST_FUNCTION(Broker_DecRef_works) ///cleanup } -//Tests_SRS_BROKER_13_030: [If broker or message is NULL the function shall return BROKER_INVALIDARG.] +//Tests_SRS_BCAST_BROKER_13_030: [If broker or message is NULL the function shall return BROKER_INVALIDARG.] TEST_FUNCTION(Broker_Publish_fails_with_null_broker) { ///arrange @@ -1937,7 +1969,7 @@ TEST_FUNCTION(Broker_Publish_fails_with_null_broker) ///cleanup } -//Tests_SRS_BROKER_13_030: [If broker or message is NULL the function shall return BROKER_INVALIDARG.] +//Tests_SRS_BCAST_BROKER_13_030: [If broker or message is NULL the function shall return BROKER_INVALIDARG.] TEST_FUNCTION(Broker_Publish_fails_with_null_message) { ///arrange @@ -1953,7 +1985,7 @@ TEST_FUNCTION(Broker_Publish_fails_with_null_message) ///cleanup } -//Tests_SRS_BROKER_13_037: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.] +//Tests_SRS_BCAST_BROKER_13_037: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.] TEST_FUNCTION(Broker_Publish_fails_when_lock_on_modules_lock_fails) { ///arrange @@ -1985,7 +2017,7 @@ TEST_FUNCTION(Broker_Publish_fails_when_lock_on_modules_lock_fails) Broker_Destroy(broker); } -//Tests_SRS_BROKER_13_037: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.] +//Tests_SRS_BCAST_BROKER_13_037: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.] TEST_FUNCTION(Broker_Publish_fails_when_lock_on_module_mq_lock_fails) { ///arrange @@ -2030,7 +2062,7 @@ TEST_FUNCTION(Broker_Publish_fails_when_lock_on_module_mq_lock_fails) Broker_Destroy(broker); } -//Tests_SRS_BROKER_13_037: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.] +//Tests_SRS_BCAST_BROKER_13_037: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.] TEST_FUNCTION(Broker_Publish_fails_when_vector_push_back_fails) { ///arrange @@ -2084,7 +2116,7 @@ TEST_FUNCTION(Broker_Publish_fails_when_vector_push_back_fails) Broker_Destroy(broker); } -//Tests_SRS_BROKER_13_037: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.] +//Tests_SRS_BCAST_BROKER_13_037: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.] TEST_FUNCTION(Broker_Publish_fails_when_vector_condition_post_fails) { ///arrange @@ -2138,14 +2170,14 @@ TEST_FUNCTION(Broker_Publish_fails_when_vector_condition_post_fails) Broker_Destroy(broker); } -//Tests_SRS_BROKER_13_031: [Broker_Publish shall acquire the lock BROKER_HANDLE_DATA::modules_lock.] -//Tests_SRS_BROKER_13_032: [ Broker_Publish shall start a processing loop for every module in BROKER_HANDLE_DATA::modules. ] -//Tests_SRS_BROKER_13_033 : [In the loop, the function shall first acquire the lock on BROKER_MODULEINFO::mq_lock.] -//Tests_SRS_BROKER_13_034 : [The function shall then append message to BROKER_MODULEINFO::mq by calling Message_Clone and VECTOR_push_back.] -//Tests_SRS_BROKER_13_035 : [The function shall then release BROKER_MODULEINFO::mq_lock.] -//Tests_SRS_BROKER_13_096 : [The function shall then signal BROKER_MODULEINFO::mq_cond.] -//Tests_SRS_BROKER_13_040 : [Broker_Publish shall release the lock BROKER_HANDLE_DATA::modules_lock after the loop.] -//Tests_SRS_BROKER_13_037 : [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.] +//Tests_SRS_BCAST_BROKER_13_031: [Broker_Publish shall acquire the lock BROKER_HANDLE_DATA::modules_lock.] +//Tests_SRS_BCAST_BROKER_13_032: [ Broker_Publish shall start a processing loop for every module in BROKER_HANDLE_DATA::modules. ] +//Tests_SRS_BCAST_BROKER_13_033 : [In the loop, the function shall first acquire the lock on BROKER_MODULEINFO::mq_lock.] +//Tests_SRS_BCAST_BROKER_13_034 : [The function shall then append message to BROKER_MODULEINFO::mq by calling Message_Clone and VECTOR_push_back.] +//Tests_SRS_BCAST_BROKER_13_035 : [The function shall then release BROKER_MODULEINFO::mq_lock.] +//Tests_SRS_BCAST_BROKER_13_096 : [The function shall then signal BROKER_MODULEINFO::mq_cond.] +//Tests_SRS_BCAST_BROKER_13_040 : [Broker_Publish shall release the lock BROKER_HANDLE_DATA::modules_lock after the loop.] +//Tests_SRS_BCAST_BROKER_13_037 : [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.] TEST_FUNCTION(Broker_Publish_succeeds) { ///arrange @@ -2198,7 +2230,7 @@ TEST_FUNCTION(Broker_Publish_succeeds) Broker_Destroy(broker); } -//Tests_SRS_BROKER_17_002: [ If source is not NULL, Broker_Publish shall not publish the message to the BROKER_MODULEINFO::module which matches source. ] +//Tests_SRS_BCAST_BROKER_17_002: [ If source is not NULL, Broker_Publish shall not publish the message to the BROKER_MODULEINFO::module which matches source. ] TEST_FUNCTION(Broker_Publish_succeeds_skips_self) { ///arrange diff --git a/core/tests/broker_ut/broker_ut.cpp b/core/tests/broker_ut/broker_ut.cpp index 62e54caa..4d0fa0a2 100644 --- a/core/tests/broker_ut/broker_ut.cpp +++ b/core/tests/broker_ut/broker_ut.cpp @@ -104,8 +104,11 @@ typedef struct LIST_INSTANCE_TAG LIST_ITEM_INSTANCE* head; } LIST_INSTANCE; -static size_t current_list_index; -static const void *fake_list[10]; +struct ListNode +{ + const void* item; + ListNode *next, *prev; +}; static int current_nn_socket_index; static void* nn_socket_memory[10]; @@ -389,13 +392,19 @@ TYPED_MOCK_CLASS(CBrokerMocks, CGlobalMock) } else { - result1 = (LIST_HANDLE)(new RefCountObject()); + result1 = (LIST_HANDLE)new ListNode(); } MOCK_METHOD_END(LIST_HANDLE, result1) MOCK_STATIC_METHOD_1(, void, list_destroy, LIST_HANDLE, list) - ((RefCountObject*)list)->dec_ref(); - MOCK_VOID_METHOD_END() + ListNode *current = (ListNode*)list; + while (current != nullptr) + { + auto tmp = current; + current = current->next; + delete tmp; + } + MOCK_VOID_METHOD_END() MOCK_STATIC_METHOD_2(, LIST_ITEM_HANDLE, list_add, LIST_HANDLE, list, const void*, item) LIST_ITEM_HANDLE result1; @@ -413,8 +422,15 @@ TYPED_MOCK_CLASS(CBrokerMocks, CGlobalMock) } else { - fake_list[current_list_index++] = item; - result1 = (LIST_ITEM_HANDLE)item; + ListNode *new_item = new ListNode(); + new_item->item = item; + ListNode *real_list = (ListNode*)list; + ListNode *ptr = real_list; + while (ptr->next != nullptr) + ptr = ptr->next; + ptr->next = new_item; + new_item->prev = ptr; + result1 = (LIST_ITEM_HANDLE)new_item; } } MOCK_METHOD_END(LIST_ITEM_HANDLE, result1) @@ -428,8 +444,12 @@ TYPED_MOCK_CLASS(CBrokerMocks, CGlobalMock) } else { - /* do I need anything more compicated here? */ - result2 = 0; + ListNode *node = (ListNode*)item; + node->prev->next = node->next; + if (node->next != nullptr) + node->next->prev = node->prev; + delete node; + result = 0; } MOCK_METHOD_END(int, result2) @@ -442,8 +462,9 @@ TYPED_MOCK_CLASS(CBrokerMocks, CGlobalMock) } else { - result1 = (LIST_ITEM_HANDLE)fake_list[0]; - } + ListNode* my_result = NULL; + result1 = (LIST_ITEM_HANDLE)(((ListNode*)list)->next); + } MOCK_METHOD_END(LIST_ITEM_HANDLE, result1) MOCK_STATIC_METHOD_1(, LIST_ITEM_HANDLE, list_get_next_item, LIST_ITEM_HANDLE, item_handle) @@ -454,7 +475,7 @@ TYPED_MOCK_CLASS(CBrokerMocks, CGlobalMock) } else { - result1 = (LIST_ITEM_HANDLE)(fake_list[current_list_index]); + result1 = (LIST_ITEM_HANDLE)(((ListNode*)item_handle)->next); } MOCK_METHOD_END(LIST_ITEM_HANDLE, result1) @@ -472,21 +493,17 @@ TYPED_MOCK_CLASS(CBrokerMocks, CGlobalMock) { result1 = NULL; } - else if ((void*)&fake_module == (void*)match_context) - { - result1 = (LIST_ITEM_HANDLE)fake_list[0]; - } else { - result1 = NULL; - for (size_t i = 0; i < current_list_index; i++) - { - if ((void*)fake_list[i] == (void*)match_context) - { - result1 = (LIST_ITEM_HANDLE)fake_list[i]; - break; - } - } + result1 = (LIST_ITEM_HANDLE)(((ListNode*)list)->next); + while (result1) + { + if (match_function(result1, match_context)) + { + break; + } + result1 = (LIST_ITEM_HANDLE)(((ListNode*)result1)->next); + } } } MOCK_METHOD_END(LIST_ITEM_HANDLE, result1) @@ -499,7 +516,7 @@ TYPED_MOCK_CLASS(CBrokerMocks, CGlobalMock) } else { - result1 = item_handle; + result1 = (LIST_ITEM_HANDLE)(((ListNode*)item_handle)->item); } MOCK_METHOD_END(const void*, result1) @@ -519,6 +536,9 @@ TYPED_MOCK_CLASS(CBrokerMocks, CGlobalMock) MOCK_STATIC_METHOD_1(, const char*, STRING_c_str, STRING_HANDLE, s) MOCK_METHOD_END(const char*, BASEIMPLEMENTATION::STRING_c_str(s)) + MOCK_STATIC_METHOD_1(, size_t, STRING_length, STRING_HANDLE, s) + MOCK_METHOD_END(size_t, BASEIMPLEMENTATION::STRING_length(s)) + MOCK_STATIC_METHOD_2(, UNIQUEID_RESULT, UniqueId_Generate, char*, uid, size_t, bufferSize) for (int i = 0; i < (int)bufferSize; i++) { @@ -532,7 +552,7 @@ TYPED_MOCK_CLASS(CBrokerMocks, CGlobalMock) MOCK_STATIC_METHOD_2(, void *, nn_allocmsg, size_t, size, int, type) nn_current_msg_size = size; - MOCK_METHOD_END(void*, malloc(1)) + MOCK_METHOD_END(void*, malloc(size)) MOCK_STATIC_METHOD_1(, int, nn_freemsg, void*, msg) free(msg); @@ -633,6 +653,8 @@ DECLARE_GLOBAL_MOCK_METHOD_1(CBrokerMocks, , void, STRING_delete, STRING_HANDLE, DECLARE_GLOBAL_MOCK_METHOD_1(CBrokerMocks, , STRING_HANDLE, STRING_construct, const char*, source) DECLARE_GLOBAL_MOCK_METHOD_2(CBrokerMocks, , int, STRING_concat, STRING_HANDLE, s1, const char*, s2) DECLARE_GLOBAL_MOCK_METHOD_1(CBrokerMocks, , const char*, STRING_c_str, STRING_HANDLE, s) +DECLARE_GLOBAL_MOCK_METHOD_1(CBrokerMocks, , size_t, STRING_length, STRING_HANDLE, s) + // unique id DECLARE_GLOBAL_MOCK_METHOD_2(CBrokerMocks, , UNIQUEID_RESULT, UniqueId_Generate, char*, uid, size_t, bufferSize) DECLARE_GLOBAL_MOCK_METHOD_2(CBrokerMocks, , void *, nn_allocmsg, size_t, size, int, type) @@ -706,11 +728,6 @@ TEST_FUNCTION_INITIALIZE(TestMethodInitialize) currentThreadAPI_Create_call = 0; whenShallThreadAPI_Create_fail = 0; - current_list_index = 0; - for (int l = 0; l < 10; l++) - { - fake_list[l] = NULL; - } current_nn_socket_index = 0; for (int l = 0; l < 10; l++) { @@ -1495,7 +1512,11 @@ TEST_FUNCTION(Broker_AddModule_fails_when_nn_setSocketOpts_fails) .IgnoreArgument(1); STRICT_EXPECTED_CALL(mocks, nn_connect(IGNORED_NUM_ARG, IGNORED_PTR_ARG)) .IgnoreAllArguments(); - STRICT_EXPECTED_CALL(mocks, nn_setsockopt(IGNORED_NUM_ARG, NN_SUB, NN_SUB_SUBSCRIBE, "", 0)) + STRICT_EXPECTED_CALL(mocks, STRING_c_str(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, STRING_length(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, nn_setsockopt(IGNORED_NUM_ARG, NN_SUB, NN_SUB_SUBSCRIBE, IGNORED_PTR_ARG, 36)) .IgnoreArgument(1) .IgnoreArgument(4) .SetFailReturn(-1); @@ -1552,7 +1573,11 @@ TEST_FUNCTION(Broker_AddModule_fails_when_ThreadAPI_Create_fails) .IgnoreArgument(1); STRICT_EXPECTED_CALL(mocks, nn_connect(IGNORED_NUM_ARG, IGNORED_PTR_ARG)) .IgnoreAllArguments(); - STRICT_EXPECTED_CALL(mocks, nn_setsockopt(IGNORED_NUM_ARG, NN_SUB, NN_SUB_SUBSCRIBE, "", 0)) + STRICT_EXPECTED_CALL(mocks, STRING_c_str(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, STRING_length(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, nn_setsockopt(IGNORED_NUM_ARG, NN_SUB, NN_SUB_SUBSCRIBE, IGNORED_PTR_ARG, 36)) .IgnoreArgument(1) .IgnoreArgument(4); STRICT_EXPECTED_CALL(mocks, nn_close(IGNORED_NUM_ARG)) @@ -1584,6 +1609,7 @@ TEST_FUNCTION(Broker_AddModule_fails_when_ThreadAPI_Create_fails) //Tests_SRS_BROKER_13_045 : [Broker_AddModule shall append the new instance of BROKER_MODULEINFO to BROKER_HANDLE_DATA::modules.] //Tests_SRS_BROKER_13_046 : [This function shall release the lock on BROKER_HANDLE_DATA::modules_lock.] //Tests_SRS_BROKER_13_047 : [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.] +//Tests_SRS_BROKER_17_028: [ The function shall subscribe BROKER_MODULEINFO::receive_socket to the quit signal GUID. ] TEST_FUNCTION(Broker_AddModule_succeeds) { ///arrange @@ -1612,7 +1638,11 @@ TEST_FUNCTION(Broker_AddModule_succeeds) .IgnoreArgument(1); STRICT_EXPECTED_CALL(mocks, nn_connect(IGNORED_NUM_ARG, IGNORED_PTR_ARG)) .IgnoreAllArguments(); - STRICT_EXPECTED_CALL(mocks, nn_setsockopt(IGNORED_NUM_ARG, NN_SUB, NN_SUB_SUBSCRIBE, IGNORED_PTR_ARG, 0)) + STRICT_EXPECTED_CALL(mocks, STRING_c_str(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, STRING_length(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, nn_setsockopt(IGNORED_NUM_ARG, NN_SUB, NN_SUB_SUBSCRIBE, IGNORED_PTR_ARG, 36)) .IgnoreArgument(1) .IgnoreArgument(4); STRICT_EXPECTED_CALL(mocks, ThreadAPI_Create(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) @@ -1639,6 +1669,7 @@ TEST_FUNCTION(Broker_AddModule_succeeds) //Tests_SRS_BROKER_13_092: [ The function shall deliver the message to the module's callback function via module_info->module_apis. ] //Tests_SRS_BROKER_13_093: [ The function shall destroy the message that was dequeued by calling Message_Destroy. ] //Tests_SRS_BROKER_17_019: [ The function shall free the buffer received on the receive_socket. ] +//Tests_SRS_BROKER_17_024: [ The function shall strip off the topic from the message. ] TEST_FUNCTION(module_publish_worker_calls_receive_once_then_exits_on_quit_msg) { CBrokerMocks mocks; @@ -2006,6 +2037,8 @@ TEST_FUNCTION(Broker_RemoveModule_succeeds) .IgnoreArgument(2); STRICT_EXPECTED_CALL(mocks, list_item_get_value(IGNORED_PTR_ARG)) .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_item_get_value(IGNORED_PTR_ARG)) + .IgnoreArgument(1); STRICT_EXPECTED_CALL(mocks, nn_send(IGNORED_NUM_ARG, IGNORED_PTR_ARG, 37, 0)) .IgnoreArgument(1) .IgnoreArgument(2); @@ -2122,6 +2155,8 @@ TEST_FUNCTION(Broker_RemoveModule_succeeds_when_nn_send_fails) .IgnoreArgument(2); STRICT_EXPECTED_CALL(mocks, list_item_get_value(IGNORED_PTR_ARG)) .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_item_get_value(IGNORED_PTR_ARG)) + .IgnoreArgument(1); STRICT_EXPECTED_CALL(mocks, nn_send(IGNORED_NUM_ARG, IGNORED_PTR_ARG, 37, 0)) .IgnoreArgument(1) .IgnoreArgument(2) @@ -2176,6 +2211,8 @@ TEST_FUNCTION(Broker_RemoveModule_succeeds_even_when_Lock_fails) .IgnoreArgument(2); STRICT_EXPECTED_CALL(mocks, list_item_get_value(IGNORED_PTR_ARG)) .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_item_get_value(IGNORED_PTR_ARG)) + .IgnoreArgument(1); STRICT_EXPECTED_CALL(mocks, nn_send(IGNORED_NUM_ARG, IGNORED_PTR_ARG, 37, 0)) .IgnoreArgument(1) .IgnoreArgument(2); @@ -2232,6 +2269,8 @@ TEST_FUNCTION(Broker_RemoveModule_succeeds_even_when_nn_close_fails) .IgnoreArgument(2); STRICT_EXPECTED_CALL(mocks, list_item_get_value(IGNORED_PTR_ARG)) .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_item_get_value(IGNORED_PTR_ARG)) + .IgnoreArgument(1); STRICT_EXPECTED_CALL(mocks, nn_send(IGNORED_NUM_ARG, IGNORED_PTR_ARG, 37, 0)) .IgnoreArgument(1) .IgnoreArgument(2); @@ -2291,6 +2330,8 @@ TEST_FUNCTION(Broker_RemoveModule_succeeds_even_when_unlock_fails) .IgnoreArgument(2); STRICT_EXPECTED_CALL(mocks, list_item_get_value(IGNORED_PTR_ARG)) .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_item_get_value(IGNORED_PTR_ARG)) + .IgnoreArgument(1); STRICT_EXPECTED_CALL(mocks, nn_send(IGNORED_NUM_ARG, IGNORED_PTR_ARG, 37, 0)) .IgnoreArgument(1) .IgnoreArgument(2); @@ -2328,161 +2369,790 @@ TEST_FUNCTION(Broker_RemoveModule_succeeds_even_when_unlock_fails) Broker_Destroy(broker); } - -//Tests_SRS_BROKER_13_108: [If broker is NULL then Broker_IncRef shall do nothing.] -TEST_FUNCTION(Broker_IncRef_does_nothing_with_null_input) +//Tests_SRS_BROKER_17_029: [ If broker, link, link->module_source_handle or link->module_sink_handle are NULL, Broker_AddLink shall return BROKER_INVALIDARG. ] +TEST_FUNCTION(Broker_AddLink_null_broker_fails) { - ///arrange - CBrokerMocks mocks; - - ///act - Broker_IncRef(NULL); - - ///assert - mocks.AssertActualAndExpectedCalls(); - - ///cleanup -} + ///arrange + CBrokerMocks mocks; + BROKER_HANDLE broker = NULL; + BROKER_LINK_DATA bld = + { + fake_module_handle, + fake_module_handle + }; -//Tests_SRS_BROKER_13_109: [Otherwise, `Broker_IncRef` shall increment the internal ref count.] -TEST_FUNCTION(Broker_IncRef_increments_ref_count_1) -{ - ///arrange - CBrokerMocks mocks; - auto broker = Broker_Create(); - mocks.ResetAllCalls(); + ///act + auto result = Broker_AddLink(broker, &bld); - ///act - Broker_IncRef(broker); - Broker_DecRef(broker); + ///assert + ASSERT_ARE_EQUAL(BROKER_RESULT, result, BROKER_INVALIDARG); + mocks.AssertActualAndExpectedCalls(); - ///assert - mocks.AssertActualAndExpectedCalls(); + ///cleanup - ///cleanup - Broker_Destroy(broker); } -//Tests_SRS_BROKER_13_111: [ Otherwise, Broker_Destroy shall decrement the internal ref count of the message. ] -TEST_FUNCTION(Broker_IncRef_increments_ref_count_1_destroy) +//Tests_SRS_BROKER_17_029: [ If broker, link, link->module_source_handle or link->module_sink_handle are NULL, Broker_AddLink shall return BROKER_INVALIDARG. ] +TEST_FUNCTION(Broker_AddLink_null_link_fails) { - ///arrange - CBrokerMocks mocks; - auto broker = Broker_Create(); - mocks.ResetAllCalls(); + ///arrange + CBrokerMocks mocks; + BROKER_HANDLE broker = (BROKER_HANDLE)0x01; + BROKER_LINK_DATA bld = + { + fake_module_handle, + fake_module_handle + }; - ///act - Broker_IncRef(broker); - Broker_Destroy(broker); + ///act + auto result = Broker_AddLink(broker, NULL); - ///assert - mocks.AssertActualAndExpectedCalls(); + ///assert + ASSERT_ARE_EQUAL(BROKER_RESULT, result, BROKER_INVALIDARG); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup - ///cleanup - Broker_Destroy(broker); } -//Tests_SRS_BROKER_13_058: [If broker is NULL the function shall do nothing.] -TEST_FUNCTION(Broker_Destroy_does_nothing_with_null_input) +//Tests_SRS_BROKER_17_029: [ If broker, link, link->module_source_handle or link->module_sink_handle are NULL, Broker_AddLink shall return BROKER_INVALIDARG. ] +TEST_FUNCTION(Broker_AddLink_null_source_fails) { - ///arrange - CBrokerMocks mocks; + ///arrange + CBrokerMocks mocks; + BROKER_HANDLE broker = (BROKER_HANDLE)0x01; + BROKER_LINK_DATA bld = + { + NULL, + fake_module_handle + }; - ///act - Broker_Destroy(NULL); + ///act + auto result = Broker_AddLink(broker, &bld); - ///assert - mocks.AssertActualAndExpectedCalls(); + ///assert + ASSERT_ARE_EQUAL(BROKER_RESULT, result, BROKER_INVALIDARG); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup - ///cleanup } -//Tests_SRS_BROKER_13_058: [If broker is NULL the function shall do nothing.] -TEST_FUNCTION(Broker_DecRef_does_nothing_with_null_input) +//Tests_SRS_BROKER_17_029: [ If broker, link, link->module_source_handle or link->module_sink_handle are NULL, Broker_AddLink shall return BROKER_INVALIDARG. ] +TEST_FUNCTION(Broker_AddLink_null_sink_fails) { - ///arrange - CBrokerMocks mocks; + ///arrange + CBrokerMocks mocks; + BROKER_HANDLE broker = (BROKER_HANDLE)0x01; + BROKER_LINK_DATA bld = + { + fake_module_handle, + NULL + }; - ///act - Broker_DecRef(NULL); + ///act + auto result = Broker_AddLink(broker, &bld); - ///assert - mocks.AssertActualAndExpectedCalls(); + ///assert + ASSERT_ARE_EQUAL(BROKER_RESULT, result, BROKER_INVALIDARG); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup - ///cleanup } -//Tests_SRS_BROKER_13_112: [If the ref count is zero then the allocated resources are freed.] -TEST_FUNCTION(Broker_Destroy_works) +//Tests_SRS_BROKER_17_030: [ Broker_AddLink shall lock the modules_lock. ] +//Tests_SRS_BROKER_17_031: [ Broker_AddLink shall find the BROKER_HANDLE_DATA::module_info for link->module_sink_handle. ] +//Tests_SRS_BROKER_17_041: [ Broker_AddLink shall find the BROKER_HANDLE_DATA::module_info for link->module_source_handle. ] +//Tests_SRS_BROKER_17_032: [ Broker_AddLink shall subscribe module_info->receive_socket to the link->module_source_handle module handle. ] +//Tests_SRS_BROKER_17_033: [ Broker_AddLink shall unlock the modules_lock. ] +TEST_FUNCTION(Broker_AddLink_succeeds) { - ///arrange - CBrokerMocks mocks; - auto broker = Broker_Create(); - mocks.ResetAllCalls(); + ///arrange + CBrokerMocks mocks; + auto broker = Broker_Create(); + auto result = Broker_AddModule(broker, &fake_module); + mocks.ResetAllCalls(); - // these are for Broker_Destroy - STRICT_EXPECTED_CALL(mocks, Lock_Deinit(IGNORED_PTR_ARG)) - .IgnoreArgument(1); - STRICT_EXPECTED_CALL(mocks, nn_close(IGNORED_NUM_ARG)) + STRICT_EXPECTED_CALL(mocks, Lock(IGNORED_PTR_ARG)) .IgnoreArgument(1); - STRICT_EXPECTED_CALL(mocks, STRING_delete(IGNORED_PTR_ARG)) + STRICT_EXPECTED_CALL(mocks, Unlock(IGNORED_PTR_ARG)) .IgnoreArgument(1); - STRICT_EXPECTED_CALL(mocks, list_get_head_item(IGNORED_PTR_ARG)) - .IgnoreArgument(1); - STRICT_EXPECTED_CALL(mocks, list_destroy(IGNORED_PTR_ARG)) - .IgnoreArgument(1); - STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) - .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_find(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) + .IgnoreArgument(1) + .IgnoreArgument(2) + .IgnoreArgument(3); + STRICT_EXPECTED_CALL(mocks, list_item_get_value(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_item_get_value(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_find(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) + .IgnoreArgument(1) + .IgnoreArgument(2) + .IgnoreArgument(3); + STRICT_EXPECTED_CALL(mocks, list_item_get_value(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_item_get_value(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, nn_setsockopt(IGNORED_NUM_ARG, NN_SUB, NN_SUB_SUBSCRIBE, IGNORED_PTR_ARG, sizeof(MODULE_HANDLE))) + .IgnoreArgument(1) + .IgnoreArgument(4); - ///act - Broker_Destroy(broker); + BROKER_LINK_DATA bld = + { + fake_module_handle, + fake_module_handle + }; - ///assert - mocks.AssertActualAndExpectedCalls(); + ///act + result = Broker_AddLink(broker, &bld); - ///cleanup + ///assert + ASSERT_ARE_EQUAL(BROKER_RESULT, result, BROKER_OK); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Broker_RemoveModule(broker, &fake_module); + Broker_Destroy(broker); } -//Tests_SRS_BROKER_13_112: [If the ref count is zero then the allocated resources are freed.] -//Tests_SRS_BROKER_13_113: [ This function shall implement all the requirements of the Broker_Destroy API. ] -TEST_FUNCTION(Broker_DecRef_works) +//Tests_SRS_BROKER_17_034: [ Upon an error, Broker_AddLink shall return BROKER_ADD_LINK_ERROR ] +TEST_FUNCTION(Broker_AddLink_fails_setsocketoption_fails) { - ///arrange - CBrokerMocks mocks; - auto broker = Broker_Create(); - mocks.ResetAllCalls(); + ///arrange + CBrokerMocks mocks; + auto broker = Broker_Create(); + auto result = Broker_AddModule(broker, &fake_module); + mocks.ResetAllCalls(); - // these are for Broker_Destroy - STRICT_EXPECTED_CALL(mocks, Lock_Deinit(IGNORED_PTR_ARG)) - .IgnoreArgument(1); - STRICT_EXPECTED_CALL(mocks, nn_close(IGNORED_NUM_ARG)) + STRICT_EXPECTED_CALL(mocks, Lock(IGNORED_PTR_ARG)) .IgnoreArgument(1); - STRICT_EXPECTED_CALL(mocks, STRING_delete(IGNORED_PTR_ARG)) + STRICT_EXPECTED_CALL(mocks, Unlock(IGNORED_PTR_ARG)) .IgnoreArgument(1); - STRICT_EXPECTED_CALL(mocks, list_get_head_item(IGNORED_PTR_ARG)) - .IgnoreArgument(1); - STRICT_EXPECTED_CALL(mocks, list_destroy(IGNORED_PTR_ARG)) - .IgnoreArgument(1); - STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) - .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_find(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) + .IgnoreArgument(1) + .IgnoreArgument(2) + .IgnoreArgument(3); + STRICT_EXPECTED_CALL(mocks, list_item_get_value(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_item_get_value(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_find(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) + .IgnoreArgument(1) + .IgnoreArgument(2) + .IgnoreArgument(3); + STRICT_EXPECTED_CALL(mocks, list_item_get_value(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_item_get_value(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, nn_setsockopt(IGNORED_NUM_ARG, NN_SUB, NN_SUB_SUBSCRIBE, IGNORED_PTR_ARG, sizeof(MODULE_HANDLE))) + .IgnoreArgument(1) + .IgnoreArgument(4) + .SetFailReturn(-1); - ///act - Broker_DecRef(broker); + BROKER_LINK_DATA bld = + { + fake_module_handle, + fake_module_handle + }; - ///assert - mocks.AssertActualAndExpectedCalls(); + ///act + result = Broker_AddLink(broker, &bld); - ///cleanup + ///assert + ASSERT_ARE_EQUAL(BROKER_RESULT, result, BROKER_ADD_LINK_ERROR); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Broker_RemoveModule(broker, &fake_module); + Broker_Destroy(broker); } -//Tests_SRS_BROKER_13_030: [If broker or message is NULL the function shall return BROKER_INVALIDARG.] -TEST_FUNCTION(Broker_Publish_fails_with_null_broker) +//Tests_SRS_BROKER_17_034: [ Upon an error, Broker_AddLink shall return BROKER_ADD_LINK_ERROR ] +TEST_FUNCTION(Broker_AddLink_fails_source_find_fails) { - ///arrange - CBrokerMocks mocks; + ///arrange + CBrokerMocks mocks; + auto broker = Broker_Create(); + auto result = Broker_AddModule(broker, &fake_module); + mocks.ResetAllCalls(); - ///act - auto r1 = Broker_Publish(NULL, NULL, (MESSAGE_HANDLE)0x1); + STRICT_EXPECTED_CALL(mocks, Lock(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, Unlock(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_find(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) + .IgnoreArgument(1) + .IgnoreArgument(2) + .IgnoreArgument(3); + STRICT_EXPECTED_CALL(mocks, list_item_get_value(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_item_get_value(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_find(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) + .IgnoreArgument(1) + .IgnoreArgument(2) + .IgnoreArgument(3) + .SetFailReturn((LIST_ITEM_HANDLE)NULL); + + BROKER_LINK_DATA bld = + { + fake_module_handle, + fake_module_handle + }; + + ///act + result = Broker_AddLink(broker, &bld); + + ///assert + ASSERT_ARE_EQUAL(BROKER_RESULT, result, BROKER_ADD_LINK_ERROR); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Broker_RemoveModule(broker, &fake_module); + Broker_Destroy(broker); +} + +//Tests_SRS_BROKER_17_034: [ Upon an error, Broker_AddLink shall return BROKER_ADD_LINK_ERROR ] +TEST_FUNCTION(Broker_AddLink_fails_list_find_fails) +{ + ///arrange + CBrokerMocks mocks; + auto broker = Broker_Create(); + auto result = Broker_AddModule(broker, &fake_module); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Lock(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, Unlock(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_find(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) + .IgnoreArgument(1) + .IgnoreArgument(2) + .IgnoreArgument(3) + .SetFailReturn((LIST_ITEM_HANDLE)NULL); + + BROKER_LINK_DATA bld = + { + fake_module_handle, + fake_module_handle + }; + + ///act + result = Broker_AddLink(broker, &bld); + + ///assert + ASSERT_ARE_EQUAL(BROKER_RESULT, result, BROKER_ADD_LINK_ERROR); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Broker_RemoveModule(broker, &fake_module); + Broker_Destroy(broker); +} + +//Tests_SRS_BROKER_17_034: [ Upon an error, Broker_AddLink shall return BROKER_ADD_LINK_ERROR ] +TEST_FUNCTION(Broker_AddLink_fails_lock_fails) +{ + ///arrange + CBrokerMocks mocks; + auto broker = Broker_Create(); + auto result = Broker_AddModule(broker, &fake_module); + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Lock(IGNORED_PTR_ARG)) + .IgnoreArgument(1) + .SetFailReturn(LOCK_ERROR); + + BROKER_LINK_DATA bld = + { + fake_module_handle, + fake_module_handle + }; + + ///act + result = Broker_AddLink(broker, &bld); + + ///assert + ASSERT_ARE_EQUAL(BROKER_RESULT, result, BROKER_ADD_LINK_ERROR); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Broker_RemoveModule(broker, &fake_module); + Broker_Destroy(broker); +} + +//Tests_SRS_BROKER_17_035: [ If broker, link, link->module_source_handle or link->module_sink_handle are NULL, Broker_RemoveLink shall return BROKER_INVALIDARG. ] +TEST_FUNCTION(Broker_RemoveLink_null_broker_fails) +{ + ///arrange + CBrokerMocks mocks; + BROKER_HANDLE broker = NULL; + BROKER_LINK_DATA bld = + { + fake_module_handle, + fake_module_handle + }; + + ///act + auto result = Broker_RemoveLink(broker, &bld); + + ///assert + ASSERT_ARE_EQUAL(BROKER_RESULT, result, BROKER_INVALIDARG); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + +} + +//Tests_SRS_BROKER_17_035: [ If broker, link, link->module_source_handle or link->module_sink_handle are NULL, Broker_RemoveLink shall return BROKER_INVALIDARG. ] +TEST_FUNCTION(Broker_RemoveLink_null_link_fails) +{ + ///arrange + CBrokerMocks mocks; + BROKER_HANDLE broker = (BROKER_HANDLE)0x01; + BROKER_LINK_DATA bld = + { + fake_module_handle, + fake_module_handle + }; + + ///act + auto result = Broker_RemoveLink(broker, NULL); + + ///assert + ASSERT_ARE_EQUAL(BROKER_RESULT, result, BROKER_INVALIDARG); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + +} + +//Tests_SRS_BROKER_17_035: [ If broker, link, link->module_source_handle or link->module_sink_handle are NULL, Broker_RemoveLink shall return BROKER_INVALIDARG. ] +TEST_FUNCTION(Broker_RemoveLink_null_source_fails) +{ + ///arrange + CBrokerMocks mocks; + BROKER_HANDLE broker = (BROKER_HANDLE)0x01; + BROKER_LINK_DATA bld = + { + NULL, + fake_module_handle + }; + + ///act + auto result = Broker_RemoveLink(broker, &bld); + + ///assert + ASSERT_ARE_EQUAL(BROKER_RESULT, result, BROKER_INVALIDARG); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + +} + +//Tests_SRS_BROKER_17_035: [ If broker, link, link->module_source_handle or link->module_sink_handle are NULL, Broker_RemoveLink shall return BROKER_INVALIDARG. ] +TEST_FUNCTION(Broker_RemoveLink_null_sink_fails) +{ + ///arrange + CBrokerMocks mocks; + BROKER_HANDLE broker = (BROKER_HANDLE)0x01; + BROKER_LINK_DATA bld = + { + fake_module_handle, + NULL + }; + + ///act + auto result = Broker_RemoveLink(broker, &bld); + + ///assert + ASSERT_ARE_EQUAL(BROKER_RESULT, result, BROKER_INVALIDARG); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + +} + +//Tests_SRS_BROKER_17_036: [ Broker_RemoveLink shall lock the modules_lock. ] +//Tests_SRS_BROKER_17_037: [ Broker_RemoveLink shall find the module_info for link->module_sink_handle. ] +//Tests_SRS_BROKER_17_042: [ Broker_RemoveLink shall find the module_info for link->module_source_handle. ] +//Tests_SRS_BROKER_17_038: [ Broker_RemoveLink shall unsubscribe module_info->receive_socket from the link->module_source_handle module handle. ] +//Tests_SRS_BROKER_17_039: [ Broker_RemoveLink shall unlock the modules_lock. ] +TEST_FUNCTION(Broker_RemoveLink_succeeds) +{ + ///arrange + CBrokerMocks mocks; + auto broker = Broker_Create(); + auto result = Broker_AddModule(broker, &fake_module); + BROKER_LINK_DATA bld = + { + fake_module_handle, + fake_module_handle + }; + result = Broker_AddLink(broker, &bld); + + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Lock(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, Unlock(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_find(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) + .IgnoreArgument(1) + .IgnoreArgument(2) + .IgnoreArgument(3); + STRICT_EXPECTED_CALL(mocks, list_item_get_value(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_item_get_value(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_find(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) + .IgnoreArgument(1) + .IgnoreArgument(2) + .IgnoreArgument(3); + STRICT_EXPECTED_CALL(mocks, list_item_get_value(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_item_get_value(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + STRICT_EXPECTED_CALL(mocks, nn_setsockopt(IGNORED_NUM_ARG, NN_SUB, NN_SUB_UNSUBSCRIBE, IGNORED_PTR_ARG, sizeof(MODULE_HANDLE))) + .IgnoreArgument(1) + .IgnoreArgument(4); + + ///act + result = Broker_RemoveLink(broker, &bld); + + ///assert + ASSERT_ARE_EQUAL(BROKER_RESULT, result, BROKER_OK); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Broker_RemoveModule(broker, &fake_module); + Broker_Destroy(broker); +} + +//Tests_SRS_BROKER_17_040: [ Upon an error, Broker_RemoveLink shall return BROKER_REMOVE_LINK_ERROR. ] +TEST_FUNCTION(Broker_RemoveLink_fails_sockopt_fails) +{ + ///arrange + CBrokerMocks mocks; + auto broker = Broker_Create(); + auto result = Broker_AddModule(broker, &fake_module); + BROKER_LINK_DATA bld = + { + fake_module_handle, + fake_module_handle + }; + result = Broker_AddLink(broker, &bld); + + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Lock(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, Unlock(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_find(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) + .IgnoreArgument(1) + .IgnoreArgument(2) + .IgnoreArgument(3); + STRICT_EXPECTED_CALL(mocks, list_item_get_value(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_item_get_value(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_find(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) + .IgnoreArgument(1) + .IgnoreArgument(2) + .IgnoreArgument(3); + STRICT_EXPECTED_CALL(mocks, list_item_get_value(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_item_get_value(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, nn_setsockopt(IGNORED_NUM_ARG, NN_SUB, NN_SUB_UNSUBSCRIBE, IGNORED_PTR_ARG, sizeof(MODULE_HANDLE))) + .IgnoreArgument(1) + .IgnoreArgument(4) + .SetFailReturn(-1); + + ///act + result = Broker_RemoveLink(broker, &bld); + + ///assert + ASSERT_ARE_EQUAL(BROKER_RESULT, result, BROKER_REMOVE_LINK_ERROR); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Broker_RemoveModule(broker, &fake_module); + Broker_Destroy(broker); +} + +TEST_FUNCTION(Broker_RemoveLink_fails_source_find_fails) +{ + ///arrange + CBrokerMocks mocks; + auto broker = Broker_Create(); + auto result = Broker_AddModule(broker, &fake_module); + BROKER_LINK_DATA bld = + { + fake_module_handle, + fake_module_handle + }; + result = Broker_AddLink(broker, &bld); + + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Lock(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, Unlock(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_find(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) + .IgnoreArgument(1) + .IgnoreArgument(2) + .IgnoreArgument(3); + STRICT_EXPECTED_CALL(mocks, list_item_get_value(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_item_get_value(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_find(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) + .IgnoreArgument(1) + .IgnoreArgument(2) + .IgnoreArgument(3) + .SetFailReturn(nullptr); + + ///act + result = Broker_RemoveLink(broker, &bld); + + ///assert + ASSERT_ARE_EQUAL(BROKER_RESULT, result, BROKER_REMOVE_LINK_ERROR); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Broker_RemoveModule(broker, &fake_module); + Broker_Destroy(broker); +} + + +//Tests_SRS_BROKER_17_040: [ Upon an error, Broker_RemoveLink shall return BROKER_REMOVE_LINK_ERROR. ] +TEST_FUNCTION(Broker_RemoveLink_fails_list_find_fails) +{ + ///arrange + CBrokerMocks mocks; + auto broker = Broker_Create(); + auto result = Broker_AddModule(broker, &fake_module); + BROKER_LINK_DATA bld = + { + fake_module_handle, + fake_module_handle + }; + result = Broker_AddLink(broker, &bld); + + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Lock(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, Unlock(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_find(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) + .IgnoreArgument(1) + .IgnoreArgument(2) + .IgnoreArgument(3) + .SetFailReturn(nullptr); + + ///act + result = Broker_RemoveLink(broker, &bld); + + ///assert + ASSERT_ARE_EQUAL(BROKER_RESULT, result, BROKER_REMOVE_LINK_ERROR); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Broker_RemoveModule(broker, &fake_module); + Broker_Destroy(broker); +} + +//Tests_SRS_BROKER_17_040: [ Upon an error, Broker_RemoveLink shall return BROKER_REMOVE_LINK_ERROR. ] +TEST_FUNCTION(Broker_RemoveLink_fails_lock_fails) +{ + ///arrange + CBrokerMocks mocks; + auto broker = Broker_Create(); + auto result = Broker_AddModule(broker, &fake_module); + BROKER_LINK_DATA bld = + { + fake_module_handle, + fake_module_handle + }; + result = Broker_AddLink(broker, &bld); + + mocks.ResetAllCalls(); + + STRICT_EXPECTED_CALL(mocks, Lock(IGNORED_PTR_ARG)) + .IgnoreArgument(1) + .SetFailReturn(LOCK_ERROR); + + ///act + result = Broker_RemoveLink(broker, &bld); + + ///assert + ASSERT_ARE_EQUAL(BROKER_RESULT, result, BROKER_REMOVE_LINK_ERROR); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Broker_RemoveModule(broker, &fake_module); + Broker_Destroy(broker); +} + +//Tests_SRS_BROKER_13_108: [If broker is NULL then Broker_IncRef shall do nothing.] +TEST_FUNCTION(Broker_IncRef_does_nothing_with_null_input) +{ + ///arrange + CBrokerMocks mocks; + + ///act + Broker_IncRef(NULL); + + ///assert + mocks.AssertActualAndExpectedCalls(); + + ///cleanup +} + +//Tests_SRS_BROKER_13_109: [Otherwise, `Broker_IncRef` shall increment the internal ref count.] +TEST_FUNCTION(Broker_IncRef_increments_ref_count_1) +{ + ///arrange + CBrokerMocks mocks; + auto broker = Broker_Create(); + mocks.ResetAllCalls(); + + ///act + Broker_IncRef(broker); + Broker_DecRef(broker); + + ///assert + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Broker_Destroy(broker); +} + +//Tests_SRS_BROKER_13_111: [ Otherwise, Broker_Destroy shall decrement the internal ref count of the message. ] +TEST_FUNCTION(Broker_IncRef_increments_ref_count_1_destroy) +{ + ///arrange + CBrokerMocks mocks; + auto broker = Broker_Create(); + mocks.ResetAllCalls(); + + ///act + Broker_IncRef(broker); + Broker_Destroy(broker); + + ///assert + mocks.AssertActualAndExpectedCalls(); + + ///cleanup + Broker_Destroy(broker); +} + +//Tests_SRS_BROKER_13_058: [If broker is NULL the function shall do nothing.] +TEST_FUNCTION(Broker_Destroy_does_nothing_with_null_input) +{ + ///arrange + CBrokerMocks mocks; + + ///act + Broker_Destroy(NULL); + + ///assert + mocks.AssertActualAndExpectedCalls(); + + ///cleanup +} + +//Tests_SRS_BROKER_13_058: [If broker is NULL the function shall do nothing.] +TEST_FUNCTION(Broker_DecRef_does_nothing_with_null_input) +{ + ///arrange + CBrokerMocks mocks; + + ///act + Broker_DecRef(NULL); + + ///assert + mocks.AssertActualAndExpectedCalls(); + + ///cleanup +} + +//Tests_SRS_BROKER_13_112: [If the ref count is zero then the allocated resources are freed.] +TEST_FUNCTION(Broker_Destroy_works) +{ + ///arrange + CBrokerMocks mocks; + auto broker = Broker_Create(); + mocks.ResetAllCalls(); + + // these are for Broker_Destroy + STRICT_EXPECTED_CALL(mocks, Lock_Deinit(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, nn_close(IGNORED_NUM_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, STRING_delete(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_get_head_item(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_destroy(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + ///act + Broker_Destroy(broker); + + ///assert + mocks.AssertActualAndExpectedCalls(); + + ///cleanup +} + +//Tests_SRS_BROKER_13_112: [If the ref count is zero then the allocated resources are freed.] +//Tests_SRS_BROKER_13_113: [ This function shall implement all the requirements of the Broker_Destroy API. ] +TEST_FUNCTION(Broker_DecRef_works) +{ + ///arrange + CBrokerMocks mocks; + auto broker = Broker_Create(); + mocks.ResetAllCalls(); + + // these are for Broker_Destroy + STRICT_EXPECTED_CALL(mocks, Lock_Deinit(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, nn_close(IGNORED_NUM_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, STRING_delete(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_get_head_item(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, list_destroy(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, gballoc_free(IGNORED_PTR_ARG)) + .IgnoreArgument(1); + + ///act + Broker_DecRef(broker); + + ///assert + mocks.AssertActualAndExpectedCalls(); + + ///cleanup +} + +//Tests_SRS_BROKER_13_030: [If broker or message is NULL the function shall return BROKER_INVALIDARG.] +TEST_FUNCTION(Broker_Publish_fails_with_null_broker) +{ + ///arrange + CBrokerMocks mocks; + + ///act + auto r1 = Broker_Publish(NULL, fake_module_handle, (MESSAGE_HANDLE)0x1); ///assert ASSERT_ARE_EQUAL(BROKER_RESULT, r1, BROKER_INVALIDARG); @@ -2498,7 +3168,7 @@ TEST_FUNCTION(Broker_Publish_fails_with_null_message) CBrokerMocks mocks; ///act - auto r1 = Broker_Publish((BROKER_HANDLE)0x1, NULL, NULL); + auto r1 = Broker_Publish((BROKER_HANDLE)0x1, fake_module_handle, NULL); ///assert ASSERT_ARE_EQUAL(BROKER_RESULT, r1, BROKER_INVALIDARG); @@ -2507,6 +3177,21 @@ TEST_FUNCTION(Broker_Publish_fails_with_null_message) ///cleanup } +//Tests_SRS_BROKER_13_030: [If broker or message is NULL the function shall return BROKER_INVALIDARG.] +TEST_FUNCTION(Broker_Publish_fails_with_null_source) +{ + ///arrange + CBrokerMocks mocks; + + ///act + auto r1 = Broker_Publish((BROKER_HANDLE)0x1, NULL, (MESSAGE_HANDLE)0x1); + + ///assert + ASSERT_ARE_EQUAL(BROKER_RESULT, r1, BROKER_INVALIDARG); + mocks.AssertActualAndExpectedCalls(); + + ///cleanup +} //Tests_SRS_BROKER_13_037: [This function shall return BROKER_ERROR if an underlying API call to the platform causes an error or BROKER_OK otherwise.] TEST_FUNCTION(Broker_Publish_fails_when_Lock_fails) { @@ -2530,7 +3215,7 @@ TEST_FUNCTION(Broker_Publish_fails_when_Lock_fails) .SetFailReturn(LOCK_ERROR); ///act - result = Broker_Publish(broker, NULL, message); + result = Broker_Publish(broker, fake_module_handle, message); ///assert ASSERT_ARE_EQUAL(BROKER_RESULT, result, BROKER_ERROR); @@ -2570,7 +3255,7 @@ TEST_FUNCTION(Broker_Publish_fails_when_Message_ToByteArray_fails) .SetFailReturn(-1); ///act - result = Broker_Publish(broker, NULL, message); + result = Broker_Publish(broker, fake_module_handle, message); ///assert ASSERT_ARE_EQUAL(BROKER_RESULT, result, BROKER_ERROR); @@ -2607,11 +3292,11 @@ TEST_FUNCTION(Broker_Publish_fails_when_allocmsg_fails) STRICT_EXPECTED_CALL(mocks, Message_Clone(message)); STRICT_EXPECTED_CALL(mocks, Message_Destroy(message)); STRICT_EXPECTED_CALL(mocks, Message_ToByteArray(message, NULL, 0)); - STRICT_EXPECTED_CALL(mocks, nn_allocmsg(1, 0)) + STRICT_EXPECTED_CALL(mocks, nn_allocmsg(1 + sizeof(MODULE_HANDLE), 0)) .SetFailReturn(nullptr); ///act - result = Broker_Publish(broker, NULL, message); + result = Broker_Publish(broker, fake_module_handle, message); ///assert ASSERT_ARE_EQUAL(int, result, BROKER_ERROR); @@ -2648,7 +3333,7 @@ TEST_FUNCTION(Broker_Publish_fails_when_send_fails) STRICT_EXPECTED_CALL(mocks, Message_Clone(message)); STRICT_EXPECTED_CALL(mocks, Message_Destroy(message)); STRICT_EXPECTED_CALL(mocks, Message_ToByteArray(message, NULL, 0)); - STRICT_EXPECTED_CALL(mocks, nn_allocmsg(1, 0)) + STRICT_EXPECTED_CALL(mocks, nn_allocmsg(1 + sizeof(MODULE_HANDLE), 0)) .IgnoreArgument(1); STRICT_EXPECTED_CALL(mocks, nn_freemsg(IGNORED_PTR_ARG)) .IgnoreArgument(1); @@ -2660,7 +3345,7 @@ TEST_FUNCTION(Broker_Publish_fails_when_send_fails) .SetFailReturn((int)-1); ///act - result = Broker_Publish(broker, NULL, message); + result = Broker_Publish(broker, fake_module_handle, message); ///assert ASSERT_ARE_EQUAL(BROKER_RESULT, result, BROKER_ERROR); @@ -2675,7 +3360,9 @@ TEST_FUNCTION(Broker_Publish_fails_when_send_fails) //Tests_SRS_BROKER_17_022: [ Broker_Publish shall Lock the modules lock. ] //Tests_SRS_BROKER_17_007: [Broker_Publish shall clone the message.] //Tests_SRS_BROKER_17_008: [ Broker_Publish shall serialize the message. ] -//Tests_SRS_BROKER_17_009: [ Broker_Publish shall allocate a nanomsg buffer and copy the serialized message into it. ] +//Tests_SRS_BROKER_17_025: [ Broker_Publish shall allocate a nanomsg buffer the size of the serialized message + sizeof(MODULE_HANDLE). ] +//Tests_SRS_BROKER_17_026: [ Broker_Publish shall copy source into the beginning of the nanomsg buffer. ] +//Tests_SRS_BROKER_17_027: [ Broker_Publish shall serialize the message into the remainder of the nanomsg buffer. ] //Tests_SRS_BROKER_17_010: [ Broker_Publish shall send a message on the publish_socket. ] //Tests_SRS_BROKER_17_011: [ Broker_Publish shall free the serialized message data. ] //Tests_SRS_BROKER_17_012: [ Broker_Publish shall free the message. ] @@ -2705,7 +3392,7 @@ TEST_FUNCTION(Broker_Publish_succeeds) STRICT_EXPECTED_CALL(mocks, Message_Clone(message)); STRICT_EXPECTED_CALL(mocks, Message_Destroy(message)); STRICT_EXPECTED_CALL(mocks, Message_ToByteArray(message, NULL, 0)); - STRICT_EXPECTED_CALL(mocks, nn_allocmsg(1, 0)) + STRICT_EXPECTED_CALL(mocks, nn_allocmsg(1+sizeof(MODULE_HANDLE), 0)) .IgnoreArgument(1); STRICT_EXPECTED_CALL(mocks, Message_ToByteArray(message, IGNORED_PTR_ARG, 1)) .IgnoreArgument(2); @@ -2715,7 +3402,7 @@ TEST_FUNCTION(Broker_Publish_succeeds) ///act - result = Broker_Publish(broker, NULL, message); + result = Broker_Publish(broker, fake_module_handle, message); ///assert ASSERT_ARE_EQUAL(BROKER_RESULT, result, BROKER_OK); diff --git a/core/tests/broker_uwp_ut/broker_uwp_ut.cpp b/core/tests/broker_uwp_ut/broker_uwp_ut.cpp index abad9fb5..9a354015 100644 --- a/core/tests/broker_uwp_ut/broker_uwp_ut.cpp +++ b/core/tests/broker_uwp_ut/broker_uwp_ut.cpp @@ -620,7 +620,8 @@ TEST_FUNCTION_CLEANUP(TestMethodCleanup) } } -//Tests_SRS_BROKER_99_015: [If `module_instance` is `NULL` the function shall return `BROKER_INVALIDARG`.] +//Tests_SRS_BCAST_BROKER_99_015: [If `module_instance` is `NULL` the function shall return `BROKER_INVALIDARG`.] +//Tests_SRS_BROKER_99_015: [ If module_instance is NULL the function shall return BROKER_INVALIDARG. ] TEST_FUNCTION(Broker_AddModule_fails_with_null_broker) { ///arrange @@ -675,18 +676,19 @@ static COND_RESULT module_publish_worker_calls_module_receive_Condition_Wait(voi return COND_OK; } -// Tests_SRS_BROKER_13_089: [ This function shall acquire the lock on module_info->mq_lock. ] -// Tests_SRS_BROKER_13_068: [ This function shall run a loop that keeps running while module_info->quit_worker is equal to 0. ] -// Tests_SRS_BROKER_13_071: [ For every iteration of the loop the function will first wait on module_info->mq_cond using module_info->mq_lock as the corresponding mutex to be used by the condition variable. ] -// Tests_SRS_BROKER_13_090: [ When module_info->mq_cond has been signaled this function shall kick off another loop predicated on module_info->quit_worker being equal to 0 and module_info->mq not being empty. This thread has the lock on module_info->mq_lock at this point. ] -// Tests_SRS_BROKER_13_069: [ The function shall dequeue a message from the module's message queue. ] -// Tests_SRS_BROKER_13_091: [ The function shall unlock module_info->mq_lock. ] +// Tests_SRS_BCAST_BROKER_13_089: [ This function shall acquire the lock on module_info->mq_lock. ] +// Tests_SRS_BCAST_BROKER_13_068: [ This function shall run a loop that keeps running while module_info->quit_worker is equal to 0. ] +// Tests_SRS_BCAST_BROKER_13_071: [ For every iteration of the loop the function will first wait on module_info->mq_cond using module_info->mq_lock as the corresponding mutex to be used by the condition variable. ] +// Tests_SRS_BCAST_BROKER_13_090: [ When module_info->mq_cond has been signaled this function shall kick off another loop predicated on module_info->quit_worker being equal to 0 and module_info->mq not being empty. This thread has the lock on module_info->mq_lock at this point. ] +// Tests_SRS_BCAST_BROKER_13_069: [ The function shall dequeue a message from the module's message queue. ] +// Tests_SRS_BCAST_BROKER_13_091: [ The function shall unlock module_info->mq_lock. ] +// Tests_SRS_BCAST_BROKER_99_012: [ The function shall deliver the message to the module's Receive function via the `IInternalGatewayModule` interface. ] // Tests_SRS_BROKER_99_012: [ The function shall deliver the message to the module's Receive function via the `IInternalGatewayModule` interface. ] -// Tests_SRS_BROKER_13_093: [ The function shall destroy the message that was dequeued by calling Message_Destroy. ] -// Tests_SRS_BROKER_13_094: [ The function shall re-acquire the lock on module_info->mq_lock. ] -// Tests_SRS_BROKER_13_095: [ When the function exits the outer loop predicated on module_info->quit_worker being 0 it shall unlock module_info->mq_lock before exiting from the function. ] -// Tests_SRS_BROKER_13_026: [ This function shall assign user_data to a local variable called module_info of type BROKER_MODULEINFO*. ] -// Tests_SRS_BROKER_04_001: [** This function shall immediately start processing messages when `module->mq` is not empty without waiting on `module->mq_cond`.] +// Tests_SRS_BCAST_BROKER_13_093: [ The function shall destroy the message that was dequeued by calling Message_Destroy. ] +// Tests_SRS_BCAST_BROKER_13_094: [ The function shall re-acquire the lock on module_info->mq_lock. ] +// Tests_SRS_BCAST_BROKER_13_095: [ When the function exits the outer loop predicated on module_info->quit_worker being 0 it shall unlock module_info->mq_lock before exiting from the function. ] +// Tests_SRS_BCAST_BROKER_13_026: [ This function shall assign user_data to a local variable called module_info of type BROKER_MODULEINFO*. ] +// Tests_SRS_BCAST_BROKER_04_001: [** This function shall immediately start processing messages when `module->mq` is not empty without waiting on `module->mq_cond`.] TEST_FUNCTION(module_publish_worker_calls_module_receive) { /** diff --git a/core/tests/gateway_e2e/gateway_e2e.cpp b/core/tests/gateway_e2e/gateway_e2e.cpp index 45fc8502..0b29a8a6 100644 --- a/core/tests/gateway_e2e/gateway_e2e.cpp +++ b/core/tests/gateway_e2e/gateway_e2e.cpp @@ -179,6 +179,7 @@ BEGIN_TEST_SUITE(gateway_e2e) } GATEWAY_MODULES_ENTRY modules[3]; + GATEWAY_LINK_ENTRY links[2]; modules[0].module_configuration = &iotHubConfig; modules[0].module_name = "IoTHub"; @@ -193,11 +194,19 @@ BEGIN_TEST_SUITE(gateway_e2e) modules[2].module_name = "E2ETest"; modules[2].module_path = e2e_module_path(); + links[0].module_source = "E2ETest"; + links[0].module_sink = GW_IDMAP_MODULE; + + links[1].module_source = GW_IDMAP_MODULE; + links[1].module_sink = "IoTHub"; GATEWAY_PROPERTIES m6GatewayProperties; VECTOR_HANDLE gatewayProps = VECTOR_create(sizeof(GATEWAY_MODULES_ENTRY)); + VECTOR_HANDLE gatewayLinks = VECTOR_create(sizeof(GATEWAY_LINK_ENTRY)); VECTOR_push_back(gatewayProps, &modules, 3); + VECTOR_push_back(gatewayLinks, &links, 2); + ///act diff --git a/core/tests/gateway_ll_ut/gateway_ll_ut.cpp b/core/tests/gateway_ll_ut/gateway_ll_ut.cpp index b6043592..165500eb 100644 --- a/core/tests/gateway_ll_ut/gateway_ll_ut.cpp +++ b/core/tests/gateway_ll_ut/gateway_ll_ut.cpp @@ -160,6 +160,12 @@ TYPED_MOCK_CLASS(CGatewayLLMocks, CGlobalMock) } MOCK_METHOD_END(BROKER_RESULT, result1); + MOCK_STATIC_METHOD_2(, BROKER_RESULT, Broker_AddLink, BROKER_HANDLE, handle, const BROKER_LINK_DATA*, link) + MOCK_METHOD_END(BROKER_RESULT, BROKER_OK) + + MOCK_STATIC_METHOD_2(, BROKER_RESULT, Broker_RemoveLink, BROKER_HANDLE, handle, const BROKER_LINK_DATA*, link) + MOCK_METHOD_END(BROKER_RESULT, BROKER_OK) + MOCK_STATIC_METHOD_1(, MODULE_LIBRARY_HANDLE, ModuleLoader_Load, const char*, moduleLibraryFileName) currentModuleLoader_Load_call++; MODULE_LIBRARY_HANDLE handle = NULL; @@ -276,6 +282,8 @@ DECLARE_GLOBAL_MOCK_METHOD_0(CGatewayLLMocks, , BROKER_HANDLE, Broker_Create); DECLARE_GLOBAL_MOCK_METHOD_1(CGatewayLLMocks, , void, Broker_Destroy, BROKER_HANDLE, broker); DECLARE_GLOBAL_MOCK_METHOD_2(CGatewayLLMocks, , BROKER_RESULT, Broker_AddModule, BROKER_HANDLE, handle, const MODULE*, module); DECLARE_GLOBAL_MOCK_METHOD_2(CGatewayLLMocks, , BROKER_RESULT, Broker_RemoveModule, BROKER_HANDLE, handle, const MODULE*, module); +DECLARE_GLOBAL_MOCK_METHOD_2(CGatewayLLMocks, , BROKER_RESULT, Broker_AddLink, BROKER_HANDLE, handle, const BROKER_LINK_DATA*, link); +DECLARE_GLOBAL_MOCK_METHOD_2(CGatewayLLMocks, , BROKER_RESULT, Broker_RemoveLink, BROKER_HANDLE, handle, const BROKER_LINK_DATA*, link); DECLARE_GLOBAL_MOCK_METHOD_1(CGatewayLLMocks, , void, Broker_IncRef, BROKER_HANDLE, broker); DECLARE_GLOBAL_MOCK_METHOD_1(CGatewayLLMocks, , void, Broker_DecRef, BROKER_HANDLE, broker); @@ -411,6 +419,7 @@ TEST_FUNCTION_CLEANUP(TestMethodCleanup) whenShallBroker_Create_fail = 0; BASEIMPLEMENTATION::VECTOR_destroy(dummyProps->gateway_modules); + BASEIMPLEMENTATION::VECTOR_destroy(dummyProps->gateway_links); free(dummyProps); } @@ -998,6 +1007,8 @@ TEST_FUNCTION(Gateway_LL_Create_Adds_All_Modules_And_All_Links_In_Props_Success) .IgnoreAllArguments(); //Check if Source Module exists. STRICT_EXPECTED_CALL(mocks, VECTOR_find_if(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) .IgnoreAllArguments(); //Check if Sink Module exists. + STRICT_EXPECTED_CALL(mocks, Broker_AddLink(IGNORED_PTR_ARG, IGNORED_PTR_ARG)) + .IgnoreAllArguments(); STRICT_EXPECTED_CALL(mocks, VECTOR_push_back(IGNORED_PTR_ARG, IGNORED_PTR_ARG, 1)) .IgnoreArgument(1) .IgnoreArgument(2); @@ -1275,6 +1286,8 @@ TEST_FUNCTION(Gateway_LL_Destroy_Removes_All_Modules_And_Destroys_Vector_Success .IgnoreArgument(1); STRICT_EXPECTED_CALL(mocks, VECTOR_front(IGNORED_PTR_ARG)) .IgnoreArgument(1); + STRICT_EXPECTED_CALL(mocks, Broker_RemoveLink(IGNORED_PTR_ARG, IGNORED_PTR_ARG)) + .IgnoreAllArguments(); STRICT_EXPECTED_CALL(mocks, VECTOR_erase(IGNORED_PTR_ARG, IGNORED_PTR_ARG, 1)) .IgnoreArgument(1) .IgnoreArgument(2); @@ -1931,6 +1944,8 @@ TEST_FUNCTION(Gateway_LL_RemoveLink_Finds_Link_Data_Success) //Expectations STRICT_EXPECTED_CALL(mocks, VECTOR_find_if(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) .IgnoreAllArguments(); + STRICT_EXPECTED_CALL(mocks, Broker_RemoveLink(IGNORED_PTR_ARG, IGNORED_PTR_ARG)) + .IgnoreAllArguments(); STRICT_EXPECTED_CALL(mocks, VECTOR_erase(IGNORED_PTR_ARG, IGNORED_PTR_ARG, 1)) .IgnoreArgument(1) .IgnoreArgument(2); @@ -2450,6 +2465,8 @@ TEST_FUNCTION(Gateway_LL_AddLink_Succeeds) .IgnoreAllArguments();//Check Source Module. STRICT_EXPECTED_CALL(mocks, VECTOR_find_if(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) .IgnoreAllArguments();//Check Sink Module. + STRICT_EXPECTED_CALL(mocks, Broker_AddLink(IGNORED_PTR_ARG, IGNORED_PTR_ARG)) + .IgnoreAllArguments(); STRICT_EXPECTED_CALL(mocks, VECTOR_push_back(IGNORED_PTR_ARG, IGNORED_PTR_ARG, 1)) .IgnoreArgument(1) .IgnoreArgument(2);