* Float upload to blob errors in convenience layer (gh issue #2569) * Add unit tests * Address CR comments
This commit is contained in:
Родитель
09d4e9ca46
Коммит
e0c0c2c3c1
|
@ -73,6 +73,7 @@ typedef struct UPLOADTOBLOB_MULTIBLOCK_SAVED_DATA_TAG
|
|||
{
|
||||
IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_CALLBACK getDataCallback;
|
||||
IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_CALLBACK_EX getDataCallbackEx;
|
||||
bool isCallbackInvokedWithError;
|
||||
}UPLOADTOBLOB_MULTIBLOCK_SAVED_DATA;
|
||||
|
||||
typedef struct INVOKE_METHOD_SAVED_DATA_TAG
|
||||
|
@ -2419,6 +2420,44 @@ IOTHUB_CLIENT_RESULT IoTHubClientCore_UploadToBlobAsync(IOTHUB_CLIENT_CORE_HANDL
|
|||
return result;
|
||||
}
|
||||
|
||||
// This callback wrapper allows iothub_client_core to track if the upload to blob callback has
|
||||
// been fired with a FILE_UPLOAD_ERROR already. That is because IoTHubClientCore_LL_UploadMultipleBlocksToBlob
|
||||
// will fire the user callback with error only in specific situations (i.e., uploading to Azure Storage).
|
||||
// All other errors within IoTHubClientCore_LL_UploadMultipleBlocksToBlob do not cause the callback to be invoked,
|
||||
// only signaling the upload error through the return code. However, the return code is not exposed to the user application
|
||||
// by iothub_client_core. So iothub_client_core must invoke the user callback so the user can get a feedback that
|
||||
// an upload has failed if IoTHubClientCore_LL_UploadMultipleBlocksToBlob has not done so.
|
||||
static void uploadToBlobMultiblockCallbackWrapper(IOTHUB_CLIENT_FILE_UPLOAD_RESULT result, unsigned char const ** data, size_t* size, void* context)
|
||||
{
|
||||
HTTPWORKER_THREAD_INFO* threadInfo = (HTTPWORKER_THREAD_INFO*)context;
|
||||
|
||||
if (result == FILE_UPLOAD_ERROR)
|
||||
{
|
||||
threadInfo->uploadBlobMultiblockSavedData.isCallbackInvokedWithError = true;
|
||||
}
|
||||
|
||||
threadInfo->uploadBlobMultiblockSavedData.getDataCallback(result, data, size, threadInfo->context);
|
||||
}
|
||||
|
||||
// This callback wrapper allows iothub_client_core to track if the upload to blob callback has
|
||||
// been fired with a FILE_UPLOAD_ERROR already. That is because IoTHubClientCore_LL_UploadMultipleBlocksToBlobEx
|
||||
// will fire the user callback with error only in specific situations (i.e., uploading to Azure Storage).
|
||||
// All other errors within IoTHubClientCore_LL_UploadMultipleBlocksToBlobEx do not cause the callback to be invoked,
|
||||
// only signaling the upload error through the return code. However, the return code is not exposed to the user application
|
||||
// by iothub_client_core. So iothub_client_core must invoke the user callback so the user can get a feedback that
|
||||
// an upload has failed if IoTHubClientCore_LL_UploadMultipleBlocksToBlobEx has not done so.
|
||||
static IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_RESULT uploadToBlobMultiblockCallbackWrapperEx(IOTHUB_CLIENT_FILE_UPLOAD_RESULT result, unsigned char const ** data, size_t* size, void* context)
|
||||
{
|
||||
HTTPWORKER_THREAD_INFO* threadInfo = (HTTPWORKER_THREAD_INFO*)context;
|
||||
|
||||
if (result == FILE_UPLOAD_ERROR)
|
||||
{
|
||||
threadInfo->uploadBlobMultiblockSavedData.isCallbackInvokedWithError = true;
|
||||
}
|
||||
|
||||
return threadInfo->uploadBlobMultiblockSavedData.getDataCallbackEx(result, data, size, threadInfo->context);
|
||||
}
|
||||
|
||||
static int uploadMultipleBlock_thread(void* data)
|
||||
{
|
||||
HTTPWORKER_THREAD_INFO* threadInfo = (HTTPWORKER_THREAD_INFO*)data;
|
||||
|
@ -2430,11 +2469,21 @@ static int uploadMultipleBlock_thread(void* data)
|
|||
|
||||
if (threadInfo->uploadBlobMultiblockSavedData.getDataCallback != NULL)
|
||||
{
|
||||
result = IoTHubClientCore_LL_UploadMultipleBlocksToBlob(llHandle, threadInfo->destinationFileName, threadInfo->uploadBlobMultiblockSavedData.getDataCallback, threadInfo->context);
|
||||
result = IoTHubClientCore_LL_UploadMultipleBlocksToBlob(llHandle, threadInfo->destinationFileName, uploadToBlobMultiblockCallbackWrapper, threadInfo);
|
||||
|
||||
if (result != IOTHUB_CLIENT_OK && !threadInfo->uploadBlobMultiblockSavedData.isCallbackInvokedWithError)
|
||||
{
|
||||
threadInfo->uploadBlobMultiblockSavedData.getDataCallback(FILE_UPLOAD_ERROR, NULL, NULL, threadInfo->context);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = IoTHubClientCore_LL_UploadMultipleBlocksToBlobEx(llHandle, threadInfo->destinationFileName, threadInfo->uploadBlobMultiblockSavedData.getDataCallbackEx, threadInfo->context);
|
||||
result = IoTHubClientCore_LL_UploadMultipleBlocksToBlobEx(llHandle, threadInfo->destinationFileName, uploadToBlobMultiblockCallbackWrapperEx, threadInfo);
|
||||
|
||||
if (result != IOTHUB_CLIENT_OK && !threadInfo->uploadBlobMultiblockSavedData.isCallbackInvokedWithError)
|
||||
{
|
||||
(void)threadInfo->uploadBlobMultiblockSavedData.getDataCallbackEx(FILE_UPLOAD_ERROR, NULL, NULL, threadInfo->context);
|
||||
}
|
||||
}
|
||||
(void)markThreadReadyToBeGarbageCollected(threadInfo);
|
||||
|
||||
|
|
|
@ -118,20 +118,30 @@ static int my_DeviceMethodCallback_Impl(const char* method_name, const unsigned
|
|||
return 200;
|
||||
}
|
||||
|
||||
typedef struct TEST_GETDATA_CALLBACK_ARGS_TAG
|
||||
{
|
||||
IOTHUB_CLIENT_FILE_UPLOAD_RESULT last_result;
|
||||
unsigned char const ** last_data;
|
||||
size_t* last_size;
|
||||
int invokation_counter;
|
||||
} TEST_GETDATA_CALLBACK_ARGS;
|
||||
|
||||
static void my_FileUpload_GetData_Callback(IOTHUB_CLIENT_FILE_UPLOAD_RESULT result, unsigned char const ** data, size_t* size, void* context)
|
||||
{
|
||||
(void)data;
|
||||
(void)size;
|
||||
(void)context;
|
||||
(void)result;
|
||||
TEST_GETDATA_CALLBACK_ARGS* saved_args = (TEST_GETDATA_CALLBACK_ARGS*)context;
|
||||
saved_args->last_result = result;
|
||||
saved_args->last_data = data;
|
||||
saved_args->last_size = size;
|
||||
saved_args->invokation_counter++;
|
||||
}
|
||||
|
||||
static IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_RESULT my_FileUpload_GetData_CallbackEx(IOTHUB_CLIENT_FILE_UPLOAD_RESULT result, unsigned char const ** data, size_t* size, void* context)
|
||||
{
|
||||
(void)data;
|
||||
(void)size;
|
||||
(void)context;
|
||||
(void)result;
|
||||
TEST_GETDATA_CALLBACK_ARGS* saved_args = (TEST_GETDATA_CALLBACK_ARGS*)context;
|
||||
saved_args->last_result = result;
|
||||
saved_args->last_data = data;
|
||||
saved_args->last_size = size;
|
||||
saved_args->invokation_counter++;
|
||||
return IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_OK;
|
||||
}
|
||||
|
||||
|
@ -167,6 +177,9 @@ IMPLEMENT_UMOCK_C_ENUM_TYPE(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_RESULT_VALUES);
|
|||
TEST_DEFINE_ENUM_TYPE(IOTHUB_CLIENT_RETRY_POLICY, IOTHUB_CLIENT_RETRY_POLICY_VALUES);
|
||||
IMPLEMENT_UMOCK_C_ENUM_TYPE(IOTHUB_CLIENT_RETRY_POLICY, IOTHUB_CLIENT_RETRY_POLICY_VALUES);
|
||||
|
||||
TEST_DEFINE_ENUM_TYPE(IOTHUB_CLIENT_FILE_UPLOAD_RESULT, IOTHUB_CLIENT_FILE_UPLOAD_RESULT_VALUES);
|
||||
IMPLEMENT_UMOCK_C_ENUM_TYPE(IOTHUB_CLIENT_FILE_UPLOAD_RESULT, IOTHUB_CLIENT_FILE_UPLOAD_RESULT_VALUES);
|
||||
|
||||
// Overloading operators for Micromock
|
||||
static TEST_MUTEX_HANDLE test_serialize_mutex;
|
||||
|
||||
|
@ -3216,7 +3229,7 @@ TEST_FUNCTION(IoTHubClientCore_UploadMultipleBlocksToBlobAsync_fails_when_handle
|
|||
{
|
||||
///arrange
|
||||
IOTHUB_CLIENT_CORE_HANDLE iothub_handle = NULL;
|
||||
int context = 1;
|
||||
TEST_GETDATA_CALLBACK_ARGS context = { 0 };
|
||||
umock_c_reset_all_calls();
|
||||
|
||||
///act
|
||||
|
@ -3234,7 +3247,7 @@ TEST_FUNCTION(IoTHubClientCore_UploadMultipleBlocksToBlobAsync_fails_when_destin
|
|||
{
|
||||
///arrange
|
||||
IOTHUB_CLIENT_CORE_HANDLE iothub_handle = IoTHubClientCore_Create(TEST_CLIENT_CONFIG);
|
||||
int context = 1;
|
||||
TEST_GETDATA_CALLBACK_ARGS context = { 0 };
|
||||
umock_c_reset_all_calls();
|
||||
|
||||
///act
|
||||
|
@ -3270,7 +3283,7 @@ static void IoTHubClientCore_UploadMultipleBlocksToBlobAsync_succeeds_Impl(bool
|
|||
{
|
||||
///arrange
|
||||
IOTHUB_CLIENT_CORE_HANDLE iothub_handle = IoTHubClientCore_Create(TEST_CLIENT_CONFIG);
|
||||
int context = 1;
|
||||
TEST_GETDATA_CALLBACK_ARGS context = { 0 };
|
||||
umock_c_reset_all_calls();
|
||||
|
||||
set_expected_calls_for_allocateUploadToBlob();
|
||||
|
@ -3345,7 +3358,7 @@ static void IoTHubClientCore_UploadMultipleBlocksToBlobAsync_fails_when_ThreadAP
|
|||
{
|
||||
///arrange
|
||||
IOTHUB_CLIENT_CORE_HANDLE iothub_handle = IoTHubClientCore_Create(TEST_CLIENT_CONFIG);
|
||||
int context = 1;
|
||||
TEST_GETDATA_CALLBACK_ARGS context = { 0 };
|
||||
umock_c_reset_all_calls();
|
||||
|
||||
set_expected_calls_for_allocateUploadToBlob();
|
||||
|
@ -3395,7 +3408,7 @@ static void IoTHubClientCore_UploadMultipleBlocksToBlobAsync_fails_when_strcpy_f
|
|||
{
|
||||
///arrange
|
||||
IOTHUB_CLIENT_CORE_HANDLE iothub_handle = IoTHubClientCore_Create(TEST_CLIENT_CONFIG);
|
||||
int context = 1;
|
||||
TEST_GETDATA_CALLBACK_ARGS context = { 0 };
|
||||
umock_c_reset_all_calls();
|
||||
|
||||
STRICT_EXPECTED_CALL(gballoc_malloc(IGNORED_NUM_ARG));
|
||||
|
@ -3438,7 +3451,7 @@ static void IoTHubClientCore_UploadMultipleBlocksToBlobAsync_fails_when_malloc_f
|
|||
{
|
||||
///arrange
|
||||
IOTHUB_CLIENT_CORE_HANDLE iothub_handle = IoTHubClientCore_Create(TEST_CLIENT_CONFIG);
|
||||
int context = 1;
|
||||
TEST_GETDATA_CALLBACK_ARGS context = { 0 };
|
||||
umock_c_reset_all_calls();
|
||||
|
||||
STRICT_EXPECTED_CALL(gballoc_malloc(IGNORED_NUM_ARG))
|
||||
|
@ -3474,6 +3487,106 @@ TEST_FUNCTION(IoTHubClientCore_UploadMultipleBlocksToBlobAsyncEx_fails_when_mall
|
|||
{
|
||||
IoTHubClientCore_UploadMultipleBlocksToBlobAsync_fails_when_malloc_fails_Impl(true);
|
||||
}
|
||||
|
||||
TEST_FUNCTION(IoTHubClientCore_UploadMultipleBlocksToBlobAsync_callback_invoked_on_error_return_if_not_already)
|
||||
{
|
||||
///arrange
|
||||
IOTHUB_CLIENT_CORE_HANDLE iothub_handle = IoTHubClientCore_Create(TEST_CLIENT_CONFIG);
|
||||
TEST_GETDATA_CALLBACK_ARGS context = { 0 };
|
||||
umock_c_reset_all_calls();
|
||||
|
||||
set_expected_calls_for_allocateUploadToBlob();
|
||||
STRICT_EXPECTED_CALL(ThreadAPI_Create(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG));
|
||||
STRICT_EXPECTED_CALL(Lock(IGNORED_PTR_ARG));
|
||||
|
||||
STRICT_EXPECTED_CALL(singlylinkedlist_add(IGNORED_PTR_ARG, IGNORED_PTR_ARG)); /*this is adding HTTPWORKER_THREAD_INFO to the list of HTTPWORKER_THREAD_INFO's to be cleaned*/
|
||||
STRICT_EXPECTED_CALL(ThreadAPI_Create(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG));
|
||||
STRICT_EXPECTED_CALL(Unlock(IGNORED_PTR_ARG));
|
||||
|
||||
STRICT_EXPECTED_CALL(get_time(IGNORED_NUM_ARG)).CallCannotFail();
|
||||
STRICT_EXPECTED_CALL(IoTHubClientCore_LL_UploadMultipleBlocksToBlob(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG))
|
||||
.SetReturn(IOTHUB_CLIENT_ERROR);
|
||||
|
||||
STRICT_EXPECTED_CALL(Lock(IGNORED_PTR_ARG));
|
||||
STRICT_EXPECTED_CALL(Unlock(IGNORED_PTR_ARG));
|
||||
STRICT_EXPECTED_CALL(ThreadAPI_Exit(0));
|
||||
|
||||
///act
|
||||
IOTHUB_CLIENT_RESULT result = IoTHubClientCore_UploadMultipleBlocksToBlobAsync(iothub_handle, "someFileName.txt", my_FileUpload_GetData_Callback, NULL, &context);
|
||||
g_thread_func(g_thread_func_arg); /*this is the thread uploading function*/
|
||||
|
||||
///assert
|
||||
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
|
||||
ASSERT_ARE_EQUAL(int, 1, context.invokation_counter);
|
||||
ASSERT_ARE_EQUAL(IOTHUB_CLIENT_FILE_UPLOAD_RESULT, FILE_UPLOAD_ERROR, context.last_result);
|
||||
ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result);
|
||||
|
||||
///cleanup
|
||||
umock_c_reset_all_calls();
|
||||
STRICT_EXPECTED_CALL(Lock(IGNORED_PTR_ARG));
|
||||
STRICT_EXPECTED_CALL(Unlock(IGNORED_PTR_ARG));
|
||||
|
||||
EXPECTED_CALL(ThreadAPI_Join(IGNORED_PTR_ARG, IGNORED_PTR_ARG));
|
||||
|
||||
STRICT_EXPECTED_CALL(Lock(IGNORED_PTR_ARG));
|
||||
EXPECTED_CALL(singlylinkedlist_get_head_item(TEST_SLL_HANDLE))
|
||||
.SetReturn(TEST_LIST_HANDLE);
|
||||
|
||||
setup_gargageCollection(my_malloc_items[2], true);
|
||||
setup_IothubClient_Destroy_after_garbage_collection();
|
||||
|
||||
IoTHubClientCore_Destroy(iothub_handle);
|
||||
}
|
||||
|
||||
TEST_FUNCTION(IoTHubClientCore_UploadMultipleBlocksToBlobAsync_callbackEx_invoked_on_error_return_if_not_already)
|
||||
{
|
||||
///arrange
|
||||
IOTHUB_CLIENT_CORE_HANDLE iothub_handle = IoTHubClientCore_Create(TEST_CLIENT_CONFIG);
|
||||
TEST_GETDATA_CALLBACK_ARGS context = { 0 };
|
||||
umock_c_reset_all_calls();
|
||||
|
||||
set_expected_calls_for_allocateUploadToBlob();
|
||||
STRICT_EXPECTED_CALL(ThreadAPI_Create(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG));
|
||||
STRICT_EXPECTED_CALL(Lock(IGNORED_PTR_ARG));
|
||||
|
||||
STRICT_EXPECTED_CALL(singlylinkedlist_add(IGNORED_PTR_ARG, IGNORED_PTR_ARG)); /*this is adding HTTPWORKER_THREAD_INFO to the list of HTTPWORKER_THREAD_INFO's to be cleaned*/
|
||||
STRICT_EXPECTED_CALL(ThreadAPI_Create(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG));
|
||||
STRICT_EXPECTED_CALL(Unlock(IGNORED_PTR_ARG));
|
||||
|
||||
STRICT_EXPECTED_CALL(get_time(IGNORED_NUM_ARG)).CallCannotFail();
|
||||
STRICT_EXPECTED_CALL(IoTHubClientCore_LL_UploadMultipleBlocksToBlobEx(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG))
|
||||
.SetReturn(IOTHUB_CLIENT_ERROR);
|
||||
|
||||
STRICT_EXPECTED_CALL(Lock(IGNORED_PTR_ARG));
|
||||
STRICT_EXPECTED_CALL(Unlock(IGNORED_PTR_ARG));
|
||||
STRICT_EXPECTED_CALL(ThreadAPI_Exit(0));
|
||||
|
||||
///act
|
||||
IOTHUB_CLIENT_RESULT result = IoTHubClientCore_UploadMultipleBlocksToBlobAsync(iothub_handle, "someFileName.txt", NULL, my_FileUpload_GetData_CallbackEx, &context);
|
||||
g_thread_func(g_thread_func_arg); /*this is the thread uploading function*/
|
||||
|
||||
///assert
|
||||
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
|
||||
ASSERT_ARE_EQUAL(int, 1, context.invokation_counter);
|
||||
ASSERT_ARE_EQUAL(IOTHUB_CLIENT_FILE_UPLOAD_RESULT, FILE_UPLOAD_ERROR, context.last_result);
|
||||
ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result);
|
||||
|
||||
///cleanup
|
||||
umock_c_reset_all_calls();
|
||||
STRICT_EXPECTED_CALL(Lock(IGNORED_PTR_ARG));
|
||||
STRICT_EXPECTED_CALL(Unlock(IGNORED_PTR_ARG));
|
||||
|
||||
EXPECTED_CALL(ThreadAPI_Join(IGNORED_PTR_ARG, IGNORED_PTR_ARG));
|
||||
|
||||
STRICT_EXPECTED_CALL(Lock(IGNORED_PTR_ARG));
|
||||
EXPECTED_CALL(singlylinkedlist_get_head_item(TEST_SLL_HANDLE))
|
||||
.SetReturn(TEST_LIST_HANDLE);
|
||||
|
||||
setup_gargageCollection(my_malloc_items[2], true);
|
||||
setup_IothubClient_Destroy_after_garbage_collection();
|
||||
|
||||
IoTHubClientCore_Destroy(iothub_handle);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* SYNC DEVICE METHOD */
|
||||
|
|
Загрузка…
Ссылка в новой задаче