// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. #include #include #include #include "testrunnerswitcher.h" #include "iothub.h" #include "iothub_device_client.h" #include "iothub_client_options.h" #include "iothub_message.h" #include "iothubtransporthttp.h" #include "internal/iothubtransport.h" #include "iothub_messaging.h" #include "iothub_account.h" #include "iothubtest.h" #include "azure_c_shared_utility/buffer_.h" #include "azure_c_shared_utility/threadapi.h" #include "azure_c_shared_utility/xlogging.h" static bool g_callbackRecv = false; const char* TEST_EVENT_DATA_FMT = "{\"data\":\"%.24s\",\"id\":\"%d\"}"; const char* MSG_ID1 = "MessageIdForE2E_1"; const char* MSG_ID2 = "MessageIdForE2E_2"; const char* MSG_CORRELATION_ID1 = "MessageCorrelationIdForE2E_1"; const char* MSG_CORRELATION_ID2 = "MessageCorrelationIdForE2E_2"; const char* MSG_CONTENT1 = "Message content for E2E_1"; const char* MSG_CONTENT2 = "Message content for E2E_2"; #define MSG_PROP_COUNT 3 const char* MSG_PROP_KEYS[MSG_PROP_COUNT] = { "Key1", "Key2", "Key3" }; const char* MSG_PROP_VALS[MSG_PROP_COUNT] = { "Val1", "Val2", "Val3" }; static size_t g_iotHubTestId = 0; static IOTHUB_ACCOUNT_INFO_HANDLE g_iothubAcctInfo1 = NULL; static IOTHUB_ACCOUNT_INFO_HANDLE g_iothubAcctInfo2 = NULL; static IOTHUB_ACCOUNT_INFO_HANDLE g_iothubAcctInfo3 = NULL; #define IOTHUB_COUNTER_MAX 10 #define MAX_CLOUD_TRAVEL_TIME 60.0 #define DEVICE_CREATE_WAIT 30 TEST_DEFINE_ENUM_TYPE(IOTHUB_TEST_CLIENT_RESULT, IOTHUB_TEST_CLIENT_RESULT_VALUES); TEST_DEFINE_ENUM_TYPE(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_RESULT_VALUES); TEST_DEFINE_ENUM_TYPE(MAP_RESULT, MAP_RESULT_VALUES); TEST_DEFINE_ENUM_TYPE(IOTHUB_CLIENT_CONFIRMATION_RESULT, IOTHUB_CLIENT_CONFIRMATION_RESULT_VALUES); typedef struct EXPECTED_SEND_DATA_TAG { const char* expectedString; bool wasFound; bool dataWasRecv; LOCK_HANDLE lock; IOTHUB_CLIENT_CONFIRMATION_RESULT result; } EXPECTED_SEND_DATA; typedef struct EXPECTED_RECEIVE_DATA_TAG { bool wasFound; LOCK_HANDLE lock; /*needed to protect this structure*/ } EXPECTED_RECEIVE_DATA; static size_t IoTHub_HTTP_LL_CanSend_2000_smallest_messages_batched_nCalls; static void openCompleteCallback(void* context) { (void)printf("Open completed, context: %s\n", (char*)context); } static void sendCompleteCallback(void* context, IOTHUB_MESSAGING_RESULT messagingResult) { (void)context; if (messagingResult == IOTHUB_MESSAGING_OK) { (void)printf("Message has been sent successfully\n"); } else { (void)printf("Send failed\n"); } } static void IoTHub_HTTP_LL_CanSend_2000_smallest_messages_batched_Message(IOTHUB_CLIENT_CONFIRMATION_RESULT result, void* userContextCallback) { (void)result; (void)userContextCallback; IoTHub_HTTP_LL_CanSend_2000_smallest_messages_batched_nCalls++; } static size_t IoTHub_HTTP_LL_CanSend_2000_smallest_messages_batched_with_properties_nCalls; static void IoTHub_HTTP_LL_CanSend_2000_smallest_messages_batched_with_properties_Message(IOTHUB_CLIENT_CONFIRMATION_RESULT result, void* userContextCallback) { (void)result; (void)userContextCallback; IoTHub_HTTP_LL_CanSend_2000_smallest_messages_batched_with_properties_nCalls++; } BEGIN_TEST_SUITE(iothubclient_http_e2e) static int IoTHubCallback(void* context, const char* data, size_t size) { EXPECTED_SEND_DATA* expectedData = (EXPECTED_SEND_DATA*)context; int result = 0; // 0 means "keep processing" if (expectedData != NULL) { if (Lock(expectedData->lock) != LOCK_OK) { ASSERT_FAIL("unable to lock"); } else { if ( (strlen(expectedData->expectedString) == size) && (memcmp(expectedData->expectedString, data, size) == 0) ) { expectedData->wasFound = true; result = 1; } (void)Unlock(expectedData->lock); } } return result; } static int IoTHubCallbackMultipleEvents(void* context, const char* data, size_t size) { EXPECTED_SEND_DATA** expectedData = (EXPECTED_SEND_DATA**)context; int result = 0; // 0 means "keep processing" bool allDataFound = false; if (expectedData != NULL) { allDataFound = true; for (size_t i = 0; i < 2; i++) { EXPECTED_SEND_DATA* expected = expectedData[i]; if (Lock(expected->lock) != LOCK_OK) { allDataFound = false; ASSERT_FAIL("unable to lock"); } else { if ( (strlen(expected->expectedString) == size) && (memcmp(expected->expectedString, data, size) == 0) ) { expected->wasFound = true; } allDataFound &= expected->wasFound; (void)Unlock(expected->lock); } } } if (allDataFound == true) { result = 1; } return result; } static void ReceiveConfirmationCallback(IOTHUB_CLIENT_CONFIRMATION_RESULT result, void* userContextCallback) { EXPECTED_SEND_DATA* expectedData = (EXPECTED_SEND_DATA*)userContextCallback; ASSERT_IS_NOT_NULL(userContextCallback, "userContextCallback is NULL"); if (expectedData != NULL) { LogInfo("ReceiveConfirmationCallback device=%s", expectedData->expectedString); if (Lock(expectedData->lock) != LOCK_OK) { ASSERT_FAIL("unable to lock"); } else { expectedData->result = result; if (result == IOTHUB_CLIENT_CONFIRMATION_OK) { expectedData->dataWasRecv = true; } else { LogError("ReceiveConfirmationCallback failed result=%s", MU_ENUM_TO_STRING(IOTHUB_CLIENT_CONFIRMATION_RESULT, result)); } (void)Unlock(expectedData->lock); } } } static IOTHUBMESSAGE_DISPOSITION_RESULT ReceiveMessageCallback(IOTHUB_MESSAGE_HANDLE messageHandle, void* userContextCallback) { EXPECTED_RECEIVE_DATA* receiveUserContext = (EXPECTED_RECEIVE_DATA*)userContextCallback; if (receiveUserContext == NULL) { ASSERT_FAIL("User context is NULL"); } else { if (Lock(receiveUserContext->lock) != LOCK_OK) { ASSERT_FAIL("Unable to lock"); /*because the test must absolutely be terminated*/ } else { const char* messageId; const char* correlationId; const unsigned char* content; size_t contentSize; if ((messageId = IoTHubMessage_GetMessageId(messageHandle)) == NULL) { ASSERT_FAIL("Message ID is NULL."); } if ((strcmp(messageId, MSG_ID1) != 0) && (strcmp(messageId, MSG_ID2) != 0)) { ASSERT_FAIL("Message ID mismatch."); } if ((correlationId = IoTHubMessage_GetCorrelationId(messageHandle)) == NULL) { ASSERT_FAIL("Message correlation ID is NULL."); } if ((strcmp(correlationId, MSG_CORRELATION_ID1) != 0) && (strcmp(correlationId, MSG_CORRELATION_ID2) != 0)) { ASSERT_FAIL("Message correlation ID mismatch."); } IOTHUBMESSAGE_CONTENT_TYPE contentType = IoTHubMessage_GetContentType(messageHandle); if (contentType != IOTHUBMESSAGE_BYTEARRAY) { ASSERT_FAIL("Message content type mismatch."); } else { if (IoTHubMessage_GetByteArray(messageHandle, &content, &contentSize) != IOTHUB_MESSAGE_OK) { ASSERT_FAIL("Unable to get the content of the message."); } else { (void)printf("Received new message from IoT Hub :\r\nMessage-id: %s\r\nCorrelation-id: %s\r\n", messageId, correlationId); (void)printf("\r\n"); } receiveUserContext->wasFound = true; MAP_HANDLE mapHandle = IoTHubMessage_Properties(messageHandle); if (mapHandle != NULL) { const char*const* keys; const char*const* values; size_t propertyCount = 0; if (Map_GetInternals(mapHandle, &keys, &values, &propertyCount) == MAP_OK) { receiveUserContext->wasFound = true; if (propertyCount == MSG_PROP_COUNT) { (void)printf("Message Properties:\r\n"); for (size_t index = 0; index < propertyCount; index++) { (void)printf("\tKey: %s Value: %s\r\n", keys[index], values[index]); if (strcmp(keys[index], MSG_PROP_KEYS[index]) != 0) { receiveUserContext->wasFound = false; } if (strcmp(values[index], MSG_PROP_VALS[index]) != 0) { receiveUserContext->wasFound = false; } } (void)printf("\r\n"); } else { receiveUserContext->wasFound = false; } } } } Unlock(receiveUserContext->lock); } } return IOTHUBMESSAGE_ACCEPTED; } static EXPECTED_RECEIVE_DATA* ReceiveUserContext_Create(void) { EXPECTED_RECEIVE_DATA* result = (EXPECTED_RECEIVE_DATA*)malloc(sizeof(EXPECTED_RECEIVE_DATA)); if (result != NULL) { result->wasFound = false; if ((result->lock = Lock_Init()) == NULL) { free(result); result = NULL; } } return result; } static void ReceiveUserContext_Destroy(EXPECTED_RECEIVE_DATA* data) { if (data != NULL) { (void)Lock_Deinit(data->lock); free(data); } } static EXPECTED_SEND_DATA* EventData_Create(void) { EXPECTED_SEND_DATA* result = (EXPECTED_SEND_DATA*)calloc(1, sizeof(EXPECTED_SEND_DATA)); if (result != NULL) { if ((result->lock = Lock_Init()) == NULL) { ASSERT_FAIL("unable to Lock_Init"); } else { char temp[1000]; char* tempString; time_t t = time(NULL); sprintf(temp, TEST_EVENT_DATA_FMT, ctime(&t), g_iotHubTestId); if ((tempString = (char*)malloc(strlen(temp) + 1)) == NULL) { Lock_Deinit(result->lock); free(result); result = NULL; } else { strcpy(tempString, temp); result->expectedString = tempString; result->wasFound = false; result->dataWasRecv = false; } } } return result; } static void EventData_Destroy(EXPECTED_SEND_DATA* data) { if (data != NULL) { (void)Lock_Deinit(data->lock); if (data->expectedString != NULL) { free((void*)data->expectedString); } free(data); } } static void SendEvent(IOTHUB_PROVISIONED_DEVICE* deviceToUse) { // arrange IOTHUB_DEVICE_CLIENT_HANDLE iotHubClientHandle; IOTHUB_MESSAGE_HANDLE msgHandle; EXPECTED_SEND_DATA* sendData = EventData_Create(); ASSERT_IS_NOT_NULL(sendData, "Failure creating data to be sent"); // Send the Event { IOTHUB_CLIENT_RESULT result; // Create the IoT Hub Data iotHubClientHandle = IoTHubDeviceClient_CreateFromConnectionString(deviceToUse->connectionString, HTTP_Protocol); ASSERT_IS_NOT_NULL(iotHubClientHandle, "Failure creating IothubClient handle"); msgHandle = IoTHubMessage_CreateFromByteArray((const unsigned char*)sendData->expectedString, strlen(sendData->expectedString)); ASSERT_IS_NOT_NULL(msgHandle, "Failure to create message handle"); if (deviceToUse->howToCreate == IOTHUB_ACCOUNT_AUTH_X509) { result = IoTHubDeviceClient_SetOption(iotHubClientHandle, OPTION_X509_CERT, deviceToUse->certificate); ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result, "Could not set the device x509 certificate"); result = IoTHubDeviceClient_SetOption(iotHubClientHandle, OPTION_X509_PRIVATE_KEY, deviceToUse->primaryAuthentication); ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result, "Could not set the device x509 privateKey"); } // act result = IoTHubDeviceClient_SendEventAsync(iotHubClientHandle, msgHandle, ReceiveConfirmationCallback, sendData); ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result, "Failure calling IoTHubDeviceClient_SendEventAsync"); } time_t beginOperation, nowTime; beginOperation = time(NULL); while ( (nowTime = time(NULL)), (difftime(nowTime, beginOperation) < MAX_CLOUD_TRAVEL_TIME) // time box ) { if (Lock(sendData->lock) != LOCK_OK) { ASSERT_FAIL("unable to lock"); } else { if (sendData->dataWasRecv) { Unlock(sendData->lock); break; } Unlock(sendData->lock); } ThreadAPI_Sleep(100); } if (Lock(sendData->lock) != LOCK_OK) { ASSERT_FAIL("unable to lock"); } else { ASSERT_IS_TRUE(sendData->dataWasRecv, "Failure sending event to IotHub, result=%s", MU_ENUM_TO_STRING(IOTHUB_CLIENT_CONFIRMATION_RESULT, sendData->result)); // was found is written by the callback... (void)Unlock(sendData->lock); } { IOTHUB_TEST_HANDLE iotHubTestHandle = IoTHubTest_Initialize(IoTHubAccount_GetEventHubConnectionString(g_iothubAcctInfo1), IoTHubAccount_GetIoTHubConnString(g_iothubAcctInfo1), deviceToUse->deviceId, IoTHubAccount_GetEventhubListenName(g_iothubAcctInfo1), IoTHubAccount_GetEventhubAccessKey(g_iothubAcctInfo1), IoTHubAccount_GetSharedAccessSignature(g_iothubAcctInfo1), IoTHubAccount_GetEventhubConsumerGroup(g_iothubAcctInfo1)); ASSERT_IS_NOT_NULL(iotHubTestHandle); IOTHUB_TEST_CLIENT_RESULT result = IoTHubTest_ListenForEventForMaxDrainTime(iotHubTestHandle, IoTHubCallback, IoTHubAccount_GetIoTHubPartitionCount(g_iothubAcctInfo1), sendData); ASSERT_ARE_EQUAL(IOTHUB_TEST_CLIENT_RESULT, IOTHUB_TEST_CLIENT_OK, result); IoTHubTest_Deinit(iotHubTestHandle); } // assert ASSERT_IS_TRUE(sendData->wasFound, "Failure receiving data from eventhub"); // was found is written by the callback...*/ // cleanup IoTHubMessage_Destroy(msgHandle); IoTHubDeviceClient_Destroy(iotHubClientHandle); EventData_Destroy(sendData); } static void RecvMessage(IOTHUB_PROVISIONED_DEVICE* deviceToUse) { // arrange IOTHUB_DEVICE_CLIENT_HANDLE iotHubClientHandle; IOTHUB_SERVICE_CLIENT_AUTH_HANDLE iotHubServiceClientHandle; IOTHUB_MESSAGING_CLIENT_HANDLE iotHubMessagingHandle; IOTHUB_MESSAGING_RESULT iotHubMessagingResult; IOTHUB_MESSAGE_RESULT iotHubMessageResult; EXPECTED_RECEIVE_DATA* receiveUserContext; IOTHUB_MESSAGE_HANDLE messageHandle; // act IoTHub_Init(); // Create Service Client iotHubServiceClientHandle = IoTHubServiceClientAuth_CreateFromConnectionString(IoTHubAccount_GetIoTHubConnString(g_iothubAcctInfo1)); ASSERT_IS_NOT_NULL(iotHubServiceClientHandle, "Could not initialize IoTHubServiceClient to send C2D messages to the device"); iotHubMessagingHandle = IoTHubMessaging_Create(iotHubServiceClientHandle); ASSERT_IS_NOT_NULL(iotHubMessagingHandle, "Could not initialize IoTHubMessaging to send C2D messages to the device"); iotHubMessagingResult = IoTHubMessaging_Open(iotHubMessagingHandle, openCompleteCallback, (void*)"Context string for open"); ASSERT_ARE_EQUAL(int, IOTHUB_MESSAGING_OK, iotHubMessagingResult); // Create user context and message receiveUserContext = ReceiveUserContext_Create(); ASSERT_IS_NOT_NULL(receiveUserContext, "Could not create receive user context"); messageHandle = IoTHubMessage_CreateFromString(MSG_CONTENT1); ASSERT_IS_NOT_NULL(messageHandle, "Could not create IoTHubMessage to send C2D messages to the device"); iotHubMessageResult = IoTHubMessage_SetMessageId(messageHandle, MSG_ID1); ASSERT_ARE_EQUAL(int, IOTHUB_MESSAGING_OK, iotHubMessageResult); iotHubMessageResult = IoTHubMessage_SetCorrelationId(messageHandle, MSG_CORRELATION_ID1); ASSERT_ARE_EQUAL(int, IOTHUB_MESSAGING_OK, iotHubMessageResult); MAP_HANDLE mapHandle = IoTHubMessage_Properties(messageHandle); for (size_t i = 0; i < MSG_PROP_COUNT; i++) { if (Map_AddOrUpdate(mapHandle, MSG_PROP_KEYS[i], MSG_PROP_VALS[i]) != MAP_OK) { (void)printf("ERROR: Map_AddOrUpdate failed for property %zu!\r\n", i); } } iotHubMessagingResult = IoTHubMessaging_SendAsync(iotHubMessagingHandle, deviceToUse->deviceId, messageHandle, sendCompleteCallback, receiveUserContext); ASSERT_ARE_EQUAL(int, IOTHUB_MESSAGING_OK, iotHubMessagingResult, "IoTHubMessaging_SendAsync failed, could not send C2D message to the device"); iotHubClientHandle = IoTHubDeviceClient_CreateFromConnectionString(deviceToUse->connectionString, HTTP_Protocol); ASSERT_IS_NOT_NULL(iotHubClientHandle, "Failure creating Iothub Client"); if (deviceToUse->howToCreate == IOTHUB_ACCOUNT_AUTH_X509) { IOTHUB_CLIENT_RESULT result; result = IoTHubDeviceClient_SetOption(iotHubClientHandle, OPTION_X509_CERT, deviceToUse->certificate); ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result, "Could not set the device x509 certificate"); result = IoTHubDeviceClient_SetOption(iotHubClientHandle, OPTION_X509_PRIVATE_KEY, deviceToUse->primaryAuthentication); ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result, "Could not set the device x509 privateKey"); } IOTHUB_CLIENT_RESULT result = IoTHubDeviceClient_SetMessageCallback(iotHubClientHandle, ReceiveMessageCallback, receiveUserContext); ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result, "Failure setting message callback"); unsigned int minimumPollingTime = 1; /*because it should not wait*/ if (IoTHubDeviceClient_SetOption(iotHubClientHandle, OPTION_MIN_POLLING_TIME, &minimumPollingTime) != IOTHUB_CLIENT_OK) { printf("failure to set option \"MinimumPollingTime\"\r\n"); } time_t beginOperation, nowTime; beginOperation = time(NULL); while ( ( (nowTime = time(NULL)), (difftime(nowTime, beginOperation) < MAX_CLOUD_TRAVEL_TIME) //time box ) ) { if (Lock(receiveUserContext->lock) != LOCK_OK) { ASSERT_FAIL("unable ot lock"); } else { if (receiveUserContext->wasFound) { (void)Unlock(receiveUserContext->lock); break; } (void)Unlock(receiveUserContext->lock); } ThreadAPI_Sleep(100); } // assert ASSERT_IS_TRUE(receiveUserContext->wasFound, "Failure retrieving message that was sent to IotHub."); // was found is written by the callback... // cleanup IoTHubMessage_Destroy(messageHandle); IoTHubMessaging_Close(iotHubMessagingHandle); IoTHubMessaging_Destroy(iotHubMessagingHandle); IoTHubServiceClientAuth_Destroy(iotHubServiceClientHandle); IoTHubDeviceClient_Destroy(iotHubClientHandle); ReceiveUserContext_Destroy(receiveUserContext); } TEST_SUITE_INITIALIZE(TestClassInitialize) { IoTHub_Init(); g_iothubAcctInfo1 = IoTHubAccount_Init(false); ASSERT_IS_NOT_NULL(g_iothubAcctInfo1); g_iothubAcctInfo2 = IoTHubAccount_Init(false); ASSERT_IS_NOT_NULL(g_iothubAcctInfo2, "Failure to init 2nd IoTHubAccount information."); g_iothubAcctInfo3 = IoTHubAccount_Init(false); ASSERT_IS_NOT_NULL(g_iothubAcctInfo3, "Failure to init 3rd IoTHubAccount information."); IoTHub_Init(); } TEST_SUITE_CLEANUP(TestClassCleanup) { IoTHubAccount_deinit(g_iothubAcctInfo3); IoTHubAccount_deinit(g_iothubAcctInfo2); IoTHubAccount_deinit(g_iothubAcctInfo1); IoTHub_Deinit(); } TEST_FUNCTION_INITIALIZE(TestMethodInitialize) { g_iotHubTestId++; } TEST_FUNCTION_CLEANUP(TestMethodCleanup) { } TEST_FUNCTION(IoTHub_HTTP_SendEvent_e2e_sas) { SendEvent(IoTHubAccount_GetSASDevice(g_iothubAcctInfo1)); } #ifndef __APPLE__ TEST_FUNCTION(IoTHub_HTTP_SendEvent_e2e_x509) { SendEvent(IoTHubAccount_GetX509Device(g_iothubAcctInfo1)); } #endif TEST_FUNCTION(IoTHub_HTTP_SendEvent_Shared_e2e) { // arrange TRANSPORT_HANDLE transportHandle; IOTHUB_CLIENT_CONFIG iotHubConfig1 = { 0 }; IOTHUB_CLIENT_CONFIG iotHubConfig2 = { 0 }; IOTHUB_DEVICE_CLIENT_HANDLE iotHubClientHandle1; IOTHUB_DEVICE_CLIENT_HANDLE iotHubClientHandle2; IOTHUB_MESSAGE_HANDLE msgHandle1; IOTHUB_MESSAGE_HANDLE msgHandle2; iotHubConfig1.iotHubName = IoTHubAccount_GetIoTHubName(g_iothubAcctInfo3); iotHubConfig1.iotHubSuffix = IoTHubAccount_GetIoTHubSuffix(g_iothubAcctInfo3); iotHubConfig1.deviceId = IoTHubAccount_GetSASDevice(g_iothubAcctInfo3)->deviceId; iotHubConfig1.deviceKey = IoTHubAccount_GetSASDevice(g_iothubAcctInfo3)->primaryAuthentication; iotHubConfig1.protocol = HTTP_Protocol; iotHubConfig2.iotHubName = IoTHubAccount_GetIoTHubName(g_iothubAcctInfo2); iotHubConfig2.iotHubSuffix = IoTHubAccount_GetIoTHubSuffix(g_iothubAcctInfo2); iotHubConfig2.deviceId = IoTHubAccount_GetSASDevice(g_iothubAcctInfo2)->deviceId; iotHubConfig2.deviceKey = IoTHubAccount_GetSASDevice(g_iothubAcctInfo2)->primaryAuthentication; iotHubConfig2.protocol = HTTP_Protocol; EXPECTED_SEND_DATA* sendData1 = EventData_Create(); EXPECTED_SEND_DATA* sendData2 = EventData_Create(); ASSERT_IS_NOT_NULL(sendData1, "Failure creating set 1 data to be sent"); ASSERT_IS_NOT_NULL(sendData2, "Failure creating set 2 data to be sent"); // Create the transport { transportHandle = IoTHubTransport_Create(HTTP_Protocol, IoTHubAccount_GetIoTHubName(g_iothubAcctInfo3), IoTHubAccount_GetIoTHubSuffix(g_iothubAcctInfo3)); ASSERT_IS_NOT_NULL(transportHandle, "Failure creating transport handle."); // Create device clients iotHubClientHandle1 = IoTHubDeviceClient_CreateWithTransport(transportHandle, &iotHubConfig1); ASSERT_IS_NOT_NULL(iotHubClientHandle1, "Failure creating IothubClient handle device 1"); iotHubClientHandle2 = IoTHubDeviceClient_CreateWithTransport(transportHandle, &iotHubConfig2); ASSERT_IS_NOT_NULL(iotHubClientHandle2, "Failure creating IothubClient handle device 2"); } // Send the Event device 1 { IOTHUB_CLIENT_RESULT result; // Create the IoT Hub Data msgHandle1 = IoTHubMessage_CreateFromByteArray((const unsigned char*)sendData1->expectedString, strlen(sendData1->expectedString)); ASSERT_IS_NOT_NULL(msgHandle1, "Failure to create message handle"); // act LogInfo("Send the Event device 1"); result = IoTHubDeviceClient_SendEventAsync(iotHubClientHandle1, msgHandle1, ReceiveConfirmationCallback, sendData1); ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result, "Failure calling IoTHubDeviceClient_SendEventAsync"); } // Send the Event device 2 { IOTHUB_CLIENT_RESULT result; // Create the IoT Hub Data msgHandle2 = IoTHubMessage_CreateFromByteArray((const unsigned char*)sendData2->expectedString, strlen(sendData2->expectedString)); ASSERT_IS_NOT_NULL(msgHandle2, "Failure to create message handle"); // act LogInfo("Send the Event device 2"); result = IoTHubDeviceClient_SendEventAsync(iotHubClientHandle2, msgHandle2, ReceiveConfirmationCallback, sendData2); ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result, "Failure calling IoTHubDeviceClient_SendEventAsync"); } time_t beginOperation, nowTime; beginOperation = time(NULL); bool dataWasRecv1 = false; bool dataWasRecv2 = false; while ( (nowTime = time(NULL)), (difftime(nowTime, beginOperation) < MAX_CLOUD_TRAVEL_TIME) // time box ) { if (Lock(sendData1->lock) != LOCK_OK) { ASSERT_FAIL("unable to lock send data 1"); } else { dataWasRecv1 = sendData1->dataWasRecv; // was found is written by the callback... Unlock(sendData1->lock); } if (Lock(sendData2->lock) != LOCK_OK) { ASSERT_FAIL("unable to lock send data 2"); } else { dataWasRecv2 = sendData2->dataWasRecv; // was found is written by the callback... Unlock(sendData2->lock); } if (dataWasRecv1 && dataWasRecv2) { break; } ThreadAPI_Sleep(100); } ASSERT_IS_TRUE(dataWasRecv1, "Failure sending data to IotHub, device 1, result=%s", MU_ENUM_TO_STRING(IOTHUB_CLIENT_CONFIRMATION_RESULT, sendData1->result)); ASSERT_IS_TRUE(dataWasRecv2, "Failure sending data to IotHub, device 2, result=%s", MU_ENUM_TO_STRING(IOTHUB_CLIENT_CONFIRMATION_RESULT, sendData2->result)); { EXPECTED_SEND_DATA* sendList[2]; sendList[0] = sendData1; sendList[1] = sendData2; IOTHUB_TEST_HANDLE iotHubTestHandle1 = IoTHubTest_Initialize(IoTHubAccount_GetEventHubConnectionString(g_iothubAcctInfo3), IoTHubAccount_GetIoTHubConnString(g_iothubAcctInfo3), IoTHubAccount_GetSASDevice(g_iothubAcctInfo3)->deviceId, IoTHubAccount_GetEventhubListenName(g_iothubAcctInfo1), IoTHubAccount_GetEventhubAccessKey(g_iothubAcctInfo1), IoTHubAccount_GetSharedAccessSignature(g_iothubAcctInfo1), IoTHubAccount_GetEventhubConsumerGroup(g_iothubAcctInfo1)); ASSERT_IS_NOT_NULL(iotHubTestHandle1); IOTHUB_TEST_CLIENT_RESULT result = IoTHubTest_ListenForEventForMaxDrainTime(iotHubTestHandle1, IoTHubCallbackMultipleEvents, IoTHubAccount_GetIoTHubPartitionCount(g_iothubAcctInfo1), sendList); ASSERT_ARE_EQUAL(IOTHUB_TEST_CLIENT_RESULT, IOTHUB_TEST_CLIENT_OK, result); IoTHubTest_Deinit(iotHubTestHandle1); } // assert ASSERT_IS_TRUE(sendData1->wasFound, "Failure receiving client 1 data from eventhub"); // was found is written by the callback...*/ ASSERT_IS_TRUE(sendData2->wasFound, "Failure receiving client 2 data from eventhub"); // was found is written by the callback...*/ // cleanup IoTHubMessage_Destroy(msgHandle2); IoTHubMessage_Destroy(msgHandle1); IoTHubDeviceClient_Destroy(iotHubClientHandle2); IoTHubDeviceClient_Destroy(iotHubClientHandle1); IoTHubTransport_Destroy(transportHandle); EventData_Destroy(sendData2); EventData_Destroy(sendData1); } TEST_FUNCTION(IoTHub_HTTP_RecvMessage_E2ETest_sas) { RecvMessage(IoTHubAccount_GetSASDevice(g_iothubAcctInfo1)); } #ifndef __APPLE__ TEST_FUNCTION(IoTHub_HTTP_RecvMessage_E2ETest_x509) { RecvMessage(IoTHubAccount_GetX509Device(g_iothubAcctInfo1)); } #endif TEST_FUNCTION(IoTHub_HTTP_RecvMessage_shared_E2ETest) { // arrange TRANSPORT_HANDLE transportHandle; IOTHUB_CLIENT_CONFIG iotHubConfig1 = { 0 }; IOTHUB_CLIENT_CONFIG iotHubConfig2 = { 0 }; IOTHUB_DEVICE_CLIENT_HANDLE iotHubClientHandle1; IOTHUB_DEVICE_CLIENT_HANDLE iotHubClientHandle2; IOTHUB_SERVICE_CLIENT_AUTH_HANDLE iotHubServiceClientHandle1; IOTHUB_SERVICE_CLIENT_AUTH_HANDLE iotHubServiceClientHandle2; IOTHUB_MESSAGING_CLIENT_HANDLE iotHubMessagingHandle1; IOTHUB_MESSAGING_CLIENT_HANDLE iotHubMessagingHandle2; IOTHUB_MESSAGING_RESULT iotHubMessagingResult; IOTHUB_MESSAGE_RESULT iotHubMessageResult; EXPECTED_RECEIVE_DATA* receiveUserContext1; EXPECTED_RECEIVE_DATA* receiveUserContext2; IOTHUB_MESSAGE_HANDLE messageHandle1; IOTHUB_MESSAGE_HANDLE messageHandle2; MAP_HANDLE mapHandle1; MAP_HANDLE mapHandle2; // act iotHubConfig1.iotHubName = IoTHubAccount_GetIoTHubName(g_iothubAcctInfo3); iotHubConfig1.iotHubSuffix = IoTHubAccount_GetIoTHubSuffix(g_iothubAcctInfo3); iotHubConfig1.deviceId = IoTHubAccount_GetSASDevice(g_iothubAcctInfo3)->deviceId; iotHubConfig1.deviceKey = IoTHubAccount_GetSASDevice(g_iothubAcctInfo3)->primaryAuthentication; iotHubConfig1.protocol = HTTP_Protocol; iotHubConfig2.iotHubName = IoTHubAccount_GetIoTHubName(g_iothubAcctInfo2); iotHubConfig2.iotHubSuffix = IoTHubAccount_GetIoTHubSuffix(g_iothubAcctInfo2); iotHubConfig2.deviceId = IoTHubAccount_GetSASDevice(g_iothubAcctInfo2)->deviceId; iotHubConfig2.deviceKey = IoTHubAccount_GetSASDevice(g_iothubAcctInfo2)->primaryAuthentication; iotHubConfig2.protocol = HTTP_Protocol; IoTHub_Init(); // Create the transport { transportHandle = IoTHubTransport_Create(HTTP_Protocol, IoTHubAccount_GetIoTHubName(g_iothubAcctInfo3), IoTHubAccount_GetIoTHubSuffix(g_iothubAcctInfo3)); ASSERT_IS_NOT_NULL(transportHandle, "Failure creating transport handle."); } // Create Service Client1 iotHubServiceClientHandle1 = IoTHubServiceClientAuth_CreateFromConnectionString(IoTHubAccount_GetIoTHubConnString(g_iothubAcctInfo3)); ASSERT_IS_NOT_NULL(iotHubServiceClientHandle1, "Could not initialize IoTHubServiceClient to send C2D messages to the device"); // Create Messaging1 iotHubMessagingHandle1 = IoTHubMessaging_Create(iotHubServiceClientHandle1); ASSERT_IS_NOT_NULL(iotHubMessagingHandle1, "Could not initialize IoTHubMessaging to send C2D messages to the device"); iotHubMessagingResult = IoTHubMessaging_Open(iotHubMessagingHandle1, openCompleteCallback, (void*)"Context string for open"); ASSERT_ARE_EQUAL(int, IOTHUB_MESSAGING_OK, iotHubMessagingResult); // Create user context and message receiveUserContext1 = ReceiveUserContext_Create(); ASSERT_IS_NOT_NULL(receiveUserContext1, "Could not create receive user context"); messageHandle1 = IoTHubMessage_CreateFromString(MSG_CONTENT1); ASSERT_IS_NOT_NULL(messageHandle1, "Could not create IoTHubMessage to send C2D messages to the device"); iotHubMessageResult = IoTHubMessage_SetMessageId(messageHandle1, MSG_ID1); ASSERT_ARE_EQUAL(int, IOTHUB_MESSAGING_OK, iotHubMessageResult); iotHubMessageResult = IoTHubMessage_SetCorrelationId(messageHandle1, MSG_CORRELATION_ID1); ASSERT_ARE_EQUAL(int, IOTHUB_MESSAGING_OK, iotHubMessageResult); mapHandle1 = IoTHubMessage_Properties(messageHandle1); for (size_t i = 0; i < MSG_PROP_COUNT; i++) { if (Map_AddOrUpdate(mapHandle1, MSG_PROP_KEYS[i], MSG_PROP_VALS[i]) != MAP_OK) { (void)printf("ERROR: Map_AddOrUpdate failed for property %zu!\r\n", i); } } iotHubMessagingResult = IoTHubMessaging_SendAsync(iotHubMessagingHandle1, iotHubConfig1.deviceId, messageHandle1, sendCompleteCallback, receiveUserContext1); ASSERT_ARE_EQUAL(int, IOTHUB_MESSAGING_OK, iotHubMessagingResult, "IoTHubMessaging_SendAsync failed, could not send C2D message to the device"); // Create Service Client2 iotHubServiceClientHandle2 = IoTHubServiceClientAuth_CreateFromConnectionString(IoTHubAccount_GetIoTHubConnString(g_iothubAcctInfo2)); ASSERT_IS_NOT_NULL(iotHubServiceClientHandle2, "Could not initialize IoTHubServiceClient to send C2D messages to the device"); // Create Messaging2 iotHubMessagingHandle2 = IoTHubMessaging_Create(iotHubServiceClientHandle2); ASSERT_IS_NOT_NULL(iotHubMessagingHandle2, "Could not initialize IoTHubMessaging to send C2D messages to the device"); iotHubMessagingResult = IoTHubMessaging_Open(iotHubMessagingHandle2, openCompleteCallback, (void*)"Context string for open"); ASSERT_ARE_EQUAL(int, IOTHUB_MESSAGING_OK, iotHubMessagingResult); // Create user context and message receiveUserContext2 = ReceiveUserContext_Create(); ASSERT_IS_NOT_NULL(receiveUserContext2, "Could not create receive user context"); messageHandle2 = IoTHubMessage_CreateFromString(MSG_CONTENT2); ASSERT_IS_NOT_NULL(messageHandle2, "Could not create IoTHubMessage to send C2D messages to the device"); iotHubMessageResult = IoTHubMessage_SetMessageId(messageHandle2, MSG_ID2); ASSERT_ARE_EQUAL(int, IOTHUB_MESSAGING_OK, iotHubMessageResult); iotHubMessageResult = IoTHubMessage_SetCorrelationId(messageHandle2, MSG_CORRELATION_ID2); ASSERT_ARE_EQUAL(int, IOTHUB_MESSAGING_OK, iotHubMessageResult); mapHandle2 = IoTHubMessage_Properties(messageHandle2); for (size_t i = 0; i < MSG_PROP_COUNT; i++) { if (Map_AddOrUpdate(mapHandle2, MSG_PROP_KEYS[i], MSG_PROP_VALS[i]) != MAP_OK) { (void)printf("ERROR: Map_AddOrUpdate failed for property %zu!\r\n", i); } } iotHubMessagingResult = IoTHubMessaging_SendAsync(iotHubMessagingHandle2, iotHubConfig2.deviceId, messageHandle2, sendCompleteCallback, receiveUserContext1); ASSERT_ARE_EQUAL(int, IOTHUB_MESSAGING_OK, iotHubMessagingResult, "IoTHubMessaging_SendAsync failed, could not send C2D message to the device"); // Create Device Client iotHubClientHandle1 = IoTHubDeviceClient_CreateWithTransport(transportHandle, &iotHubConfig1); ASSERT_IS_NOT_NULL(iotHubClientHandle1, "Failure creating Iothub Client, device 1"); iotHubClientHandle2 = IoTHubDeviceClient_CreateWithTransport(transportHandle, &iotHubConfig2); ASSERT_IS_NOT_NULL(iotHubClientHandle2, "Failure creating Iothub Client, device 2"); IOTHUB_CLIENT_RESULT result1 = IoTHubDeviceClient_SetMessageCallback(iotHubClientHandle1, ReceiveMessageCallback, receiveUserContext1); ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result1, "Failure setting message callback, device 1"); IOTHUB_CLIENT_RESULT result2 = IoTHubDeviceClient_SetMessageCallback(iotHubClientHandle2, ReceiveMessageCallback, receiveUserContext2); ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result2, "Failure setting message callback device 2"); unsigned int minimumPollingTime = 1; /*because it should not wait*/ if (IoTHubDeviceClient_SetOption(iotHubClientHandle1, OPTION_MIN_POLLING_TIME, &minimumPollingTime) != IOTHUB_CLIENT_OK) { printf("failure to set option \"MinimumPollingTime\"\r\n"); } if (IoTHubDeviceClient_SetOption(iotHubClientHandle2, OPTION_MIN_POLLING_TIME, &minimumPollingTime) != IOTHUB_CLIENT_OK) { printf("failure to set option \"MinimumPollingTime\"\r\n"); } time_t beginOperation, nowTime; bool wasFound1 = false; bool wasFound2 = false; beginOperation = time(NULL); while ( ( (nowTime = time(NULL)), (difftime(nowTime, beginOperation) < MAX_CLOUD_TRAVEL_TIME) //time box ) ) { if (Lock(receiveUserContext1->lock) != LOCK_OK) { ASSERT_FAIL("unable to lock"); } else { wasFound1 = receiveUserContext1->wasFound; // was found is written by the callback... (void)Unlock(receiveUserContext1->lock); } if (Lock(receiveUserContext2->lock) != LOCK_OK) { ASSERT_FAIL("unable to lock"); } else { wasFound2 = receiveUserContext2->wasFound; // was found is written by the callback... (void)Unlock(receiveUserContext2->lock); } if (wasFound1 && wasFound2) { break; } ThreadAPI_Sleep(100); } // assert ASSERT_IS_TRUE(wasFound1, "Failure retrieving message from client 1 that was sent to IotHub."); ASSERT_IS_TRUE(wasFound2, "Failure retrieving message from client 2 that was sent to IotHub."); // cleanup IoTHubDeviceClient_Destroy(iotHubClientHandle2); IoTHubDeviceClient_Destroy(iotHubClientHandle1); IoTHubMessage_Destroy(messageHandle2); ReceiveUserContext_Destroy(receiveUserContext2); IoTHubMessaging_Close(iotHubMessagingHandle2); //sync IoTHubMessaging_Destroy(iotHubMessagingHandle2); IoTHubServiceClientAuth_Destroy(iotHubServiceClientHandle2); IoTHubMessage_Destroy(messageHandle1); ReceiveUserContext_Destroy(receiveUserContext1); IoTHubMessaging_Close(iotHubMessagingHandle1); IoTHubMessaging_Destroy(iotHubMessagingHandle1); IoTHubServiceClientAuth_Destroy(iotHubServiceClientHandle1); IoTHubTransport_Destroy(transportHandle); } END_TEST_SUITE(iothubclient_http_e2e)