diff --git a/iothub_client/CMakeLists.txt b/iothub_client/CMakeLists.txt index db4f6f6b24..bed1e2cb8c 100644 --- a/iothub_client/CMakeLists.txt +++ b/iothub_client/CMakeLists.txt @@ -250,9 +250,7 @@ endif() set(IOTHUB_CLIENT_INC_FOLDER ${CMAKE_CURRENT_LIST_DIR}/inc CACHE INTERNAL "this is what needs to be included if using iothub_client lib" FORCE) -if(NOT ${dont_use_uploadtoblob} OR ${use_edge_modules}) - include_directories(../deps/parson) -endif() +include_directories(../deps/parson) include_directories(${DEV_AUTH_MODULES_CLIENT_INC_FOLDER}) include_directories(${AZURE_C_SHARED_UTILITY_INCLUDES}) diff --git a/iothub_client/inc/internal/iothub_client_diagnostic.h b/iothub_client/inc/internal/iothub_client_diagnostic.h index deb7fc1549..f4c3e20989 100644 --- a/iothub_client/inc/internal/iothub_client_diagnostic.h +++ b/iothub_client/inc/internal/iothub_client_diagnostic.h @@ -21,6 +21,7 @@ extern "C" { #include #endif +/* Deprecated: Use IOTHUB_DISTRIBUTED_TRACING_SETTING_DATA_TAG instead with IoTHubClient_DistributedTracing_AddToMessageHeadersIfNecessary API */ /** @brief diagnostic related setting */ typedef struct IOTHUB_DIAGNOSTIC_SETTING_DATA_TAG { @@ -28,18 +29,64 @@ typedef struct IOTHUB_DIAGNOSTIC_SETTING_DATA_TAG uint32_t currentMessageNumber; } IOTHUB_DIAGNOSTIC_SETTING_DATA; +#define IOTHUB_DISTRIBUTED_TRACING_SAMPLING_MODE_VALUE \ + IOTHUB_DISTRIBUTED_TRACING_SAMPLING_MODE_NOT_SET, \ + IOTHUB_DISTRIBUTED_TRACING_SAMPLING_MODE_ON, \ + IOTHUB_DISTRIBUTED_TRACING_SAMPLING_MODE_OFF, \ + IOTHUB_DISTRIBUTED_TRACING_SAMPLING_MODE_INHERIT +DEFINE_ENUM(IOTHUB_DISTRIBUTED_TRACING_SAMPLING_MODE, IOTHUB_DISTRIBUTED_TRACING_SAMPLING_MODE_VALUE); + +/** @brief distributed tracing settings */ +typedef struct IOTHUB_DISTRIBUTED_TRACING_SETTING_DATA_TAG +{ + bool policyEnabled; + + /* Distributed Tracing sampling enabled flag. + Possible options from server - On (1), Off (2), Inherit (3) */ + IOTHUB_DISTRIBUTED_TRACING_SAMPLING_MODE samplingMode; + + /* Distributed tracing fixed-rate sampling percentage. + Set to 100/N where N is an integer. E.g. 50 (=100/2), 33.33 (=100/3), 25 (=100/4), 20, 1 (=100/100), 0.1 (=100/1000) */ + uint8_t samplingRate; + + /* Distributed tracing message sequence number */ + uint32_t currentMessageNumber; +} IOTHUB_DISTRIBUTED_TRACING_SETTING_DATA; + /** - * @brief Adds diagnostic information to message if: - * a. diagSetting->diagSamplingPercentage > 0 and - * b. the number of current message matches sample rule specified by diagSetting->diagSamplingPercentage - * - * @param diagSetting Pointer to an @c IOTHUB_DIAGNOSTIC_SETTING_DATA structure - * - * @param messageHandle message handle - * - * @return 0 upon success - */ -MOCKABLE_FUNCTION(, int, IoTHubClient_Diagnostic_AddIfNecessary, IOTHUB_DIAGNOSTIC_SETTING_DATA *, diagSetting, IOTHUB_MESSAGE_HANDLE, messageHandle); +* @brief Adds diagnostic information to message if: +** DEPRECATED: Use IoTHubClient_DistributedTracing_AddToMessageHeadersIfNecessary instead. ** +* a. diagSetting->diagSamplingPercentage > 0 and +* b. the number of current message matches sample rule specified by diagSetting->diagSamplingPercentage +* +* @param diagSetting Pointer to an @c IOTHUB_DIAGNOSTIC_SETTING_DATA structure +* @param messageHandle message handle +* @return 0 upon success, non-zero otherwise +*/ +MOCKABLE_FUNCTION(, int, IoTHubClient_Diagnostic_AddIfNecessary, IOTHUB_DIAGNOSTIC_SETTING_DATA*, diagSetting, IOTHUB_MESSAGE_HANDLE, messageHandle); + +/** +* @brief Adds tracestate information to message if: +* a. distributedTracingSetting->sampingMode = true +* b. distributedTracingSetting->samplingRate > 0 and +* c. the number of current message matches sample rule specified by distributedTracingSetting->samplingRate +* +* @param distributedTracingSetting Pointer to an @c IOTHUB_DISTRIBUTED_TRACING_SETTING_DATA structure +* @param messageHandle message handle +* @return 0 upon success, non-zero otherwise +*/ +MOCKABLE_FUNCTION(, int, IoTHubClient_DistributedTracing_AddToMessageHeadersIfNecessary, IOTHUB_DISTRIBUTED_TRACING_SETTING_DATA*, distributedTracingSetting, IOTHUB_MESSAGE_HANDLE, messageHandle); + +/** +* @brief Update distributed tracing settings from device twin +* +* @param distributedTracingSetting Pointer to an @c IOTHUB_DISTRIBUTED_TRACING_SETTING_DATA structure +* @param isPartialUpdate Whether device twin is complete or partial update +* @param payLoad Received device twin +* @param reportedStatePayload Reported state payload for distributed tracing setting +* @return 0 upon success, non-zero otherwise +*/ +MOCKABLE_FUNCTION(, int, IoTHubClient_DistributedTracing_UpdateFromTwin, IOTHUB_DISTRIBUTED_TRACING_SETTING_DATA*, distributedTracingSetting, bool, isPartialUpdate, const unsigned char*, payLoad, STRING_HANDLE*, reportedStatePayload); #ifdef __cplusplus } diff --git a/iothub_client/inc/iothub_client_core.h b/iothub_client/inc/iothub_client_core.h index 878d6c1948..fbd296fd6b 100644 --- a/iothub_client/inc/iothub_client_core.h +++ b/iothub_client/inc/iothub_client_core.h @@ -59,6 +59,7 @@ extern "C" MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClientCore_SendEventToOutputAsync, IOTHUB_CLIENT_CORE_HANDLE, iotHubClientHandle, IOTHUB_MESSAGE_HANDLE, eventMessageHandle, const char*, outputName, IOTHUB_CLIENT_EVENT_CONFIRMATION_CALLBACK, eventConfirmationCallback, void*, userContextCallback); MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClientCore_SetInputMessageCallback, IOTHUB_CLIENT_CORE_HANDLE, iotHubClientHandle, const char*, inputName, IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC, eventHandlerCallback, void*, userContextCallback); + MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClientCore_EnablePolicyConfiguration, IOTHUB_CLIENT_CORE_HANDLE, iotHubClientHandle, POLICY_CONFIGURATION_TYPE, policyType, bool, enablePolicyConfiguration); #ifdef USE_EDGE_MODULES MOCKABLE_FUNCTION(, IOTHUB_CLIENT_CORE_HANDLE, IoTHubClientCore_CreateFromEnvironment, IOTHUB_CLIENT_TRANSPORT_PROVIDER, protocol); diff --git a/iothub_client/inc/iothub_client_core_common.h b/iothub_client/inc/iothub_client_core_common.h index 4c91f655bc..f83e990d25 100644 --- a/iothub_client/inc/iothub_client_core_common.h +++ b/iothub_client/inc/iothub_client_core_common.h @@ -235,6 +235,11 @@ extern "C" const char* deviceSasToken; } IOTHUB_CLIENT_DEVICE_CONFIG; +#define POLICY_CONFIGURATION_TYPE_VALUES \ + POLICY_CONFIGURATION_DISTRIBUTED_TRACING + + DEFINE_ENUM(POLICY_CONFIGURATION_TYPE, POLICY_CONFIGURATION_TYPE_VALUES); + #ifdef __cplusplus } #endif diff --git a/iothub_client/inc/iothub_client_core_ll.h b/iothub_client/inc/iothub_client_core_ll.h index 9bcba3ebdf..12b92e6f6a 100644 --- a/iothub_client/inc/iothub_client_core_ll.h +++ b/iothub_client/inc/iothub_client_core_ll.h @@ -68,7 +68,8 @@ extern "C" #ifdef USE_EDGE_MODULES MOCKABLE_FUNCTION(, IOTHUB_CLIENT_CORE_LL_HANDLE, IoTHubClientCore_LL_CreateFromEnvironment, IOTHUB_CLIENT_TRANSPORT_PROVIDER, protocol); #endif - + + MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClientCore_LL_EnablePolicyConfiguration, IOTHUB_CLIENT_CORE_LL_HANDLE, iotHubClientHandle, POLICY_CONFIGURATION_TYPE, policyType, bool, enablePolicyConfiguration); MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClientCore_LL_SetStreamRequestCallback, IOTHUB_CLIENT_CORE_LL_HANDLE, iotHubClientHandle, DEVICE_STREAM_C2D_REQUEST_CALLBACK, streamRequestCallback, void*, context); MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClientCore_LL_SendStreamResponse, IOTHUB_CLIENT_CORE_LL_HANDLE, iotHubClientHandle, DEVICE_STREAM_C2D_RESPONSE*, response); diff --git a/iothub_client/inc/iothub_device_client.h b/iothub_client/inc/iothub_device_client.h index ae170aa38b..038678be69 100644 --- a/iothub_client/inc/iothub_device_client.h +++ b/iothub_client/inc/iothub_device_client.h @@ -378,6 +378,18 @@ extern "C" #endif /* DONT_USE_UPLOADTOBLOB */ + /** + * @brief This API enables the device to use specific IoTHub features that are configured via device twins. + * + * @param iotHubClientHandle The handle created by a call to the create function. + * @param policyType The policy type that will be accepted from Azure IoT Hub. + * @param enablePolicyConfiguration True to enable parsing device twin for specific feature configuration. + Default is false. + * + * @return IOTHUB_CLIENT_OK upon success or an error code upon failure. + */ + MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubDeviceClient_EnablePolicyConfiguration, IOTHUB_DEVICE_CLIENT_HANDLE, iotHubClientHandle, POLICY_CONFIGURATION_TYPE, policyType, bool, enablePolicyConfiguration); + /** * @brief Subscribes/unsubscribes for cloud-to-device stream requests. * diff --git a/iothub_client/inc/iothub_device_client_ll.h b/iothub_client/inc/iothub_device_client_ll.h index e9334e7ea9..0f0187e805 100644 --- a/iothub_client/inc/iothub_device_client_ll.h +++ b/iothub_client/inc/iothub_device_client_ll.h @@ -389,6 +389,18 @@ typedef struct IOTHUB_CLIENT_CORE_LL_HANDLE_DATA_TAG* IOTHUB_DEVICE_CLIENT_LL_HA #endif /*DONT_USE_UPLOADTOBLOB*/ + /** + * @brief This API enables the device to use specific IoTHub features that are configured via device twins. + * + * @param iotHubClientHandle The handle created by a call to the create function. + * @param policyType The policy type that will be accepted from Azure IoT Hub. + * @param enablePolicyConfiguration True to enable parsing device twin for specific feature configuration. + Default is false. + * + * @return IOTHUB_CLIENT_OK upon success or an error code upon failure. + */ + MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubDeviceClient_LL_EnablePolicyConfiguration, IOTHUB_DEVICE_CLIENT_LL_HANDLE, iotHubClientHandle, POLICY_CONFIGURATION_TYPE, policyType, bool, enablePolicyConfiguration); + /** * @brief Subscribes/unsubscribes for cloud-to-device stream requests. * diff --git a/iothub_client/inc/iothub_message.h b/iothub_client/inc/iothub_message.h index f493081760..403f7b369e 100644 --- a/iothub_client/inc/iothub_message.h +++ b/iothub_client/inc/iothub_message.h @@ -51,7 +51,6 @@ typedef struct IOTHUB_MESSAGE_DIAGNOSTIC_PROPERTY_DATA_TAG char* diagnosticCreationTimeUtc; }IOTHUB_MESSAGE_DIAGNOSTIC_PROPERTY_DATA, *IOTHUB_MESSAGE_DIAGNOSTIC_PROPERTY_DATA_HANDLE; -static const char DIAG_CREATION_TIME_UTC_PROPERTY_NAME[] = "diag_creation_time_utc"; /** * @brief Creates a new IoT hub message from a byte array. The type of the @@ -246,6 +245,7 @@ MOCKABLE_FUNCTION(, IOTHUB_MESSAGE_RESULT, IoTHubMessage_SetCorrelationId, IOTHU /** * @brief Gets the DiagnosticData from the IOTHUB_MESSAGE_HANDLE. CAUTION: SDK user should not call it directly, it is for internal use only. +** DEPRECATED: Use IoTHubMessage_GetDistributedTracingSystemProperty instead. ** * * @param iotHubMessageHandle Handle to the message. * @@ -255,6 +255,7 @@ MOCKABLE_FUNCTION(, const IOTHUB_MESSAGE_DIAGNOSTIC_PROPERTY_DATA*, IoTHubMessag /** * @brief Sets the DiagnosticData for the IOTHUB_MESSAGE_HANDLE. CAUTION: SDK user should not call it directly, it is for internal use only. +** DEPRECATED: Use IoTHubMessage_SetDistributedTracingSystemProperty instead. ** * * @param iotHubMessageHandle Handle to the message. * @param diagnosticData Pointer to the memory location of the diagnosticData @@ -264,6 +265,26 @@ MOCKABLE_FUNCTION(, const IOTHUB_MESSAGE_DIAGNOSTIC_PROPERTY_DATA*, IoTHubMessag */ MOCKABLE_FUNCTION(, IOTHUB_MESSAGE_RESULT, IoTHubMessage_SetDiagnosticPropertyData, IOTHUB_MESSAGE_HANDLE, iotHubMessageHandle, const IOTHUB_MESSAGE_DIAGNOSTIC_PROPERTY_DATA*, diagnosticData); +/** +* @brief Gets the tracestate (current timestamp) from the IOTHUB_MESSAGE_HANDLE. +* +* @param iotHubMessageHandle Handle to the message. +* +* @return A const char* pointing to the distributed tracing tracestate value. +*/ +MOCKABLE_FUNCTION(, const char*, IoTHubMessage_GetDistributedTracingSystemProperty, IOTHUB_MESSAGE_HANDLE, iotHubMessageHandle); + +/** +* @brief Sets the distributed tracing system property for the IOTHUB_MESSAGE_HANDLE. +* +* @param iotHubMessageHandle Handle to the message. +* @param distributedTracingTracestate Pointer to the memory location of the Distributed Tracing tracestate. +* +* @return Returns IOTHUB_MESSAGE_OK if the Distributed Tracing tracestate was set successfully +* or an error code otherwise. +*/ +MOCKABLE_FUNCTION(, IOTHUB_MESSAGE_RESULT, IoTHubMessage_SetDistributedTracingSystemProperty, IOTHUB_MESSAGE_HANDLE, iotHubMessageHandle, const char*, distributedTracingTracestate); + /** * @brief Gets the output name from the IOTHUB_MESSAGE_HANDLE. * diff --git a/iothub_client/src/iothub_client_core.c b/iothub_client/src/iothub_client_core.c index 0cd5091d16..6b6bc59d12 100644 --- a/iothub_client/src/iothub_client_core.c +++ b/iothub_client/src/iothub_client_core.c @@ -2689,6 +2689,35 @@ IOTHUB_CLIENT_RESULT IoTHubClientCore_GenericMethodInvoke(IOTHUB_CLIENT_CORE_HAN } #endif /* USE_EDGE_MODULES */ +IOTHUB_CLIENT_RESULT IoTHubClientCore_EnablePolicyConfiguration(IOTHUB_CLIENT_CORE_HANDLE iotHubClientHandle, POLICY_CONFIGURATION_TYPE policyType, bool enablePolicyConfiguration) +{ + IOTHUB_CLIENT_RESULT result; + if (iotHubClientHandle == NULL) + { + LogError("Invalid argument (iotHubClientHandle=%p)", iotHubClientHandle); + result = IOTHUB_CLIENT_INVALID_ARG; + } + else + { + IOTHUB_CLIENT_CORE_INSTANCE* iotHubClientInstance = (IOTHUB_CLIENT_CORE_INSTANCE*)iotHubClientHandle; + + /*Codes_SRS_IOTHUBCLIENT_38_001: [ IoTHubClientCore_EnablePolicyConfiguration shall be made thread-safe by using the lock created in IoTHubClient_Create. ]*/ + if (Lock(iotHubClientInstance->LockHandle) != LOCK_OK) + { + /*Codes_SRS_IOTHUBCLIENT_38_002: [ If acquiring the lock fails, IoTHubClientCore_EnablePolicyConfiguration shall return IOTHUB_CLIENT_ERROR. ]*/ + result = IOTHUB_CLIENT_ERROR; + LogError("Could not acquire lock"); + } + else + { + result = IoTHubClientCore_LL_EnablePolicyConfiguration(iotHubClientHandle->IoTHubClientLLHandle, policyType, enablePolicyConfiguration); + (void)Unlock(iotHubClientInstance->LockHandle); + } + } + + return result; +} + static DEVICE_STREAM_C2D_RESPONSE* iothub_ll_device_stream_request_callback(DEVICE_STREAM_C2D_REQUEST* request, void* context) { DEVICE_STREAM_C2D_RESPONSE* result; diff --git a/iothub_client/src/iothub_client_core_ll.c b/iothub_client/src/iothub_client_core_ll.c old mode 100755 new mode 100644 index 3c21db0f7a..af0489c500 --- a/iothub_client/src/iothub_client_core_ll.c +++ b/iothub_client/src/iothub_client_core_ll.c @@ -126,7 +126,8 @@ typedef struct IOTHUB_CLIENT_CORE_LL_HANDLE_DATA_TAG bool complete_twin_update_encountered; IOTHUB_AUTHORIZATION_HANDLE authorization_module; STRING_HANDLE product_info; - IOTHUB_DIAGNOSTIC_SETTING_DATA diagnostic_setting; + IOTHUB_DIAGNOSTIC_SETTING_DATA diagnostic_setting; // Deprecated + IOTHUB_DISTRIBUTED_TRACING_SETTING_DATA distributedTracing_setting; SINGLYLINKEDLIST_HANDLE event_callbacks; // List of IOTHUB_EVENT_CALLBACK's }IOTHUB_CLIENT_CORE_LL_HANDLE_DATA; @@ -141,7 +142,6 @@ static const char MODULE_ID_TOKEN[] = "ModuleId"; static const char PROVISIONING_TOKEN[] = "UseProvisioning"; static const char PROVISIONING_ACCEPTABLE_VALUE[] = "true"; - #ifdef USE_EDGE_MODULES /*The following section should be moved to iothub_module_client_ll.c during impending refactor*/ @@ -517,6 +517,31 @@ static void IoTHubClientCore_LL_SendComplete(PDLIST_ENTRY completed, IOTHUB_CLIE } } +static int update_distributed_tracing_settings_from_twin(IOTHUB_DISTRIBUTED_TRACING_SETTING_DATA* diagSetting, IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* iotHubClientHandle, DEVICE_TWIN_UPDATE_STATE update_state, const unsigned char* payLoad) +{ + int result; + STRING_HANDLE reportedStatePayload = NULL; + + if (IoTHubClient_DistributedTracing_UpdateFromTwin(diagSetting, update_state == DEVICE_TWIN_UPDATE_PARTIAL, payLoad, &reportedStatePayload) != 0) + { + LogError("Error calling IoTHubClient_DistributedTracing_UpdateFromTwin"); + result = __FAILURE__; + } + else if (reportedStatePayload != NULL && IoTHubClient_LL_SendReportedState(iotHubClientHandle, (const unsigned char*)STRING_c_str(reportedStatePayload), STRING_length(reportedStatePayload), NULL, NULL) != IOTHUB_CLIENT_OK) + { + LogError("IoTHubClient_LL_SendReportedState failed"); + result = __FAILURE__; + } + else + { + result = 0; + } + + STRING_delete(reportedStatePayload); + + return result; +} + static void IoTHubClientCore_LL_RetrievePropertyComplete(DEVICE_TWIN_UPDATE_STATE update_state, const unsigned char* payLoad, size_t size, void* ctx) { if (ctx == NULL) @@ -527,6 +552,13 @@ static void IoTHubClientCore_LL_RetrievePropertyComplete(DEVICE_TWIN_UPDATE_STAT else { IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_CORE_LL_HANDLE_DATA*)ctx; + + /*Codes_SRS_IOTHUBCLIENT_LL_38_003: [If distributed tracing is enabled, synchronize (update and report) distributed tracing settings based on device twin information.] */ + if(handleData->distributedTracing_setting.policyEnabled) + { + update_distributed_tracing_settings_from_twin(&handleData->distributedTracing_setting, handleData, update_state, payLoad); + } + /* Codes_SRS_IOTHUBCLIENT_LL_07_014: [ If deviceTwinCallback is NULL then IoTHubClientCore_LL_RetrievePropertyComplete shall do nothing.] */ if (handleData->deviceTwinCallback) { @@ -761,6 +793,25 @@ static int IoTHubClientCore_LL_DeviceMethodComplete(const char* method_name, con return result; } +static void IotHubClientCore_LL_GetTwin_PolicyConfigurationCallback(DEVICE_TWIN_UPDATE_STATE update_state, const unsigned char* payLoad, size_t size, void* userContextCallback) +{ + (void)size; + + if (userContextCallback == NULL) + { + LogError("Invalid argument userContextCallback=%p", userContextCallback); + } + else + { + IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_CORE_LL_HANDLE_DATA*)userContextCallback; + + if (handleData->distributedTracing_setting.policyEnabled) + { + update_distributed_tracing_settings_from_twin(&handleData->distributedTracing_setting, handleData, update_state, payLoad); + } + } +} + static IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* initialize_iothub_client(const IOTHUB_CLIENT_CONFIG* client_config, const IOTHUB_CLIENT_DEVICE_CONFIG* device_config, bool use_dev_auth, const char* module_id) { IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* result; @@ -1043,6 +1094,12 @@ static IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* initialize_iothub_client(const IOTHUB_ result->diagnostic_setting.currentMessageNumber = 0; result->diagnostic_setting.diagSamplingPercentage = 0; + + result->distributedTracing_setting.policyEnabled = false; + result->distributedTracing_setting.samplingMode = IOTHUB_DISTRIBUTED_TRACING_SAMPLING_MODE_NOT_SET; + result->distributedTracing_setting.samplingRate = 0; + result->distributedTracing_setting.currentMessageNumber = 0; + /*Codes_SRS_IOTHUBCLIENT_LL_25_124: [ `IoTHubClientCore_LL_Create` shall set the default retry policy as Exponential backoff with jitter and if succeed and return a `non-NULL` handle. ]*/ if (IoTHubClientCore_LL_SetRetryPolicy(result, IOTHUB_CLIENT_RETRY_EXPONENTIAL_BACKOFF_WITH_JITTER, 0) != IOTHUB_CLIENT_OK) { @@ -1803,16 +1860,21 @@ IOTHUB_CLIENT_RESULT IoTHubClientCore_LL_SendEventAsync(IOTHUB_CLIENT_CORE_LL_HA free(newEntry); LOG_ERROR_RESULT; } - else if (IoTHubClient_Diagnostic_AddIfNecessary(&handleData->diagnostic_setting, newEntry->messageHandle) != 0) - { - /*Codes_SRS_IOTHUBCLIENT_LL_02_014: [If cloning and/or adding the information/diagnostic fails for any reason, IoTHubClientCore_LL_SendEventAsync shall fail and return IOTHUB_CLIENT_ERROR.] */ - result = IOTHUB_CLIENT_ERROR; - IoTHubMessage_Destroy(newEntry->messageHandle); - free(newEntry); - LOG_ERROR_RESULT; - } else { + /*Codes_SRS_IOTHUBCLIENT_LL_38_001: [IoTHubClientCore_LL_SendEventAsync shall read distributed tracing properties and override any deprecated diagnostics settings.]*/ + if (handleData->distributedTracing_setting.policyEnabled && IoTHubClient_DistributedTracing_AddToMessageHeadersIfNecessary(&handleData->distributedTracing_setting, newEntry->messageHandle) != 0) + { + /*Codes_SRS_IOTHUBCLIENT_LL_38_002: [If adding distributed tracing information fails for any reason, IoTHubClientCore_LL_SendEventAsync shall not fail.] */ + LogInfo("unable to add distributed tracing information to message"); + } + /*Codes_SRS_IOTHUBCLIENT_LL_02_014: [If distributed tracing isn't enabled, check if deprecated diagnostic information needs to be added to message header]*/ + else if (IoTHubClient_Diagnostic_AddIfNecessary(&handleData->diagnostic_setting, newEntry->messageHandle) != 0) + { + /*Codes_SRS_IOTHUBCLIENT_LL_02_014: [If cloning and/or adding the information/diagnostic fails for any reason, IoTHubClientCore_LL_SendEventAsync shall not fail.] */ + LogInfo("unable to add diagnostic information to message"); + } + /*Codes_SRS_IOTHUBCLIENT_LL_02_013: [IoTHubClientCore_LL_SendEventAsync shall add the DLIST waitingToSend a new record cloning the information from eventMessageHandle, eventConfirmationCallback, userContextCallback.]*/ newEntry->callback = eventConfirmationCallback; newEntry->context = userContextCallback; @@ -2981,6 +3043,41 @@ IOTHUB_CLIENT_RESULT IoTHubClientCore_LL_GenericMethodInvoke(IOTHUB_CLIENT_CORE_ } #endif +IOTHUB_CLIENT_RESULT IoTHubClientCore_LL_EnablePolicyConfiguration(IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle, POLICY_CONFIGURATION_TYPE policyType, bool enablePolicyConfiguration) +{ + (void)policyType; + IOTHUB_CLIENT_RESULT result; + + // Codes_SRS_IOTHUBCLIENT_LL_38_004: [ If `iotHubClientHandle` is NULL, `IoTHubClientCore_LL_EnablePolicyConfiguration` shall return IOTHUB_CLIENT_INVALID_ARG. ] + if (iotHubClientHandle != NULL) + { + switch(policyType) + { + case(POLICY_CONFIGURATION_DISTRIBUTED_TRACING): + { + iotHubClientHandle->distributedTracing_setting.policyEnabled = enablePolicyConfiguration; + break; + } + default: + //do nothing + break; + } + + // Codes_SRS_IOTHUBCLIENT_LL_38_005: [ If a policy is enabled, `IoTHubClientCore_LL_GetTwinAsync` shall be called to refresh policy settings. ] + if (enablePolicyConfiguration) + { + (void)IoTHubClientCore_LL_GetTwinAsync(iotHubClientHandle, IotHubClientCore_LL_GetTwin_PolicyConfigurationCallback, iotHubClientHandle); + } + + result = IOTHUB_CLIENT_OK; + } + else + { + result = IOTHUB_CLIENT_INVALID_ARG; + } + return result; +} + IOTHUB_CLIENT_RESULT IoTHubClientCore_LL_SetStreamRequestCallback(IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle, DEVICE_STREAM_C2D_REQUEST_CALLBACK streamRequestCallback, void* context) { IOTHUB_CLIENT_RESULT result; diff --git a/iothub_client/src/iothub_client_diagnostic.c b/iothub_client/src/iothub_client_diagnostic.c index 6ca79627af..08aaea27f8 100644 --- a/iothub_client/src/iothub_client_diagnostic.c +++ b/iothub_client/src/iothub_client_diagnostic.c @@ -10,8 +10,41 @@ #include "azure_c_shared_utility/agenttime.h" #include "azure_c_shared_utility/buffer_.h" +#include "parson.h" #include "internal/iothub_client_diagnostic.h" +#define DTRACING_NAMESPACE "azureiot*com^dtracing^1" +#define DTRACING_JSON_DOT_SEPARATOR "." +#define DTRACING_SAMPLING_MODE "sampling_mode" +#define DTRACING_SAMPLING_RATE "sampling_rate" + +static const char* DEVICE_TWIN_DISTRIBUTED_TRACING_SAMPLING_MODE_KEY = DTRACING_NAMESPACE DTRACING_JSON_DOT_SEPARATOR DTRACING_SAMPLING_MODE; +static const char* DEVICE_TWIN_DISTRIBUTED_TRACING_SAMPLING_RATE_KEY = DTRACING_NAMESPACE DTRACING_JSON_DOT_SEPARATOR DTRACING_SAMPLING_RATE; + +static const char* MESSAGE_DISTRIBUTED_TRACING_TIMESTAMP_KEY = "timestamp="; +static const char* DEVICE_TWIN_REPORTED_STATUS_FAILED_OPERATION = "401"; +static const char* DEVICE_TWIN_REPORTED_STATUS_SUCCESS = "204"; + +static const char* DISTRIBUTED_TRACING_REPORTED_TWIN_TEMPLATE = "{ \"__iot:interfaces\": \ +{ \"" DTRACING_NAMESPACE "\": { \"@id\": \"http://azureiot.com/dtracing/1.0.0\" } }, \ + \"" DTRACING_NAMESPACE "\": { \ + \"" DTRACING_SAMPLING_MODE "\": { \ + \"value\": %d, \ + \"status\" : { \ + \"code\": %s, \ + \"description\" : \"%s\" \ + } \ +}, \ + \"" DTRACING_SAMPLING_RATE "\": { \ + \"value\": %d, \ + \"status\" : { \ + \"code\": %s, \ + \"description\" : \"%s\" \ + } \ + } \ +} \ +}"; + #define TIME_STRING_BUFFER_LEN 30 static const int BASE_36 = 36; @@ -153,6 +186,7 @@ static IOTHUB_MESSAGE_DIAGNOSTIC_PROPERTY_DATA* prepare_message_diagnostic_data( return result; } +// **Deprecated - should use IoTHubClient_DistributedTracing_AddToMessageHeadersIfNecessary instead int IoTHubClient_Diagnostic_AddIfNecessary(IOTHUB_DIAGNOSTIC_SETTING_DATA* diagSetting, IOTHUB_MESSAGE_HANDLE messageHandle) { int result; @@ -197,3 +231,306 @@ int IoTHubClient_Diagnostic_AddIfNecessary(IOTHUB_DIAGNOSTIC_SETTING_DATA* diagS return result; } + +// Distributed tracing uses fixed-rate sampling, not true random sampling. +static bool should_add_distributedtrace_fixed_rate_sampling(IOTHUB_DISTRIBUTED_TRACING_SETTING_DATA* distributedTraceSetting) +{ + bool result = false; + + /* Codes_SRS_IOTHUB_DIAGNOSTIC_38_003: [ If samplingMode is disabled or samplingRate is equal to 0, message number should not be increased and no distributed_tracing properties added and return false ]*/ + if (distributedTraceSetting->samplingMode != IOTHUB_DISTRIBUTED_TRACING_SAMPLING_MODE_OFF && distributedTraceSetting->samplingRate > 0) + { + /* Codes_SRS_IOTHUB_DIAGNOSTIC_38_004: [ If diagSamplingPercentage is equal to 100, distributed_tracing properties should be added to all messages]*/ + /* Codes_SRS_IOTHUB_DIAGNOSTIC_38_005: [ If diagSamplingPercentage is between(0, 100), distributed_tracing properties should be added based on percentage]*/ + double number; + double percentage; + + if (distributedTraceSetting->currentMessageNumber == UINT32_MAX) + { + distributedTraceSetting->currentMessageNumber %= distributedTraceSetting->samplingRate * 100; + } + ++distributedTraceSetting->currentMessageNumber; + + number = distributedTraceSetting->currentMessageNumber; + percentage = distributedTraceSetting->samplingRate; + result = (floor((number - 2) * percentage / 100.0) < floor((number - 1) * percentage / 100.0)); + } + return result; +} + +int IoTHubClient_DistributedTracing_AddToMessageHeadersIfNecessary(IOTHUB_DISTRIBUTED_TRACING_SETTING_DATA* distributedTraceSetting, IOTHUB_MESSAGE_HANDLE messageHandle) +{ + int result; + STRING_HANDLE messagePropertyContent = NULL; + /* Codes_SRS_IOTHUB_DIAGNOSTIC_38_001: [ IoTHubClient_DistributedTracing_AddToMessageHeadersIfNecessary should return nonezero if distributedTraceSetting or messageHandle is NULL. ]*/ + if (distributedTraceSetting == NULL || messageHandle == NULL) + { + LogError("Invalid parameter for Distributed Tracing, distributedTraceSetting=%p, messageHandle=%p", distributedTraceSetting, messageHandle); + result = __FAILURE__; + } + else if (should_add_distributedtrace_fixed_rate_sampling(distributedTraceSetting)) + { + char* timeBuffer; + + timeBuffer = (char*)malloc(TIME_STRING_BUFFER_LEN); + if (timeBuffer == NULL) + { + LogError("malloc for timeBuffer failed"); + result = __FAILURE__; + } + else if (get_epoch_time(timeBuffer) == NULL) + { + LogError("Failed getting current time"); + free(timeBuffer); + result = __FAILURE__; + } + else if ((messagePropertyContent = STRING_construct(MESSAGE_DISTRIBUTED_TRACING_TIMESTAMP_KEY)) == NULL) + { + LogError("Failed to allocate messagePropertyContent"); + result = __FAILURE__; + } + else if (STRING_concat(messagePropertyContent, (const char*)timeBuffer) != 0) + { + LogError("Failed to generate message system property string"); + free(timeBuffer); + result = __FAILURE__; + } + else if (IoTHubMessage_SetDistributedTracingSystemProperty(messageHandle, STRING_c_str(messagePropertyContent)) != IOTHUB_MESSAGE_OK) + { + /* Codes_SRS_IOTHUB_DIAGNOSTIC_38_002: [ IoTHubClient_DistributedTracing_AddToMessageHeadersIfNecessary should return nonezero if failing to add distributed tracing property. ]*/ + LogError("Failed to set distributed tracing system property"); + free(timeBuffer); + result = __FAILURE__; + } + else + { + free(timeBuffer); + result = 0; + } + } + else + { + result = 0; + } + + STRING_delete(messagePropertyContent); + + return result; +} + +static int parse_json_object_for_dtracing_property(JSON_Object* desiredJsonObject, const char* key, uint8_t currentValue, uint8_t* retValue, STRING_HANDLE* message, const char** statusCode, bool isPartialUpdate) +{ + int result = 0; + if (json_object_dothas_value(desiredJsonObject, key)) + { + JSON_Value* value = NULL; + JSON_Value_Type valueType = JSONNull; + + if ((value = json_object_dotget_value(desiredJsonObject, key)) == NULL) + { + /* Codes_SRS_IOTHUB_DIAGNOSTIC_38_010: [ IoTHubClient_DistributedTracing_UpdateFromTwin should keep sampling mode untouched when failing parse sampling mode from twin. ]*/ + if ((*message = STRING_construct_sprintf("Property %s cannot be parsed, leaving old setting.", key)) == NULL) + { + result = __FAILURE__; + } + + *statusCode = DEVICE_TWIN_REPORTED_STATUS_SUCCESS; + } + else if ((valueType = json_value_get_type(value)) == JSONNull) + { + /* Codes_SRS_IOTHUB_DIAGNOSTIC_38_014: [ IoTHubClient_DistributedTracing_UpdateFromTwin should set diagSamplingMode = false when sampling mode in twin is null. ]*/ + *retValue = 0; + if ((*message = STRING_construct_sprintf("Property %s is set to null, set it to default.", key)) == NULL) + { + result = __FAILURE__; + } + + *statusCode = DEVICE_TWIN_REPORTED_STATUS_SUCCESS; + } + else if (valueType != JSONNumber) + { + /* Codes_SRS_IOTHUB_DIAGNOSTIC_38_010: [ IoTHubClient_DistributedTracing_UpdateFromTwin should keep sampling mode untouched when failing parse sampling mode from twin. ]*/ + if ((*message = STRING_construct_sprintf("Cannot parse property %s from twin settings, leaving old setting.", key)) == NULL) + { + result = __FAILURE__; + } + + *statusCode = DEVICE_TWIN_REPORTED_STATUS_FAILED_OPERATION; + } + else + { + /* Codes_SRS_IOTHUB_DIAGNOSTIC_38_015: [ IoTHubClient_DistributedTracing_UpdateFromTwin should keep sampling mode untouched if sampling mode parsed from twin is not between [0,3]. ]*/ + *retValue = (uint8_t)json_object_dotget_number(desiredJsonObject, key); + *statusCode = DEVICE_TWIN_REPORTED_STATUS_SUCCESS; + } + } + else + { + if (!isPartialUpdate) + { + /* Codes_SRS_IOTHUB_DIAGNOSTIC_13_013: [ IoTHubClient_DistributedTracing_UpdateFromTwin should report diagnostic property does not exist if there is no sampling mode in complete twin. ]*/ + if ((*message = STRING_construct_sprintf("Property %s does not exist.", DEVICE_TWIN_DISTRIBUTED_TRACING_SAMPLING_MODE_KEY)) == NULL) + { + /* Codes_SRS_IOTHUB_DIAGNOSTIC_13_014: [ IoTHubClient_DistributedTracing_UpdateFromTwin should return nonzero if STRING_sprintf failed. ]*/ + result = __FAILURE__; + } + + *statusCode = DEVICE_TWIN_REPORTED_STATUS_FAILED_OPERATION; + } + else + { + /* Codes_SRS_IOTHUB_DIAGNOSTIC_38_015: [ IoTHubClient_DistributedTracing_UpdateFromTwin should report current value, if sampling mode is not parsed from a twin partial update. ]*/ + *retValue = currentValue; + *statusCode = DEVICE_TWIN_REPORTED_STATUS_SUCCESS; + } + } + + return result; +} + +int IoTHubClient_DistributedTracing_UpdateFromTwin(IOTHUB_DISTRIBUTED_TRACING_SETTING_DATA* distributedTracingSetting, bool isPartialUpdate, const unsigned char* payLoad, STRING_HANDLE* reportedStatePayload) +{ + int result = 0; + STRING_HANDLE modeMessage = NULL; + STRING_HANDLE rateMessage = NULL; + const char* modeStatusCode = NULL; + const char* rateStatusCode = NULL; + + /* Codes_SRS_IOTHUB_DIAGNOSTIC_38_006: [ IoTHubClient_DistributedTracing_UpdateFromTwin should return nonezero if arguments are NULL. ]*/ + if (distributedTracingSetting == NULL || payLoad == NULL) + { + LogError("Invalid parameter for IoTHubClient_DistributedTracing_UpdateFromTwin, distributedTracingSetting=%p, payLoad=%p", distributedTracingSetting, payLoad); + result = __FAILURE__; + } + else + { + uint8_t current_sampling_mode = distributedTracingSetting->samplingMode; + uint8_t current_sampling_rate = distributedTracingSetting->samplingRate; + JSON_Value* json = NULL; + JSON_Object* jsonObject = NULL; + JSON_Object* desiredJsonObject = NULL; + + /* Codes_SRS_IOTHUB_DIAGNOSTIC_38_007: [ IoTHubClient_DistributedTracing_UpdateFromTwin should return nonzero if payLoad is not a valid json string. ]*/ + if ((json = json_parse_string((const char *)payLoad)) == NULL) + { + LogError("Invalid JSON payload=%s", (const char *)payLoad); + result = __FAILURE__; + } + else if ((jsonObject = json_value_get_object(json)) == NULL) + { + result = __FAILURE__; + } + else if ((desiredJsonObject = isPartialUpdate + ? jsonObject + : json_object_get_object(jsonObject, "desired")) == NULL) + { + /* Codes_SRS_IOTHUB_DIAGNOSTIC_38_008: [ IoTHubClient_DistributedTracing_UpdateFromTwin should return nonezero if device twin json doesn't contain a valid desired property. ]*/ + result = __FAILURE__; + } + else + { + uint8_t sampling_mode; + if (parse_json_object_for_dtracing_property(desiredJsonObject, DEVICE_TWIN_DISTRIBUTED_TRACING_SAMPLING_MODE_KEY, current_sampling_mode, &sampling_mode, &modeMessage, &modeStatusCode, isPartialUpdate) != 0) + { + LogError("Error calling parse_json_object_for_dtracing_property for distributed tracing reported status while parsing JSON for sampling mode"); + result = __FAILURE__; + } + else if (modeStatusCode == DEVICE_TWIN_REPORTED_STATUS_SUCCESS) + { + if (sampling_mode < 0 || sampling_mode > 3) + { + if ((modeMessage = STRING_construct_sprintf("The value of property %s must be between [0, 3].", DEVICE_TWIN_DISTRIBUTED_TRACING_SAMPLING_MODE_KEY)) == NULL) + { + LogError("Error calling STRING_construct_sprintf for distributed tracing reported status bounds error checking for sampling mode"); + result = __FAILURE__; + } + + modeStatusCode = DEVICE_TWIN_REPORTED_STATUS_FAILED_OPERATION; + } + else + { + /* Codes_SRS_IOTHUB_DIAGNOSTIC_38_012: [ IoTHubClient_DistributedTracing_UpdateFromTwin should set diagSamplingMode correctly if sampling mode is valid. ]*/ + distributedTracingSetting->samplingMode = sampling_mode; + if ((modeMessage = STRING_new()) == NULL) + { + LogError("Error calling STRING_new for distributed tracing reported status bounds error checking for sampling mode"); + result = __FAILURE__; + } + + modeStatusCode = DEVICE_TWIN_REPORTED_STATUS_SUCCESS; + } + } + + uint8_t sampling_rate; + if (parse_json_object_for_dtracing_property(desiredJsonObject, DEVICE_TWIN_DISTRIBUTED_TRACING_SAMPLING_RATE_KEY, current_sampling_rate, &sampling_rate, &rateMessage, &rateStatusCode, isPartialUpdate) != 0) + { + LogError("Error calling parse_json_object_for_dtracing_property for distributed tracing reported status while parsing JSON for sampling rate"); + result = __FAILURE__; + } + else if (rateStatusCode == DEVICE_TWIN_REPORTED_STATUS_SUCCESS) + { + if (sampling_rate < 0 || sampling_rate > 100) + { + if ((rateMessage = STRING_construct_sprintf("The value of property %s must be between [0, 100].", DEVICE_TWIN_DISTRIBUTED_TRACING_SAMPLING_RATE_KEY)) == NULL) + { + LogError("Error calling STRING_sprintf for distributed tracing reported status bounds error checking for sampling rate"); + result = __FAILURE__; + } + + rateStatusCode = DEVICE_TWIN_REPORTED_STATUS_FAILED_OPERATION; + } + else + { + /* Codes_SRS_IOTHUB_DIAGNOSTIC_38_013: [ IoTHubClient_DistributedTracing_UpdateFromTwin should reset the sampling sequence, after diagSamplingPercentage changes. ]*/ + if (current_sampling_mode != sampling_mode || current_sampling_rate != sampling_rate) + { + distributedTracingSetting->currentMessageNumber = 0; + } + + /* Codes_SRS_IOTHUB_DIAGNOSTIC_38_014: [ IoTHubClient_DistributedTracing_UpdateFromTwin should set diagSamplingPercentage correctly if sampling rate is valid. ]*/ + distributedTracingSetting->samplingRate = sampling_rate; + + if ((rateMessage = STRING_new()) == NULL) + { + LogError("Error calling STRING_new for distributed tracing reported status bounds error checking for sampling rate"); + result = __FAILURE__; + } + + rateStatusCode = DEVICE_TWIN_REPORTED_STATUS_SUCCESS; + } + } + } + + if (current_sampling_mode != distributedTracingSetting->samplingMode || current_sampling_rate != distributedTracingSetting->samplingRate || + modeStatusCode != DEVICE_TWIN_REPORTED_STATUS_SUCCESS || rateStatusCode != DEVICE_TWIN_REPORTED_STATUS_SUCCESS) + { + if ((*reportedStatePayload = STRING_new()) == NULL) + { + LogError("Error creating message string"); + result = __FAILURE__; + } + /* Codes_SRS_IOTHUB_DIAGNOSTIC_38_015: [ IoTHubClient_DistributedTracing_UpdateFromTwin should report back the sampling rate and status of the property update. ]*/ + else if (STRING_sprintf(*reportedStatePayload, DISTRIBUTED_TRACING_REPORTED_TWIN_TEMPLATE, + distributedTracingSetting->samplingMode, + modeStatusCode, + STRING_c_str(modeMessage), + distributedTracingSetting->samplingRate, + rateStatusCode, + STRING_c_str(rateMessage)) != 0) + { + LogError("Error calling STRING_sprintf for distributed tracing reported status"); + STRING_delete(*reportedStatePayload); + reportedStatePayload = NULL; + result = __FAILURE__; + } + } + + if (json != NULL) + json_value_free(json); + + STRING_delete(modeMessage); + STRING_delete(rateMessage); + } + + return result; +} diff --git a/iothub_client/src/iothub_client_dll.def b/iothub_client/src/iothub_client_dll.def index 5eee3cea6d..89dfb7987c 100644 --- a/iothub_client/src/iothub_client_dll.def +++ b/iothub_client/src/iothub_client_dll.def @@ -35,6 +35,7 @@ EXPORTS IoTHubDeviceClient_CreateWithTransport IoTHubDeviceClient_CreateFromDeviceAuth IoTHubDeviceClient_Destroy + IoTHubDeviceClient_SetDeviceTwinCallback IoTHubDeviceClient_SendEventAsync IoTHubDeviceClient_GetSendStatus IoTHubDeviceClient_SetMessageCallback @@ -49,6 +50,7 @@ EXPORTS IoTHubDeviceClient_DeviceMethodResponse IoTHubDeviceClient_UploadToBlobAsync IoTHubDeviceClient_UploadMultipleBlocksToBlobAsync + IoTHubDeviceClient_EnablePolicyConfiguration IoTHubModuleClient_CreateFromConnectionString IoTHubModuleClient_Destroy @@ -78,6 +80,7 @@ EXPORTS IoTHubDeviceClient_LL_CreateWithTransport IoTHubDeviceClient_LL_CreateFromDeviceAuth IoTHubDeviceClient_LL_Destroy + IoTHubDeviceClient_LL_SetDeviceTwinCallback IoTHubDeviceClient_LL_SendEventAsync IoTHubDeviceClient_LL_GetSendStatus IoTHubDeviceClient_LL_SetMessageCallback @@ -93,6 +96,7 @@ EXPORTS IoTHubDeviceClient_LL_DeviceMethodResponse IoTHubDeviceClient_LL_UploadToBlob IoTHubDeviceClient_LL_UploadMultipleBlocksToBlob + IoTHubDeviceClient_LL_EnablePolicyConfiguration IoTHubModuleClient_LL_CreateFromConnectionString IoTHubModuleClient_LL_Destroy @@ -122,6 +126,7 @@ EXPORTS IoTHubMessage_GetContentEncodingSystemProperty IoTHubMessage_GetCorrelationId IoTHubMessage_GetDiagnosticPropertyData + IoTHubMessage_GetDistributedTracingSystemProperty IoTHubMessage_GetMessageId IoTHubMessage_GetOutputName IoTHubMessage_GetProperty diff --git a/iothub_client/src/iothub_device_client.c b/iothub_client/src/iothub_device_client.c index 1d5aa12306..dfb2140c8a 100644 --- a/iothub_client/src/iothub_device_client.c +++ b/iothub_client/src/iothub_device_client.c @@ -112,6 +112,11 @@ IOTHUB_CLIENT_RESULT IoTHubDeviceClient_UploadMultipleBlocksToBlobAsync(IOTHUB_D #endif /*DONT_USE_UPLOADTOBLOB*/ +IOTHUB_CLIENT_RESULT IoTHubDeviceClient_EnablePolicyConfiguration(IOTHUB_DEVICE_CLIENT_HANDLE iotHubClientHandle, POLICY_CONFIGURATION_TYPE policyType, bool enablePolicyConfiguration) +{ + return IoTHubClientCore_EnablePolicyConfiguration((IOTHUB_CLIENT_CORE_HANDLE)iotHubClientHandle, policyType, enablePolicyConfiguration); +} + IOTHUB_CLIENT_RESULT IoTHubDeviceClient_SetStreamRequestCallback(IOTHUB_DEVICE_CLIENT_HANDLE iotHubClientHandle, DEVICE_STREAM_C2D_REQUEST_CALLBACK streamRequestCallback, void* context) { return IoTHubClientCore_SetStreamRequestCallback((IOTHUB_CLIENT_CORE_HANDLE)iotHubClientHandle, streamRequestCallback, context); diff --git a/iothub_client/src/iothub_device_client_ll.c b/iothub_client/src/iothub_device_client_ll.c index 2a5478aea8..42a8c70f5a 100644 --- a/iothub_client/src/iothub_device_client_ll.c +++ b/iothub_client/src/iothub_device_client_ll.c @@ -134,6 +134,11 @@ IOTHUB_CLIENT_RESULT IoTHubDeviceClient_LL_UploadMultipleBlocksToBlob(IOTHUB_DEV #endif +IOTHUB_CLIENT_RESULT IoTHubDeviceClient_LL_EnablePolicyConfiguration(IOTHUB_DEVICE_CLIENT_LL_HANDLE iotHubClientHandle, POLICY_CONFIGURATION_TYPE policyType, bool enablePolicyConfiguration) +{ + return IoTHubClientCore_LL_EnablePolicyConfiguration((IOTHUB_DEVICE_CLIENT_LL_HANDLE)iotHubClientHandle, policyType, enablePolicyConfiguration); +} + IOTHUB_CLIENT_RESULT IoTHubDeviceClient_LL_SetStreamRequestCallback(IOTHUB_DEVICE_CLIENT_LL_HANDLE iotHubClientHandle, DEVICE_STREAM_C2D_REQUEST_CALLBACK streamRequestCallback, void* context) { return IoTHubClientCore_LL_SetStreamRequestCallback((IOTHUB_CLIENT_CORE_LL_HANDLE)iotHubClientHandle, streamRequestCallback, context); diff --git a/iothub_client/src/iothub_message.c b/iothub_client/src/iothub_message.c index caa1109cd6..08bef5adc2 100644 --- a/iothub_client/src/iothub_message.c +++ b/iothub_client/src/iothub_message.c @@ -32,7 +32,8 @@ typedef struct IOTHUB_MESSAGE_HANDLE_DATA_TAG char* inputName; char* connectionModuleId; char* connectionDeviceId; - IOTHUB_MESSAGE_DIAGNOSTIC_PROPERTY_DATA_HANDLE diagnosticData; + IOTHUB_MESSAGE_DIAGNOSTIC_PROPERTY_DATA_HANDLE diagnosticData; //Deprecated + char* distributedTracingTracestate; }IOTHUB_MESSAGE_HANDLE_DATA; static bool ContainsOnlyUsAscii(const char* asciiValue) @@ -96,6 +97,7 @@ static void DestroyMessageData(IOTHUB_MESSAGE_HANDLE_DATA* handleData) free(handleData->userDefinedContentType); free(handleData->contentEncoding); DestroyDiagnosticPropertyData(handleData->diagnosticData); + free(handleData->distributedTracingTracestate); free(handleData->outputName); free(handleData->inputName); free(handleData->connectionModuleId); @@ -305,9 +307,10 @@ IOTHUB_MESSAGE_HANDLE IoTHubMessage_Clone(IOTHUB_MESSAGE_HANDLE iotHubMessageHan DestroyMessageData(result); result = NULL; } + //Deprecated else if (source->diagnosticData != NULL && (result->diagnosticData = CloneDiagnosticPropertyData(source->diagnosticData)) == NULL) { - LogError("unable to copy CloneDiagnosticPropertyData"); + LogError("unable to CloneDiagnosticPropertyData"); DestroyMessageData(result); result = NULL; } @@ -325,13 +328,19 @@ IOTHUB_MESSAGE_HANDLE IoTHubMessage_Clone(IOTHUB_MESSAGE_HANDLE iotHubMessageHan } else if (source->connectionModuleId != NULL && mallocAndStrcpy_s(&result->connectionModuleId, source->connectionModuleId) != 0) { - LogError("unable to copy inputName"); + LogError("unable to copy connectionModuleId"); DestroyMessageData(result); result = NULL; } else if (source->connectionDeviceId != NULL && mallocAndStrcpy_s(&result->connectionDeviceId, source->connectionDeviceId) != 0) { - LogError("unable to copy inputName"); + LogError("unable to copy connectionDeviceId"); + DestroyMessageData(result); + result = NULL; + } + else if (source->distributedTracingTracestate != NULL && mallocAndStrcpy_s(&result->distributedTracingTracestate, source->distributedTracingTracestate) != 0) + { + LogError("unable to copy distributedTracingTracestate"); DestroyMessageData(result); result = NULL; } @@ -467,7 +476,7 @@ MAP_HANDLE IoTHubMessage_Properties(IOTHUB_MESSAGE_HANDLE iotHubMessageHandle) else { /*Codes_SRS_IOTHUBMESSAGE_02_002: [Otherwise, for any non-NULL iotHubMessageHandle it shall return a non-NULL MAP_HANDLE.]*/ - IOTHUB_MESSAGE_HANDLE_DATA* handleData = (IOTHUB_MESSAGE_HANDLE_DATA*)iotHubMessageHandle; + IOTHUB_MESSAGE_HANDLE_DATA* handleData = iotHubMessageHandle; result = handleData->properties; } return result; @@ -633,7 +642,7 @@ IOTHUB_MESSAGE_RESULT IoTHubMessage_SetContentTypeSystemProperty(IOTHUB_MESSAGE_ } else { - IOTHUB_MESSAGE_HANDLE_DATA* handleData = (IOTHUB_MESSAGE_HANDLE_DATA*)iotHubMessageHandle; + IOTHUB_MESSAGE_HANDLE_DATA* handleData = iotHubMessageHandle; // Codes_SRS_IOTHUBMESSAGE_09_002: [If the IOTHUB_MESSAGE_HANDLE `contentType` is not NULL it shall be deallocated.] if (handleData->userDefinedContentType != NULL) @@ -691,7 +700,7 @@ IOTHUB_MESSAGE_RESULT IoTHubMessage_SetContentEncodingSystemProperty(IOTHUB_MESS } else { - IOTHUB_MESSAGE_HANDLE_DATA* handleData = (IOTHUB_MESSAGE_HANDLE_DATA*)iotHubMessageHandle; + IOTHUB_MESSAGE_HANDLE_DATA* handleData = iotHubMessageHandle; // Codes_SRS_IOTHUBMESSAGE_09_007: [If the IOTHUB_MESSAGE_HANDLE `contentEncoding` is not NULL it shall be deallocated.] if (handleData->contentEncoding != NULL) @@ -737,6 +746,7 @@ const char* IoTHubMessage_GetContentEncodingSystemProperty(IOTHUB_MESSAGE_HANDLE return result; } +//Deprecated const IOTHUB_MESSAGE_DIAGNOSTIC_PROPERTY_DATA* IoTHubMessage_GetDiagnosticPropertyData(IOTHUB_MESSAGE_HANDLE iotHubMessageHandle) { const IOTHUB_MESSAGE_DIAGNOSTIC_PROPERTY_DATA* result; @@ -754,6 +764,7 @@ const IOTHUB_MESSAGE_DIAGNOSTIC_PROPERTY_DATA* IoTHubMessage_GetDiagnosticProper return result; } +//Deprecated IOTHUB_MESSAGE_RESULT IoTHubMessage_SetDiagnosticPropertyData(IOTHUB_MESSAGE_HANDLE iotHubMessageHandle, const IOTHUB_MESSAGE_DIAGNOSTIC_PROPERTY_DATA* diagnosticData) { IOTHUB_MESSAGE_RESULT result; @@ -793,6 +804,61 @@ IOTHUB_MESSAGE_RESULT IoTHubMessage_SetDiagnosticPropertyData(IOTHUB_MESSAGE_HAN return result; } +const char* IoTHubMessage_GetDistributedTracingSystemProperty(IOTHUB_MESSAGE_HANDLE iotHubMessageHandle) +{ + const char* result; + // Codes_SRS_IOTHUBMESSAGE_38_001: [If any of the parameters are NULL then IoTHubMessage_GetDistributedTracingSystemProperty shall return a NULL value.] + if (iotHubMessageHandle == NULL) + { + LogError("Invalid argument (iotHubMessageHandle is NULL)"); + result = NULL; + } + else + { + IOTHUB_MESSAGE_HANDLE_DATA* handleData = iotHubMessageHandle; + + /* Codes_SRS_IOTHUBMESSAGE_38_002: [IoTHubMessage_GetDistributedTracingSystemProperty shall return the tracestate data as a const char*.] */ + result = (const char*)handleData->distributedTracingTracestate; + } + return result; +} + +IOTHUB_MESSAGE_RESULT IoTHubMessage_SetDistributedTracingSystemProperty(IOTHUB_MESSAGE_HANDLE iotHubMessageHandle, const char* distributedTracingTracestate) +{ + IOTHUB_MESSAGE_RESULT result; + + // Codes_SRS_IOTHUBMESSAGE_38_006: [If any of the parameters are NULL then IoTHubMessage_SetDistributedTracingSystemProperty shall return a IOTHUB_MESSAGE_INVALID_ARG value.] + if (iotHubMessageHandle == NULL || distributedTracingTracestate == NULL) + { + LogError("Invalid argument (iotHubMessageHandle=%p, distributedTracingTracestate=%s)", iotHubMessageHandle, P_OR_NULL(distributedTracingTracestate)); + result = IOTHUB_MESSAGE_INVALID_ARG; + } + else + { + IOTHUB_MESSAGE_HANDLE_DATA* handleData = iotHubMessageHandle; + + // Codes_SRS_IOTHUBMESSAGE_38_007: [If the IOTHUB_MESSAGE_HANDLE `distributedTracingTracestate` is not NULL it shall be deallocated.] + if (handleData->distributedTracingTracestate != NULL) + { + free(handleData->distributedTracingTracestate); + handleData->distributedTracingTracestate = NULL; + } + + if (mallocAndStrcpy_s(&handleData->distributedTracingTracestate, distributedTracingTracestate) != 0) + { + LogError("Failed saving a copy of distributedTracingTracestate"); + // Codes_SRS_IOTHUBMESSAGE_38_008: [If the allocation or the copying of `distributedTracingTracestate` fails, then IoTHubMessage_SetDistributedTracingSystemProperty shall return IOTHUB_MESSAGE_ERROR.] + result = IOTHUB_MESSAGE_ERROR; + } + else + { + // Codes_SRS_IOTHUBMESSAGE_38_009: [If IoTHubMessage_SetDistributedTracingSystemProperty finishes successfully it shall return IOTHUB_MESSAGE_OK.] + result = IOTHUB_MESSAGE_OK; + } + } + + return result; +} const char* IoTHubMessage_GetOutputName(IOTHUB_MESSAGE_HANDLE iotHubMessageHandle) { @@ -823,7 +889,7 @@ IOTHUB_MESSAGE_RESULT IoTHubMessage_SetOutputName(IOTHUB_MESSAGE_HANDLE iotHubMe } else { - IOTHUB_MESSAGE_HANDLE_DATA* handleData = (IOTHUB_MESSAGE_HANDLE_DATA*)iotHubMessageHandle; + IOTHUB_MESSAGE_HANDLE_DATA* handleData = iotHubMessageHandle; // Codes_SRS_IOTHUBMESSAGE_31_037: [If the IOTHUB_MESSAGE_HANDLE OutputName is not NULL, then the IOTHUB_MESSAGE_HANDLE OutputName will be deallocated.] if (handleData->outputName != NULL) @@ -878,7 +944,7 @@ IOTHUB_MESSAGE_RESULT IoTHubMessage_SetInputName(IOTHUB_MESSAGE_HANDLE iotHubMes } else { - IOTHUB_MESSAGE_HANDLE_DATA* handleData = (IOTHUB_MESSAGE_HANDLE_DATA*)iotHubMessageHandle; + IOTHUB_MESSAGE_HANDLE_DATA* handleData = iotHubMessageHandle; // Codes_SRS_IOTHUBMESSAGE_31_043: [If the IOTHUB_MESSAGE_HANDLE InputName is not NULL, then the IOTHUB_MESSAGE_HANDLE InputName will be deallocated.] if (handleData->inputName != NULL) @@ -934,7 +1000,7 @@ IOTHUB_MESSAGE_RESULT IoTHubMessage_SetConnectionModuleId(IOTHUB_MESSAGE_HANDLE } else { - IOTHUB_MESSAGE_HANDLE_DATA* handleData = (IOTHUB_MESSAGE_HANDLE_DATA*)iotHubMessageHandle; + IOTHUB_MESSAGE_HANDLE_DATA* handleData = iotHubMessageHandle; // Codes_SRS_IOTHUBMESSAGE_31_049: [If the IOTHUB_MESSAGE_HANDLE ConnectionModuleId is not NULL, then the IOTHUB_MESSAGE_HANDLE ConnectionModuleId will be deallocated.] if (handleData->connectionModuleId != NULL) @@ -990,7 +1056,7 @@ IOTHUB_MESSAGE_RESULT IoTHubMessage_SetConnectionDeviceId(IOTHUB_MESSAGE_HANDLE } else { - IOTHUB_MESSAGE_HANDLE_DATA* handleData = (IOTHUB_MESSAGE_HANDLE_DATA*)iotHubMessageHandle; + IOTHUB_MESSAGE_HANDLE_DATA* handleData = iotHubMessageHandle; // Codes_SRS_IOTHUBMESSAGE_31_055: [If the IOTHUB_MESSAGE_HANDLE ConnectionDeviceId is not NULL, then the IOTHUB_MESSAGE_HANDLE ConnectionDeviceId will be deallocated.] if (handleData->connectionDeviceId != NULL) diff --git a/iothub_client/src/iothubtransport_mqtt_common.c b/iothub_client/src/iothubtransport_mqtt_common.c index 523d6f5362..b3149a92be 100755 --- a/iothub_client/src/iothubtransport_mqtt_common.c +++ b/iothub_client/src/iothubtransport_mqtt_common.c @@ -109,6 +109,8 @@ static const char* CONNECTION_MODULE_ID_PROPERTY = "cmid"; static const char* DIAGNOSTIC_CONTEXT_CREATION_TIME_UTC_PROPERTY = "creationtimeutc"; +static const char* DISTRIBUTED_TRACING_PROPERTY = "tracestate"; + #define TOLOWER(c) (((c>='A') && (c<='Z'))?c-'A'+'a':c) #define UNSUBSCRIBE_FROM_TOPIC 0x0000 @@ -750,10 +752,21 @@ static int addSystemPropertiesTouMqttMessage(IOTHUB_MESSAGE_HANDLE iothub_messag index++; } } + // Codes_SRS_IOTHUB_TRANSPORT_MQTT_COMMON_38_012: [ `IoTHubTransport_MQTT_Common_DoWork` shall check for the DistributedTracing property and if found add the `value` as a system property in the format of `$.tracestate=` ] + if (result == 0) + { + const char* tracestate = IoTHubMessage_GetDistributedTracingSystemProperty(iothub_message_handle); + if (tracestate != NULL) + { + result = addSystemPropertyToTopicString(topic_string, index, DISTRIBUTED_TRACING_PROPERTY, tracestate, true); + index++; + } + } *index_ptr = index; return result; } +// Deprecated static int addDiagnosticPropertiesTouMqttMessage(IOTHUB_MESSAGE_HANDLE iothub_message_handle, STRING_HANDLE topic_string, size_t* index_ptr) { int result = 0; @@ -842,6 +855,7 @@ static STRING_HANDLE addPropertiesTouMqttMessage(IOTHUB_MESSAGE_HANDLE iothub_me STRING_delete(result); result = NULL; } + //Deprecated else if (addDiagnosticPropertiesTouMqttMessage(iothub_message_handle, result, &index) != 0) { LogError("Failed adding Diagnostic Properties to uMQTT Message"); diff --git a/iothub_client/src/uamqp_messaging.c b/iothub_client/src/uamqp_messaging.c index 1dfcde2ccf..021fc4d461 100644 --- a/iothub_client/src/uamqp_messaging.c +++ b/iothub_client/src/uamqp_messaging.c @@ -25,6 +25,8 @@ #define MESSAGE_ID_MAX_SIZE 128 +#define AMQP_DISTRIBUTED_TRACING_KEY "tracestate" + #define AMQP_DIAGNOSTIC_ID_KEY "Diagnostic-Id" #define AMQP_DIAGNOSTIC_CONTEXT_KEY "Correlation-Context" #define AMQP_DIAGNOSTIC_CREATION_TIME_UTC_KEY "creationtimeutc" @@ -446,13 +448,18 @@ static int add_map_item(AMQP_VALUE map, const char* name, const char* value) static int create_message_annotations_to_encode(IOTHUB_MESSAGE_HANDLE messageHandle, AMQP_VALUE *message_annotations, size_t *message_annotations_length) { - AMQP_VALUE message_annotations_map = NULL; int result; + const char* distributed_tracing; + // Deprecated: maintained for backwards compatibility; use IoTHubMessage_GetDistributedTracingSystemProperty instead. const IOTHUB_MESSAGE_DIAGNOSTIC_PROPERTY_DATA* diagnosticData; + result = RESULT_OK; + if ((diagnosticData = IoTHubMessage_GetDiagnosticPropertyData(messageHandle)) != NULL && diagnosticData->diagnosticId != NULL && diagnosticData->diagnosticCreationTimeUtc != NULL) { + AMQP_VALUE message_annotations_map = NULL; + // Codes_SRS_UAMQP_MESSAGING_32_001: [If optional diagnostic properties are present in the iot hub message, encode them into the AMQP message as annotation properties. Errors stop processing on this message.] if ((message_annotations_map = amqpvalue_create_map()) == NULL) { @@ -503,6 +510,43 @@ static int create_message_annotations_to_encode(IOTHUB_MESSAGE_HANDLE messageHan amqpvalue_destroy(message_annotations_map); } } + + // Distributed tracing + if (result == RESULT_OK && (distributed_tracing = IoTHubMessage_GetDistributedTracingSystemProperty(messageHandle)) != NULL) + { + AMQP_VALUE message_annotations_map = NULL; + + // Codes_SRS_UAMQP_MESSAGING_32_001: [If optional diagnostic properties are present in the iot hub message, encode them into the AMQP message as annotation properties. Errors stop processing on this message.] + if ((message_annotations_map = amqpvalue_create_map()) == NULL) + { + LogError("Failed amqpvalue_create_map for annotations"); + result = __FAILURE__; + } + else + { + if (add_map_item(message_annotations_map, AMQP_DISTRIBUTED_TRACING_KEY, distributed_tracing) != RESULT_OK) + { + LogError("Failed adding distributed tracing property"); + result = __FAILURE__; + } + else if ((*message_annotations = amqpvalue_create_message_annotations(message_annotations_map)) == NULL) + { + LogError("Failed creating message annotations"); + result = __FAILURE__; + } + else if (amqpvalue_get_encoded_size(*message_annotations, message_annotations_length) != 0) + { + LogError("Failed getting size of annotations"); + result = __FAILURE__; + } + else + { + result = RESULT_OK; + } + + amqpvalue_destroy(message_annotations_map); + } + } else { // Codes_SRS_UAMQP_MESSAGING_32_002: [If optional diagnostic properties are not present in the iot hub message, no error should happen.] diff --git a/iothub_client/tests/common_dt_e2e/iothubclient_common_dt_e2e.c b/iothub_client/tests/common_dt_e2e/iothubclient_common_dt_e2e.c index 869bf0e37b..e4cd2265d9 100644 --- a/iothub_client/tests/common_dt_e2e/iothubclient_common_dt_e2e.c +++ b/iothub_client/tests/common_dt_e2e/iothubclient_common_dt_e2e.c @@ -305,8 +305,6 @@ static void sendeventasync_on_device_or_module(IOTHUB_MESSAGE_HANDLE msgHandle) ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result, "SendEventAsync failed"); } - - static void dt_e2e_update_twin(IOTHUB_SERVICE_CLIENT_DEVICE_TWIN_HANDLE serviceClientDeviceTwinHandle, IOTHUB_PROVISIONED_DEVICE* deviceToUse, const char* twinJson) { char* twinResponse; @@ -992,3 +990,87 @@ void dt_e2e_get_complete_desired_test_svc_fault_ctrl_kill_Tcp(IOTHUB_CLIENT_TRAN destroy_on_device_or_module(); device_desired_deinit(device); } + +static const char *DTRACING_DESIRED_PAYLOAD_FORMAT = "{\"properties\":{\"desired\":{\"azureiot*com^dtracing^1\":{\"sampling_mode\":%d, \"sampling_rate\":%d}}}}"; +static char *malloc_and_fill_desired_dtracing_payload(uint8_t sampling_mode, uint8_t sampling_rate) +{ + size_t length = snprintf(NULL, 0, DTRACING_DESIRED_PAYLOAD_FORMAT, sampling_mode, sampling_rate); + char *retValue = (char *)malloc(length + 1); + if (retValue == NULL) + { + LogError("malloc failed"); + } + else + { + (void)sprintf(retValue, DTRACING_DESIRED_PAYLOAD_FORMAT, sampling_mode, sampling_rate); + } + return retValue; +} + +static void change_dtracing_setting_and_test(IOTHUB_PROVISIONED_DEVICE* deviceToUse, DEVICE_DESIRED_DATA* device, bool enableDTracing, uint8_t expected_sampling_mode, uint8_t expected_sampling_rate) +{ + (void)device; + (void)IoTHubDeviceClient_EnablePolicyConfiguration(iothub_deviceclient_handle, POLICY_CONFIGURATION_DISTRIBUTED_TRACING, enableDTracing); + + ThreadAPI_Sleep(3000); + + const char *connectionString = IoTHubAccount_GetIoTHubConnString(g_iothubAcctInfo); + IOTHUB_SERVICE_CLIENT_AUTH_HANDLE iotHubServiceClientHandle = IoTHubServiceClientAuth_CreateFromConnectionString(connectionString); + ASSERT_IS_NOT_NULL(iotHubServiceClientHandle, "IoTHubServiceClientAuth_CreateFromConnectionString failed"); + + IOTHUB_SERVICE_CLIENT_DEVICE_TWIN_HANDLE serviceClientDeviceTwinHandle = IoTHubDeviceTwin_Create(iotHubServiceClientHandle); + ASSERT_IS_NOT_NULL(serviceClientDeviceTwinHandle, "IoTHubDeviceTwin_Create failed"); + + char *buffer = malloc_and_fill_desired_dtracing_payload(expected_sampling_mode, expected_sampling_rate); + ASSERT_IS_NOT_NULL(buffer, "failed to create the payload for IoTHubDeviceTwin_UpdateTwin"); + + dt_e2e_update_twin(serviceClientDeviceTwinHandle, deviceToUse, buffer); + + ThreadAPI_Sleep(3000); + + // Send the Event from the client + MAP_HANDLE propMap = Map_Create(NULL); + client_create_with_properies_and_send_d2c(propMap); + ThreadAPI_Sleep(3000); + Map_Destroy(propMap); + + free(buffer); + IoTHubDeviceTwin_Destroy(serviceClientDeviceTwinHandle); + IoTHubServiceClientAuth_Destroy(iotHubServiceClientHandle); +} + +void dt_e2e_test_dtracing(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol, IOTHUB_ACCOUNT_AUTH_METHOD accountAuthMethod) +{ + // arrange + IOTHUB_PROVISIONED_DEVICE* deviceToUse; + if (accountAuthMethod == IOTHUB_ACCOUNT_AUTH_X509) + { + deviceToUse = IoTHubAccount_GetX509Device(g_iothubAcctInfo); + } + else + { + deviceToUse = IoTHubAccount_GetSASDevice(g_iothubAcctInfo); + } + + DEVICE_DESIRED_DATA *device = device_desired_init(); + ASSERT_IS_NOT_NULL(device, "failed to create the device client data"); + + // Create the IoT Hub Data + dt_e2e_create_client_handle(deviceToUse, protocol); + + + // subscribe + setdevicetwincallback_on_device_or_module(deviceTwinCallback, device); + + // run dtrace tests [to be verified manually until all production hubs enable this feature] + change_dtracing_setting_and_test(deviceToUse, device, true, 1, 100); + + change_dtracing_setting_and_test(deviceToUse, device, false, 1, 50); + change_dtracing_setting_and_test(deviceToUse, device, true, 2, 34); + + // unsubscribe + setdevicetwincallback_on_device_or_module(NULL, NULL); + + destroy_on_device_or_module(); + device_desired_deinit(device); +} diff --git a/iothub_client/tests/common_dt_e2e/iothubclient_common_dt_e2e.h b/iothub_client/tests/common_dt_e2e/iothubclient_common_dt_e2e.h index 2a6ac52bcf..3062023b1e 100644 --- a/iothub_client/tests/common_dt_e2e/iothubclient_common_dt_e2e.h +++ b/iothub_client/tests/common_dt_e2e/iothubclient_common_dt_e2e.h @@ -13,5 +13,6 @@ extern void dt_e2e_send_reported_test(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol, extern void dt_e2e_get_complete_desired_test(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol, IOTHUB_ACCOUNT_AUTH_METHOD accountAuthMethod); extern void dt_e2e_send_reported_test_svc_fault_ctrl_kill_Tcp(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol, IOTHUB_ACCOUNT_AUTH_METHOD accountAuthMethod); extern void dt_e2e_get_complete_desired_test_svc_fault_ctrl_kill_Tcp(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol, IOTHUB_ACCOUNT_AUTH_METHOD accountAuthMethod); +extern void dt_e2e_test_dtracing(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol, IOTHUB_ACCOUNT_AUTH_METHOD accountAuthMethod); #endif /* IOTHUBCLIENT_COMMON_DT_E2E_H */ diff --git a/iothub_client/tests/iothubclient_amqp_dt_e2e/iothubclient_amqp_dt_e2e.c b/iothub_client/tests/iothubclient_amqp_dt_e2e/iothubclient_amqp_dt_e2e.c index 430e124ec1..a87ad91580 100644 --- a/iothub_client/tests/iothubclient_amqp_dt_e2e/iothubclient_amqp_dt_e2e.c +++ b/iothub_client/tests/iothubclient_amqp_dt_e2e/iothubclient_amqp_dt_e2e.c @@ -31,6 +31,11 @@ TEST_FUNCTION(IoTHub_AMQP_GetFullDesired_e2e_sas) dt_e2e_get_complete_desired_test(AMQP_Protocol, IOTHUB_ACCOUNT_AUTH_CONNSTRING); } +TEST_FUNCTION(IoTHub_AMQP_TestDTracing_e2e_sas) +{ + dt_e2e_test_dtracing(AMQP_Protocol, IOTHUB_ACCOUNT_AUTH_CONNSTRING); +} + #ifndef __APPLE__ TEST_FUNCTION(IoTHub_AMQP_SendReported_e2e_x509) { @@ -41,6 +46,11 @@ TEST_FUNCTION(IoTHub_AMQP_GetFullDesired_e2e_x509) { dt_e2e_get_complete_desired_test(AMQP_Protocol, IOTHUB_ACCOUNT_AUTH_X509); } + +TEST_FUNCTION(IoTHub_AMQP_TestDTracing_e2e_x509) +{ + dt_e2e_test_dtracing(AMQP_Protocol, IOTHUB_ACCOUNT_AUTH_X509); +} #endif #ifndef USE_WOLFSSL // Wolf doesn't run web socket tests @@ -56,6 +66,11 @@ TEST_FUNCTION(IoTHub_AMQP_WS_GetFullDesired_e2e_sas) dt_e2e_get_complete_desired_test(AMQP_Protocol_over_WebSocketsTls, IOTHUB_ACCOUNT_AUTH_CONNSTRING); } +TEST_FUNCTION(IoTHub_AMQP_WS_TestDTracing_e2e_sas) +{ + dt_e2e_test_dtracing(AMQP_Protocol_over_WebSocketsTls, IOTHUB_ACCOUNT_AUTH_CONNSTRING); +} + #ifndef __APPLE__ TEST_FUNCTION(IoTHub_AMQP_WS_SendReported_e2e_x509) { @@ -66,6 +81,11 @@ TEST_FUNCTION(IoTHub_AMQP_WS_GetFullDesired_e2e_x509) { dt_e2e_get_complete_desired_test(AMQP_Protocol_over_WebSocketsTls, IOTHUB_ACCOUNT_AUTH_X509); } + +TEST_FUNCTION(IoTHub_AMQP_WS_TestDTracing_e2e_x509) +{ + dt_e2e_test_dtracing(AMQP_Protocol_over_WebSocketsTls, IOTHUB_ACCOUNT_AUTH_X509); +} #endif #endif diff --git a/iothub_client/tests/iothubclient_diagnostic_ut/CMakeLists.txt b/iothub_client/tests/iothubclient_diagnostic_ut/CMakeLists.txt index 133615605f..b3f28112d4 100644 --- a/iothub_client/tests/iothubclient_diagnostic_ut/CMakeLists.txt +++ b/iothub_client/tests/iothubclient_diagnostic_ut/CMakeLists.txt @@ -16,6 +16,7 @@ include_directories(${SHARED_UTIL_REAL_TEST_FOLDER}) set(${theseTestsName}_c_files ../../src/iothub_client_diagnostic.c + ../../../serializer/tests/datamarshaller_ut/real_parson.c ) set(${theseTestsName}_h_files diff --git a/iothub_client/tests/iothubclient_diagnostic_ut/iothubclient_diagnostic_ut.c b/iothub_client/tests/iothubclient_diagnostic_ut/iothubclient_diagnostic_ut.c index a1a14507d1..2745b43931 100644 --- a/iothub_client/tests/iothubclient_diagnostic_ut/iothubclient_diagnostic_ut.c +++ b/iothub_client/tests/iothubclient_diagnostic_ut/iothubclient_diagnostic_ut.c @@ -28,6 +28,8 @@ static void my_gballoc_free(void* ptr) #include "umocktypes_stdint.h" #include "umocktypes_bool.h" +#include "../../../serializer/tests/datamarshaller_ut/real_parson.h" + #define ENABLE_MOCKS #include "azure_c_shared_utility/gballoc.h" #include "azure_c_shared_utility/optimize_size.h" @@ -37,13 +39,124 @@ static void my_gballoc_free(void* ptr) #include "azure_c_shared_utility/lock.h" #include "azure_c_shared_utility/map.h" #include "iothub_message.h" +#include "parson.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +MOCKABLE_FUNCTION(, JSON_Value*, json_parse_string, const char *, string); +MOCKABLE_FUNCTION(, const char*, json_object_get_string, const JSON_Object *, object, const char *, name); +MOCKABLE_FUNCTION(, JSON_Object*, json_value_get_object, const JSON_Value *, value); +MOCKABLE_FUNCTION(, double, json_object_get_number, const JSON_Object*, object, const char*, name); +MOCKABLE_FUNCTION(, char*, json_serialize_to_string, const JSON_Value*, value); +MOCKABLE_FUNCTION(, void, json_free_serialized_string, char*, string); +MOCKABLE_FUNCTION(, const char*, json_object_dotget_string, const JSON_Object*, object, const char*, name); +MOCKABLE_FUNCTION(, JSON_Status, json_object_set_string, JSON_Object*, object, const char*, name, const char*, string); +MOCKABLE_FUNCTION(, JSON_Status, json_object_dotset_string, JSON_Object*, object, const char*, name, const char*, string); +MOCKABLE_FUNCTION(, JSON_Value*, json_value_init_object); +MOCKABLE_FUNCTION(, JSON_Array*, json_array_get_array, const JSON_Array*, array, size_t, index); +MOCKABLE_FUNCTION(, JSON_Object*, json_array_get_object, const JSON_Array*, array, size_t, index); +MOCKABLE_FUNCTION(, JSON_Array*, json_value_get_array, const JSON_Value*, value); +MOCKABLE_FUNCTION(, size_t, json_array_get_count, const JSON_Array*, array); +MOCKABLE_FUNCTION(, JSON_Status, json_array_clear, JSON_Array*, array); +MOCKABLE_FUNCTION(, JSON_Status, json_object_clear, JSON_Object*, object); +MOCKABLE_FUNCTION(, void, json_value_free, JSON_Value *, value); +MOCKABLE_FUNCTION(, char *, json_serialize_to_string_pretty, const JSON_Value *, value); +MOCKABLE_FUNCTION(, JSON_Status, json_object_dotset_value, JSON_Object *, object, const char *, name, JSON_Value *, value); +MOCKABLE_FUNCTION(, JSON_Object *, json_object, const JSON_Value *, value); + +#ifdef __cplusplus +} +#endif + #undef ENABLE_MOCKS #include "internal/iothub_client_diagnostic.h" +bool g_fail_string_construct_sprintf; +bool g_fail_string_concat_with_string; + +static const char* TEST_STRING_VALUE = "Test string value"; + +#define TEST_STRING_HANDLE (STRING_HANDLE)0x46 + DEFINE_ENUM_STRINGS(UMOCK_C_ERROR_CODE, UMOCK_C_ERROR_CODE_VALUES) +static STRING_HANDLE my_STRING_new(void) +{ + return (STRING_HANDLE)my_gballoc_malloc(1); +} + +static STRING_HANDLE my_STRING_construct(const char* psz) +{ + (void)psz; + return (STRING_HANDLE)my_gballoc_malloc(1); +} + +int STRING_sprintf(STRING_HANDLE handle, const char* format, ...) +{ + (void)handle; + (void)format; + return 0; +} + +STRING_HANDLE STRING_construct_sprintf(const char* psz, ...) +{ + (void)psz; + STRING_HANDLE result; + if (g_fail_string_construct_sprintf) + { + result = (STRING_HANDLE)NULL; + } + else + { + result = (STRING_HANDLE)my_gballoc_malloc(1); + } + return result; +} + +static int m_STRING_concat_with_STRING(STRING_HANDLE handle, STRING_HANDLE arg1) +{ + (void)handle; + (void)arg1; + int result; + if (g_fail_string_concat_with_string) + { + result = -1; + } + else + { + result = 0; + } + return result; +} + +static STRING_HANDLE my_STRING_clone(STRING_HANDLE handle) +{ + (void)handle; + return (STRING_HANDLE)my_gballoc_malloc(1); +} + +static void my_STRING_delete(STRING_HANDLE handle) +{ + (void)handle; + + if (handle != TEST_STRING_HANDLE) + { + my_gballoc_free(handle); + } +} + +int my_STRING_concat(STRING_HANDLE handle, const char* s2) +{ + (void)handle; + (void)s2; + return 0; +} + static void on_umock_c_error(UMOCK_C_ERROR_CODE error_code) { char temp_str[256]; @@ -77,6 +190,7 @@ TEST_SUITE_INITIALIZE(suite_init) REGISTER_UMOCK_ALIAS_TYPE(MAP_HANDLE, void*); REGISTER_UMOCK_ALIAS_TYPE(IOTHUB_MESSAGE_HANDLE, void*); + REGISTER_UMOCK_ALIAS_TYPE(STRING_HANDLE, void*); REGISTER_GLOBAL_MOCK_HOOK(gballoc_malloc, my_gballoc_malloc); REGISTER_GLOBAL_MOCK_FAIL_RETURN(gballoc_malloc, NULL); @@ -90,6 +204,18 @@ TEST_SUITE_INITIALIZE(suite_init) REGISTER_GLOBAL_MOCK_RETURN(get_time, g_current_time); REGISTER_GLOBAL_MOCK_FAIL_RETURN(get_time, INDEFINITE_TIME); + + REGISTER_GLOBAL_MOCK_HOOK(STRING_new, my_STRING_new); + REGISTER_GLOBAL_MOCK_FAIL_RETURN(STRING_new, NULL); + REGISTER_GLOBAL_MOCK_HOOK(STRING_construct, my_STRING_construct); + REGISTER_GLOBAL_MOCK_FAIL_RETURN(STRING_construct, NULL); + REGISTER_GLOBAL_MOCK_HOOK(STRING_concat, my_STRING_concat); + REGISTER_GLOBAL_MOCK_FAIL_RETURN(STRING_concat, __FAILURE__); + REGISTER_GLOBAL_MOCK_HOOK(STRING_concat_with_STRING, m_STRING_concat_with_STRING); + REGISTER_GLOBAL_MOCK_RETURN(STRING_c_str, TEST_STRING_VALUE); + REGISTER_GLOBAL_MOCK_HOOK(STRING_clone, my_STRING_clone); + REGISTER_GLOBAL_MOCK_FAIL_RETURN(STRING_clone, NULL); + REGISTER_GLOBAL_MOCK_HOOK(STRING_delete, my_STRING_delete); } TEST_SUITE_CLEANUP(suite_cleanup) @@ -106,6 +232,8 @@ TEST_FUNCTION_INITIALIZE(method_init) ASSERT_FAIL("Could not acquire test serialization mutex."); } umock_c_reset_all_calls(); + g_fail_string_construct_sprintf = false; + g_fail_string_concat_with_string = false; } TEST_FUNCTION_CLEANUP(method_cleanup) @@ -198,7 +326,7 @@ TEST_FUNCTION(IoTHubClient_Diagnostic_AddIfNecessary_no_diag_info_with_percentag } /* Tests_SRS_IOTHUB_DIAGNOSTIC_13_004: [ If diagSamplingPercentage is equal to 100, diagnostic properties should be added to all messages]*/ -TEST_FUNCTION(IoTHubClient_Diagnostic_AddIfNecessary_no_diag_info_with_percentage_100) +TEST_FUNCTION(IoTHubClient_Diagnostic_AddIfNecessary_diag_info_with_percentage_100) { //arrange IOTHUB_DIAGNOSTIC_SETTING_DATA diag_setting = @@ -229,7 +357,7 @@ TEST_FUNCTION(IoTHubClient_Diagnostic_AddIfNecessary_no_diag_info_with_percentag } /* Tests_SRS_IOTHUB_DIAGNOSTIC_13_005: [ If diagSamplingPercentage is between(0, 100), diagnostic properties should be added based on percentage]*/ -TEST_FUNCTION(IoTHubClient_Diagnostic_AddIfNecessary_no_diag_info_with_normal_percentage) +TEST_FUNCTION(IoTHubClient_Diagnostic_AddIfNecessary_diag_info_with_normal_percentage) { //arrange IOTHUB_DIAGNOSTIC_SETTING_DATA diag_setting = @@ -261,4 +389,36 @@ TEST_FUNCTION(IoTHubClient_Diagnostic_AddIfNecessary_no_diag_info_with_normal_pe } } +/* Tests_SRS_IOTHUB_DISTRIBUTED_38_004: [ If samplingRate is equal to 100, distributed properties should be added to all messages]*/ +TEST_FUNCTION(IoTHubClient_DistributedTracing_AddToMessageHeadersIfNecessary_distributedtracing_setting_with_percentage_100) +{ + //arrange + IOTHUB_DISTRIBUTED_TRACING_SETTING_DATA distributed_tracing_setting = + { + true, /* policyEnabled */ + IOTHUB_DISTRIBUTED_TRACING_SAMPLING_MODE_ON, /* samplingMode */ + 100, /* samplingRate */ + 0 /* currentMessageNumber */ + }; + + umock_c_reset_all_calls(); + + EXPECTED_CALL(gballoc_malloc(IGNORED_NUM_ARG)); + EXPECTED_CALL(get_time(NULL)); + EXPECTED_CALL(STRING_construct("timestamp=")); + EXPECTED_CALL(STRING_concat(IGNORED_PTR_ARG, IGNORED_PTR_ARG)); + EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)); + STRICT_EXPECTED_CALL(IoTHubMessage_SetDistributedTracingSystemProperty(IGNORED_PTR_ARG, IGNORED_PTR_ARG)); + EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)); + EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG)); + + //act + int result = IoTHubClient_DistributedTracing_AddToMessageHeadersIfNecessary(&distributed_tracing_setting, TEST_MESSAGE_HANDLE); + + //assert + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); + ASSERT_IS_TRUE(result == 0); + ASSERT_ARE_EQUAL(uint32_t, distributed_tracing_setting.currentMessageNumber, 1); +} + END_TEST_SUITE(iothubclient_diagnostic_ut) diff --git a/iothub_client/tests/iothubclient_mqtt_dt_e2e/iothubclient_mqtt_dt_e2e.c b/iothub_client/tests/iothubclient_mqtt_dt_e2e/iothubclient_mqtt_dt_e2e.c index 86cca92df0..82c80d5d9f 100644 --- a/iothub_client/tests/iothubclient_mqtt_dt_e2e/iothubclient_mqtt_dt_e2e.c +++ b/iothub_client/tests/iothubclient_mqtt_dt_e2e/iothubclient_mqtt_dt_e2e.c @@ -31,6 +31,11 @@ TEST_FUNCTION(IoTHub_MQTT_GetFullDesired_e2e_sas) dt_e2e_get_complete_desired_test(MQTT_Protocol, IOTHUB_ACCOUNT_AUTH_CONNSTRING); } +TEST_FUNCTION(IoTHub_MQTT_TestDTracing_e2e_sas) +{ + dt_e2e_test_dtracing(MQTT_Protocol, IOTHUB_ACCOUNT_AUTH_CONNSTRING); +} + #ifndef __APPLE__ TEST_FUNCTION(IoTHub_MQTT_SendReported_e2e_x509) { @@ -41,6 +46,11 @@ TEST_FUNCTION(IoTHub_MQTT_GetFullDesired_e2e_x509) { dt_e2e_get_complete_desired_test(MQTT_Protocol, IOTHUB_ACCOUNT_AUTH_X509); } + +TEST_FUNCTION(IoTHub_MQTT_TestDTracing_e2e_x509) +{ + dt_e2e_test_dtracing(MQTT_Protocol, IOTHUB_ACCOUNT_AUTH_X509); +} #endif #ifndef USE_WOLFSSL // Wolf doesn't run web socket tests @@ -57,6 +67,11 @@ TEST_FUNCTION(IoTHub_MQTT_WS_GetFullDesired_e2e_sas) dt_e2e_get_complete_desired_test(MQTT_WebSocket_Protocol, IOTHUB_ACCOUNT_AUTH_CONNSTRING); } +TEST_FUNCTION(IoTHub_MQTT_WS_TestDTracing_e2e_sas) +{ + dt_e2e_test_dtracing(MQTT_WebSocket_Protocol, IOTHUB_ACCOUNT_AUTH_CONNSTRING); +} + #ifndef __APPLE__ TEST_FUNCTION(IoTHub_MQTT_WS_GetFullDesired_e2e_x509) { @@ -67,6 +82,11 @@ TEST_FUNCTION(IoTHub_MQTT_WS_SendReported_e2e_x509) { dt_e2e_send_reported_test(MQTT_WebSocket_Protocol, IOTHUB_ACCOUNT_AUTH_X509); } + +TEST_FUNCTION(IoTHub_MQTT_WS_TestDTracing_e2e_x509) +{ + dt_e2e_test_dtracing(MQTT_WebSocket_Protocol, IOTHUB_ACCOUNT_AUTH_X509); +} #endif #endif diff --git a/iothub_client/tests/iothubclientcore_ll_ut/iothub_client_core_ll_ut.c b/iothub_client/tests/iothubclientcore_ll_ut/iothub_client_core_ll_ut.c index e710591d21..72b40c96d7 100644 --- a/iothub_client/tests/iothubclientcore_ll_ut/iothub_client_core_ll_ut.c +++ b/iothub_client/tests/iothubclientcore_ll_ut/iothub_client_core_ll_ut.c @@ -364,6 +364,13 @@ static STRING_HANDLE my_STRING_construct(const char* psz) return (STRING_HANDLE)my_gballoc_malloc(1); } +int STRING_sprintf(STRING_HANDLE handle, const char* format, ...) +{ + (void)handle; + (void)format; + return 0; +} + STRING_HANDLE STRING_construct_sprintf(const char* psz, ...) { (void)psz; @@ -878,6 +885,9 @@ TEST_SUITE_INITIALIZE(suite_init) REGISTER_GLOBAL_MOCK_RETURN(IoTHubClient_Diagnostic_AddIfNecessary, 0); REGISTER_GLOBAL_MOCK_FAIL_RETURN(IoTHubClient_Diagnostic_AddIfNecessary, 100); + REGISTER_GLOBAL_MOCK_RETURN(IoTHubClient_DistributedTracing_AddToMessageHeadersIfNecessary, 0); + REGISTER_GLOBAL_MOCK_FAIL_RETURN(IoTHubClient_DistributedTracing_AddToMessageHeadersIfNecessary, 100); + REGISTER_GLOBAL_MOCK_HOOK(IoTHubClient_Auth_CreateFromDeviceAuth, my_IoTHubClient_Auth_CreateFromDeviceAuth); REGISTER_GLOBAL_MOCK_FAIL_RETURN(IoTHubClient_Auth_CreateFromDeviceAuth, NULL); @@ -1062,7 +1072,7 @@ static void setup_IoTHubClientCore_LL_sendeventasync_mocks(bool invoke_tickcount STRICT_EXPECTED_CALL(IoTHubMessage_Clone(IGNORED_PTR_ARG)) .IgnoreArgument(1); - + STRICT_EXPECTED_CALL(IoTHubClient_Diagnostic_AddIfNecessary(IGNORED_PTR_ARG, IGNORED_PTR_ARG)) .IgnoreArgument(1) .IgnoreArgument(2); @@ -2272,7 +2282,7 @@ TEST_FUNCTION(IoTHubClientCore_LL_SendEventAsync_fails) umock_c_negative_tests_snapshot(); // act - size_t calls_cannot_fail[] = { 4 }; + size_t calls_cannot_fail[] = { 3, 4, 5 }; size_t count = umock_c_negative_tests_call_count(); for (size_t index = 0; index < count; index++) { @@ -2285,7 +2295,7 @@ TEST_FUNCTION(IoTHubClientCore_LL_SendEventAsync_fails) umock_c_negative_tests_fail_call(index); char tmp_msg[64]; - sprintf(tmp_msg, "IoTHubClientCore_LL_Create failure in test %zu/%zu", index, count); + sprintf(tmp_msg, "IoTHubClientCore_LL_SendEventAsync failure in test %zu/%zu", index, count); IOTHUB_CLIENT_RESULT result = IoTHubClientCore_LL_SendEventAsync(handle, TEST_MESSAGE_HANDLE, test_event_confirmation_callback, (void*)1); @@ -5476,6 +5486,7 @@ TEST_FUNCTION(IoTHubClientCore_LL_SetOption_product_info_fails_case1) IoTHubClientCore_LL_Destroy(h); } +//Deprecated /*Tests_SRS_IoTHubClientCore_LL_10_037: [Calling IoTHubClientCore_LL_SetOption with value between [0, 100] shall return `IOTHUB_CLIENT_OK`. ]*/ TEST_FUNCTION(IoTHubClientCore_LL_SetOption_diag_sampling_percentage_succeeds) { @@ -5495,6 +5506,7 @@ TEST_FUNCTION(IoTHubClientCore_LL_SetOption_diag_sampling_percentage_succeeds) IoTHubClientCore_LL_Destroy(h); } +//Deprecated /*Tests_SRS_IoTHubClientCore_LL_10_036: [Calling IoTHubClientCore_LL_SetOption with value > 100 shall return `IOTHUB_CLIENT_ERRROR`. ]*/ TEST_FUNCTION(IoTHubClientCore_LL_SetOption_diag_sampling_percentage_fails) { @@ -5622,7 +5634,7 @@ TEST_FUNCTION(IoTHubClientCore_LL_SendEventToOutputAsync_fails) umock_c_negative_tests_snapshot(); // act - size_t calls_cannot_fail[] = { 5 /*DList_InsertTailList*/ }; + size_t calls_cannot_fail[] = { 4 /*IoTHubClient_DistributedTracing_AddToMessageHeadersIfNecessary*/, 5 /*IoTHubClient_Diagnostic_AddIfNecessary*/, 6 /*DList_InsertTailList*/ }; size_t count = umock_c_negative_tests_call_count(); for (size_t index = 0; index < count; index++) { @@ -5635,7 +5647,7 @@ TEST_FUNCTION(IoTHubClientCore_LL_SendEventToOutputAsync_fails) umock_c_negative_tests_fail_call(index); char tmp_msg[64]; - sprintf(tmp_msg, "IoTHubClientCore_LL_Create failure in test %zu/%zu", index, count); + sprintf(tmp_msg, "IoTHubClientCore_LL_SendEventToOutputAsync failure in test %zu/%zu", index, count); IOTHUB_CLIENT_RESULT result = IoTHubClientCore_LL_SendEventToOutputAsync(handle, TEST_MESSAGE_HANDLE, TEST_OUTPUT_NAME, test_event_confirmation_callback, (void*)1); @@ -6991,4 +7003,43 @@ TEST_FUNCTION(IoTHubClientCore_LL_CreateFromEnvironment_set_connection_string_an // // +// Tests_SRS_IoTHubClientCore_LL_38_004: [ If `iotHubClientHandle` is NULL, `IoTHubClientCore_LL_EnablePolicyConfiguration` shall return IOTHUB_CLIENT_INVALID_ARG. ] +TEST_FUNCTION(IoTHubClientCore_LL_EnablePolicyConfiguration_with_NULL_iotHubClientHandle_fails) +{ + //arrange + + //act + IOTHUB_CLIENT_RESULT result = IoTHubClientCore_LL_EnablePolicyConfiguration(NULL, POLICY_CONFIGURATION_DISTRIBUTED_TRACING, true); + + ///assert + ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_INVALID_ARG, result); + + //cleanup +} + +// Tests_SRS_IOTHUBCLIENT_LL_09_012: [ IoTHubClientCore_LL_GetTwinAsync shall invoke IoTHubTransport_GetTwinAsync, passing `on_device_twin_report_received` and the user data as context ] +// Tests_SRS_IOTHUBCLIENT_LL_09_014: [ If no errors occur IoTHubClientCore_LL_GetTwinAsync shall return `IOTHUB_CLIENT_OK`. ] +TEST_FUNCTION(IoTHubClientCore_LL_EnablePolicyConfiguration_succeed) +{ + //arrange + IOTHUB_CLIENT_CORE_LL_HANDLE h = IoTHubClientCore_LL_Create(&TEST_CONFIG); + + umock_c_reset_all_calls(); + STRICT_EXPECTED_CALL(FAKE_IoTHubTransport_Subscribe_DeviceTwin(IGNORED_NUM_ARG)); + STRICT_EXPECTED_CALL(malloc(IGNORED_NUM_ARG)); + STRICT_EXPECTED_CALL(FAKE_IoTHubTransport_GetTwinAsync(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)); + + //act + IOTHUB_CLIENT_RESULT result = IoTHubClientCore_LL_EnablePolicyConfiguration(h, POLICY_CONFIGURATION_DISTRIBUTED_TRACING, true); + + //assert + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); + ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result); + ASSERT_IS_NOT_NULL(my_FAKE_IoTHubTransport_GetTwinAsync_callbackContext); + + //cleanup + IoTHubClientCore_LL_Destroy(h); + my_gballoc_free(my_FAKE_IoTHubTransport_GetTwinAsync_callbackContext); +} + END_TEST_SUITE(iothub_client_core_ll_ut) diff --git a/iothub_client/tests/iothubmessage_ut/iothubmessage_ut.c b/iothub_client/tests/iothubmessage_ut/iothubmessage_ut.c index 50ddb34067..bdf0baa07f 100644 --- a/iothub_client/tests/iothubmessage_ut/iothubmessage_ut.c +++ b/iothub_client/tests/iothubmessage_ut/iothubmessage_ut.c @@ -619,6 +619,7 @@ TEST_FUNCTION(IoTHubMessage_Destroy_destroys_a_BYTEARRAY_IoTHubMEssage) STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)); + STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(gballoc_free(h)); //act @@ -648,6 +649,7 @@ TEST_FUNCTION(IoTHubMessage_Destroy_destroys_a_STRING_IoTHubMessage) STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)); + STRICT_EXPECTED_CALL(gballoc_free(IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(gballoc_free(h)); //act diff --git a/iothub_client/tests/iothubtransport_mqtt_common_ut/iothubtransport_mqtt_common_ut.c b/iothub_client/tests/iothubtransport_mqtt_common_ut/iothubtransport_mqtt_common_ut.c index 4a28f06d64..5464e45795 100644 --- a/iothub_client/tests/iothubtransport_mqtt_common_ut/iothubtransport_mqtt_common_ut.c +++ b/iothub_client/tests/iothubtransport_mqtt_common_ut/iothubtransport_mqtt_common_ut.c @@ -189,6 +189,7 @@ static const char* TEST_OUTPUT_NAME = "TestOutputName"; static const char* PROPERTY_SEPARATOR = "&"; static const char* DIAGNOSTIC_CONTEXT_CREATION_TIME_UTC_PROPERTY = "creationtimeutc"; +static const char* DISTRIBUTED_TRACING_TEST_TRACESTATE = "tracestate=1234"; static IOTHUB_MESSAGE_DIAGNOSTIC_PROPERTY_DATA TEST_DIAG_DATA; @@ -1274,6 +1275,10 @@ static void setup_IoTHubTransport_MQTT_Common_DoWork_emtpy_msg_mocks(void) STRICT_EXPECTED_CALL(IoTHubMessage_GetMessageId(IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(IoTHubMessage_GetContentTypeSystemProperty(IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(IoTHubMessage_GetContentEncodingSystemProperty(IGNORED_PTR_ARG)); + STRICT_EXPECTED_CALL(IoTHubMessage_GetDistributedTracingSystemProperty(IGNORED_PTR_ARG)).SetReturn(DISTRIBUTED_TRACING_TEST_TRACESTATE); + STRICT_EXPECTED_CALL(URL_EncodeString(IGNORED_PTR_ARG)); + STRICT_EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)); + STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(IoTHubMessage_GetDiagnosticPropertyData(IGNORED_PTR_ARG)); @@ -1383,6 +1388,10 @@ static void setup_IoTHubTransport_MQTT_Common_DoWork_resend_events_mocks( STRICT_EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG)); } + STRICT_EXPECTED_CALL(IoTHubMessage_GetDistributedTracingSystemProperty(IGNORED_PTR_ARG)).SetReturn(DISTRIBUTED_TRACING_TEST_TRACESTATE); + STRICT_EXPECTED_CALL(URL_EncodeString(IGNORED_PTR_ARG)); + STRICT_EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)); + STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(IoTHubMessage_GetDiagnosticPropertyData(IGNORED_PTR_ARG)).SetReturn(&TEST_DIAG_DATA); bool validMessage = true; @@ -1519,6 +1528,11 @@ static void setup_IoTHubTransport_MQTT_Common_DoWork_events_mocks( STRICT_EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG)); } + STRICT_EXPECTED_CALL(IoTHubMessage_GetDistributedTracingSystemProperty(IGNORED_PTR_ARG)).SetReturn(DISTRIBUTED_TRACING_TEST_TRACESTATE); + STRICT_EXPECTED_CALL(URL_EncodeString(IGNORED_PTR_ARG)); + STRICT_EXPECTED_CALL(STRING_c_str(IGNORED_PTR_ARG)); + STRICT_EXPECTED_CALL(STRING_delete(IGNORED_PTR_ARG)); + STRICT_EXPECTED_CALL(IoTHubMessage_GetDiagnosticPropertyData(IGNORED_PTR_ARG)).SetReturn(&TEST_DIAG_DATA); bool validMessage = true; @@ -4593,7 +4607,7 @@ TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_get_item_fails) IoTHubTransport_MQTT_Common_Destroy(handle); } -TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_with_emtpy_item_succeeds) +TEST_FUNCTION(IoTHubTransport_MQTT_Common_DoWork_with_empty_item_succeeds) { // arrange IOTHUBTRANSPORT_CONFIG config = { 0 }; diff --git a/iothub_client/tests/uamqp_messaging_ut/uamqp_messaging_ut.c b/iothub_client/tests/uamqp_messaging_ut/uamqp_messaging_ut.c index cceda893d5..a5888c43b9 100644 --- a/iothub_client/tests/uamqp_messaging_ut/uamqp_messaging_ut.c +++ b/iothub_client/tests/uamqp_messaging_ut/uamqp_messaging_ut.c @@ -121,6 +121,7 @@ static int saved_amqpvalue_get_string_return = 0; static const char* TEST_CONTENT_TYPE = "text/plain"; static const char* TEST_CONTENT_ENCODING = "utf8"; static IOTHUB_MESSAGE_DIAGNOSTIC_PROPERTY_DATA TEST_DIAGNOSTIC_DATA = { "12345678", "1506054179" }; +static const char* DISTRIBUTED_TRACING_TEST_TRACESTATE = "tracestate=1234"; static int test_properties_get_message_id(PROPERTIES_HANDLE properties, AMQP_VALUE* message_id_value) @@ -199,6 +200,20 @@ static void set_exp_calls_for_create_encoded_annotations_properties(bool has_dia { STRICT_EXPECTED_CALL(IoTHubMessage_GetDiagnosticPropertyData(TEST_IOTHUB_MESSAGE_HANDLE)).SetReturn(NULL); } + + STRICT_EXPECTED_CALL(IoTHubMessage_GetDistributedTracingSystemProperty(IGNORED_PTR_ARG)).SetReturn(DISTRIBUTED_TRACING_TEST_TRACESTATE); + STRICT_EXPECTED_CALL(amqpvalue_create_map()); + + STRICT_EXPECTED_CALL(amqpvalue_create_symbol(IGNORED_PTR_ARG)); + STRICT_EXPECTED_CALL(amqpvalue_create_string(IGNORED_PTR_ARG)); + STRICT_EXPECTED_CALL(amqpvalue_set_map_value(TEST_AMQP_VALUE, TEST_AMQP_VALUE, TEST_AMQP_VALUE)); + STRICT_EXPECTED_CALL(amqpvalue_destroy(TEST_AMQP_VALUE)); + STRICT_EXPECTED_CALL(amqpvalue_destroy(TEST_AMQP_VALUE)); + + STRICT_EXPECTED_CALL(amqpvalue_create_message_annotations(TEST_AMQP_VALUE)); + STRICT_EXPECTED_CALL(amqpvalue_get_encoded_size(TEST_AMQP_VALUE, IGNORED_PTR_ARG)) + .CopyOutArgumentBuffer(2, &encoding_size, sizeof(encoding_size)); + STRICT_EXPECTED_CALL(amqpvalue_destroy(TEST_AMQP_VALUE)); } static void set_exp_calls_for_create_encoded_message_properties(bool has_message_id, bool has_correlation_id, const char* content_type, const char* content_encoding) @@ -321,10 +336,7 @@ static void set_exp_calls_for_message_create_uamqp_encoding_from_iothub_message( STRICT_EXPECTED_CALL(amqpvalue_encode(TEST_AMQP_VALUE, IGNORED_PTR_ARG, IGNORED_PTR_ARG)); } - if (has_diag_properties) - { - STRICT_EXPECTED_CALL(amqpvalue_encode(TEST_AMQP_VALUE, IGNORED_PTR_ARG, IGNORED_PTR_ARG)); - } + STRICT_EXPECTED_CALL(amqpvalue_encode(TEST_AMQP_VALUE, IGNORED_PTR_ARG, IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(amqpvalue_encode(TEST_AMQP_VALUE, IGNORED_PTR_ARG, IGNORED_PTR_ARG)); @@ -333,10 +345,7 @@ static void set_exp_calls_for_message_create_uamqp_encoding_from_iothub_message( { STRICT_EXPECTED_CALL(amqpvalue_destroy(TEST_AMQP_VALUE)); } - if (has_diag_properties) - { - STRICT_EXPECTED_CALL(amqpvalue_destroy(TEST_AMQP_VALUE)); - } + STRICT_EXPECTED_CALL(amqpvalue_destroy(TEST_AMQP_VALUE)); STRICT_EXPECTED_CALL(amqpvalue_destroy(TEST_AMQP_VALUE)); } @@ -902,26 +911,42 @@ TEST_FUNCTION(message_create_from_iothub_message_BYTEARRAY_return_errors_fails) umock_c_negative_tests_fail_call(i); if ((i == 1) || // GetMessageId is optional - (i == 5) || //GetCorrelationId is optional - (i == 9) || // ContentType is optional - (i == 11) || // ContentEncoding is optional + (i == 5) || // GetCorrelationId is optional (i == 4) || // amqpvalue_destroy (i == 8) || // amqpvalue_destroy + (i == 9) || // ContentType is optional + (i == 11) || // GetContentEncodingSystemProperty is optional (i == 15) || // properties_destroy (i == 22) || // amqpvalue_destroy (i == 23) || // amqpvalue_destroy (i == 26) || // amqpvalue_destroy - (i == 27) || //IoTHubMessage_GetDiagnosticPropertyData is optional + (i == 27) || // GetDiagnosticPropertyData is optional + (i == 28) || // amqpvalue_create_map + (i == 29) || // amqp_create_symbol + (i == 30) || // amqpvalue_create_string + (i == 31) || // amqpvalue_set_map_value (i == 32) || // amqpvalue_destroy (i == 33) || // amqpvalue_destroy + (i == 34) || // gballoc_malloc + (i == 35) || // amqp_create_symbol + (i == 36) || // amqpvalue_create_string + (i == 37) || // amqpvalue_set_map_value (i == 38) || // amqpvalue_destroy (i == 39) || // amqpvalue_destroy - (i == 42) || // free + (i == 40) || // amqpvalue_create_message_annotations + (i == 41) || // amqpvalue_get_encoded_size + (i == 42) || // gballoc_free (i == 43) || // amqpvalue_destroy + (i == 44) || // GetDistributedTracingSystemProperty is optional + (i == 45) || // amqpvalue_create_map + (i == 49) || // amqpvalue_destroy + (i == 50) || // amqpvalue_destroy (i == 53) || // amqpvalue_destroy - (i == 54) || // amqpvalue_destroy - (i == 55) || // amqpvalue_destroy - (i == 56) // amqpvalue_destroy + (i == 58) || // gballoc_malloc + (i == 63) || // amqpvalue_destroy + (i == 64) || // amqpvalue_destroy + (i == 65) || // amqpvalue_destroy + (i == 66) // amqpvalue_destroy ) { continue; // these lines have functions that do not return anything (void). @@ -965,27 +990,43 @@ TEST_FUNCTION(message_create_from_iothub_message_STRING_return_errors_fails) umock_c_negative_tests_fail_call(i); if ((i == 1) || // GetMessageId is optional - (i == 5) || //GetCorrelationId is optional - (i == 9) || // ContentType is optional - (i == 11) || // ContentEncoding is optional + (i == 5) || // GetCorrelationId is optional (i == 4) || // amqpvalue_destroy (i == 8) || // amqpvalue_destroy + (i == 9) || // ContentType is optional + (i == 11) || // GetContentEncodingSystemProperty is optional (i == 15) || // properties_destroy (i == 22) || // amqpvalue_destroy (i == 23) || // amqpvalue_destroy (i == 26) || // amqpvalue_destroy - (i == 27) || //IoTHubMessage_GetDiagnosticPropertyData is optional + (i == 27) || // GetDiagnosticPropertyData is optional + (i == 28) || // amqpvalue_create_map + (i == 29) || // amqp_create_symbol + (i == 30) || // amqpvalue_create_string + (i == 31) || // amqpvalue_set_map_value (i == 32) || // amqpvalue_destroy (i == 33) || // amqpvalue_destroy + (i == 34) || // gballoc_malloc + (i == 35) || // amqp_create_symbol + (i == 36) || // amqpvalue_create_string + (i == 37) || // amqpvalue_set_map_value (i == 38) || // amqpvalue_destroy (i == 39) || // amqpvalue_destroy - (i == 42) || // free + (i == 40) || // amqpvalue_create_message_annotations + (i == 41) || // amqpvalue_get_encoded_size + (i == 42) || // gballoc_free (i == 43) || // amqpvalue_destroy + (i == 44) || // GetDistributedTracingSystemProperty is optional + (i == 45) || // amqpvalue_create_map + (i == 49) || // amqpvalue_destroy + (i == 50) || // amqpvalue_destroy (i == 53) || // amqpvalue_destroy - (i == 54) || // amqpvalue_destroy - (i == 55) || // amqpvalue_destroy - (i == 56) // amqpvalue_destroy - ) + (i == 58) || // gballoc_malloc + (i == 63) || // amqpvalue_destroy + (i == 64) || // amqpvalue_destroy + (i == 65) || // amqpvalue_destroy + (i == 66) // amqpvalue_destroy + ) { continue; // these lines have functions that do not return anything (void). }