From a50d1bc61b7b2d1d9da9e05e68adec71ec560bb9 Mon Sep 17 00:00:00 2001 From: parth21999 Date: Fri, 24 Jul 2020 12:56:17 -0400 Subject: [PATCH 01/12] file linux implementation and unit tests --- interfaces/devdoc/file_requirements.md | 2 - interfaces/tests/CMakeLists.txt | 5 +- interfaces/tests/file_int/file_int.c | 3 - .../tests/file_int/file_int_helpers_linux.c | 28 +- linux/CMakeLists.txt | 1 + linux/devdoc/file_linux_requirements.md | 56 +- linux/src/execution_engine_linux.c | 6 + linux/src/file_linux.c | 407 +++++++- linux/tests/CMakeLists.txt | 1 + linux/tests/file_linux_ut/CMakeLists.txt | 22 + linux/tests/file_linux_ut/file_linux_ut.c | 949 ++++++++++++++++++ linux/tests/file_linux_ut/main.c | 12 + linux/tests/file_linux_ut/mock_file.c | 13 + linux/tests/file_linux_ut/mock_file.h | 20 + win32/src/file_win32.c | 1 - win32/tests/file_win32_ut/file_win32_ut.c | 1 - 16 files changed, 1492 insertions(+), 35 deletions(-) create mode 100644 linux/src/execution_engine_linux.c create mode 100644 linux/tests/file_linux_ut/CMakeLists.txt create mode 100644 linux/tests/file_linux_ut/file_linux_ut.c create mode 100644 linux/tests/file_linux_ut/main.c create mode 100644 linux/tests/file_linux_ut/mock_file.c create mode 100644 linux/tests/file_linux_ut/mock_file.h diff --git a/interfaces/devdoc/file_requirements.md b/interfaces/devdoc/file_requirements.md index 0348f58d..5143d2b9 100644 --- a/interfaces/devdoc/file_requirements.md +++ b/interfaces/devdoc/file_requirements.md @@ -50,8 +50,6 @@ MOCKABLE_FUNCTION(, FILE_HANDLE, file_create,FILE_REPORT_FAULT, user_report_faul If a file by the name `full_file_name` does not exist, `file_create` creates a file by that name, opens it and returns its handle. If the file does exist, `file_create` opens the file and returns its handle. `file_create` shall register `user_report_fault_callback` with argument `user_report_fault_context` as the callback function to be called when the callback specified by the user for a specific asynchronous operation cannot be called. -**SRS_FILE_43_033: [** If `execution_engine` is `NULL`, `file_create` shall fail and return `NULL`. **]** - **SRS_FILE_43_002: [** If `full_file_name` is `NULL` then `file_create` shall fail and return `NULL`. **]** **SRS_FILE_43_037: [** If `full_file_name` is an empty string, `file_create` shall fail and return `NULL`. **]** diff --git a/interfaces/tests/CMakeLists.txt b/interfaces/tests/CMakeLists.txt index a53f1e15..f5d25b48 100644 --- a/interfaces/tests/CMakeLists.txt +++ b/interfaces/tests/CMakeLists.txt @@ -1,14 +1,11 @@ #Copyright (C) Microsoft Corporation. All rights reserved. if(${run_int_tests}) + build_test_folder(file_int) build_test_folder(interlocked_int) build_test_folder(timer_int) build_test_folder(sync_int) build_test_folder(sysinfo_int) - if(MSVC) - # waiting for timer to be implemented on linux - build_test_folder(file_int) - endif() endif() if(${run_perf_tests} AND WIN32) diff --git a/interfaces/tests/file_int/file_int.c b/interfaces/tests/file_int/file_int.c index 76618e74..cd3a03e6 100644 --- a/interfaces/tests/file_int/file_int.c +++ b/interfaces/tests/file_int/file_int.c @@ -81,7 +81,6 @@ static FILE_HANDLE file_create_helper(const char* filename) ASSERT_IS_FALSE(check_file_exists(filename)); EXECUTION_ENGINE_HANDLE execution_engine = execution_engine_create(NULL); - ASSERT_IS_NOT_NULL(execution_engine); FILE_HANDLE file_handle = file_create(execution_engine, filename, NULL, NULL); ASSERT_IS_NOT_NULL(file_handle); @@ -127,7 +126,6 @@ TEST_FUNCTION(file_create_creates_new_file) { ///arrange EXECUTION_ENGINE_HANDLE execution_engine = execution_engine_create(NULL); - ASSERT_IS_NOT_NULL(execution_engine); char filename[] = "file_create_creates_new_file.txt"; (void)delete_file(filename); ASSERT_IS_FALSE(check_file_exists(filename)); @@ -377,7 +375,6 @@ TEST_FUNCTION(perform_operations_open_write_close_open_read_close) (void)delete_file(filename); ASSERT_IS_FALSE(check_file_exists(filename)); EXECUTION_ENGINE_HANDLE execution_engine = execution_engine_create(NULL); - ASSERT_IS_NOT_NULL(execution_engine); ///act FILE_HANDLE file_handle1 = file_create(execution_engine, filename, NULL, NULL); diff --git a/interfaces/tests/file_int/file_int_helpers_linux.c b/interfaces/tests/file_int/file_int_helpers_linux.c index fb09c8c1..7e7c8809 100644 --- a/interfaces/tests/file_int/file_int_helpers_linux.c +++ b/interfaces/tests/file_int/file_int_helpers_linux.c @@ -4,12 +4,36 @@ #ifdef __cplusplus #include +#include +#include #else #include +#include +#include +#include #endif #include "file_int_helpers.h" -void delete_all_txt_files() +int delete_file(const char* filename) { - system("rm *.txt"); + char* command = malloc(strlen(filename) + 7); + if (command == NULL) + { + return -1; + } + (void)sprintf(command, "rm -f %s", filename); + (void)system(command); + free(command); + return 0; +} + +bool check_file_exists(const char* filename) +{ + FILE* file = fopen(filename, "r"); + if (file != NULL) + { + fclose(file); + return true; + } + return false; } diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt index 26b30d64..b53e63c9 100644 --- a/linux/CMakeLists.txt +++ b/linux/CMakeLists.txt @@ -31,6 +31,7 @@ set(pal_linux_c_files src/sync_linux.c src/string_utils.c src/sysinfo_linux.c + src/execution_engine_linux.c src/file_linux.c src/timer_linux.c src/${gballoc_ll_c} diff --git a/linux/devdoc/file_linux_requirements.md b/linux/devdoc/file_linux_requirements.md index ab5ea209..73b660cd 100644 --- a/linux/devdoc/file_linux_requirements.md +++ b/linux/devdoc/file_linux_requirements.md @@ -48,17 +48,19 @@ MOCKABLE_FUNCTION_WITH_RETURNS(, int, file_extend, FILE_HANDLE, handle, uint64_t MOCKABLE_FUNCTION(, FILE_HANDLE, file_create, EXECUTION_ENGINE_HANDLE, execution_engine, const char*, full_file_name, FILE_REPORT_FAULT, user_report_fault_callback, void*, user_report_fault_context); ``` -**SRS_FILE_LINUX_43_037: [** If `execution_engine` is `NULL`, `file_create` shall fail and return `NULL`. **]** - **SRS_FILE_LINUX_43_038: [** If `full_file_name` is `NULL` then `file_create` shall fail and return `NULL`. **]** **SRS_FILE_LINUX_43_050: [** If full_file_name is an empty string, `file_create` shall fail and return `NULL`. **]** **SRS_FILE_LINUX_43_029: [** `file_create` shall allocate a `FILE_HANDLE`. **]** +**SRS_FILE_LINUX_43_055: [** `file_create` shall initialize a counter for pending asynchronous operations to 0. **]** + **SRS_FILE_LINUX_43_001: [** `file_create` shall call `open` with `full_file_name` as `pathname` and flags `O_CREAT`, `O_RDWR`, `O_DIRECT` and `O_LARGEFILE`. **]** -**SRS_FILE_LINUX_43_002: [** `file_create` shall return the file handle returned by the call to `open`.**]** +**SRS_FILE_LINUX_43_053: [** If there are any other failures, `file_create` shall fail and return `NULL`. **]** + +**SRS_FILE_LINUX_43_002: [** `file_create` shall succeed and return a non-`NULL` value.**]** ## file_destroy @@ -68,7 +70,9 @@ MOCKABLE_FUNCTION(, void, file_destroy, FILE_HANDLE, handle); **SRS_FILE_LINUX_43_036: [** If `handle` is `NULL`, `file_destroy` shall return. **]** -**SRS_FILE_LINUX_43_003: [** `file_destroy` shall call `close` with `fd` as `handle`.**]** +**SRS_FILE_LINUX_43_054: [** `file_destroy` shall wait for the pending asynchronous operations counter to become equal to zero. **]** + +**SRS_FILE_LINUX_43_003: [** `file_destroy` shall call `close`.**]** **SRS_FILE_LINUX_43_030: [** `file_destroy` shall free the `FILE_HANDLE`. **]** @@ -85,20 +89,22 @@ MOCKABLE_FUNCTION_WITH_RETURNS(, FILE_WRITE_ASYNC_RESULT, file_write_async, FILE **SRS_FILE_LINUX_43_051: [** If `position` + `size` is greater than `INT64_MAX`, then `file_write_async` shall fail and return `FILE_WRITE_ASYNC_INVALID_ARGS`. **]** -**SRS_FILE_LINUX_43_049: [** **SRS_FILE_LINUX_43_033: [** If `user_callback` is `NULL` then `file_write_async` shall fail and return `FILE_WRITE_ASYNC_INVALID_ARGS`. **]** **]** +**SRS_FILE_LINUX_43_049: [** If `user_callback` is `NULL` then `file_write_async` shall fail and return `FILE_WRITE_ASYNC_INVALID_ARGS`. **]** **SRS_FILE_LINUX_43_048: [** If `size` is 0 then `file_write_async` shall fail and return `FILE_WRITE_ASYNC_INVALID_ARGS`. **]** **SRS_FILE_LINUX_43_019: [** `file_write_async` shall allocate a struct to hold `handle`, `source`, `size`, `user_callback` and `user_context`. **]** -**SRS_FILE_LINUX_43_004: [** `file_write_async` shall allocate a `sigevent` struct with `SIGEV_THREAD` as `sigev_notify`, the allocated struct as `sigev_value`, `on_file_write_complete_linux` as `sigev_notify_function`, `NULL` as `sigev_notify_attributes`. **]** +**SRS_FILE_LINUX_43_005: [** `file_write_async` shall allocate an `aiocb` struct with the file descriptor from `file_handle` as `aio_fildes`, `position` as `aio_offset`, source as `aio_buf`, `size` as `aio_nbytes`. **]** -**SRS_FILE_LINUX_43_005: [** `file_write_async` shall allocate an `aiocb` struct with `handle` as `aio_fildes`, `position` as `aio_offset`, source as `aio_buf`, `size` as `aio_nbytes`, and the allocated `sigevent` struct as `aio_sigevent`. **]** +**SRS_FILE_LINUX_43_004: [** `file_write_async` shall initialize the `sigevent` struct on the allocated `aiocb` struct with `SIGEV_THREAD` as `sigev_notify`, the allocated struct as `sigev_value`, `on_file_write_complete_linux` as `sigev_notify_function`, `NULL` as `sigev_notify_attributes`. **]** **SRS_FILE_LINUX_43_006: [** `file_write_async` shall call `aio_write` with the allocated `aiocb` struct as `aiocbp`.**]** **SRS_FILE_LINUX_43_012: [** If `aio_write` fails, `file_write_async` shall return `FILE_WRITE_ASYNC_WRITE_ERROR`. **]** +**SRS_FILE_LINUX_43_056: [** If `aio_write` succeeds, `file_write_async` shall increment the pending asynchronous operations counter on `file_handle`. **]** + **SRS_FILE_LINUX_43_007: [** If `aio_write` succeeds, `file_write_async` shall return `FILE_WRITE_ASYNC_OK`. **]** **SRS_FILE_LINUX_43_013: [** If there are any other failures, `file_write_async` shall return `FILE_WRITE_ASYNC_ERROR`. **]** @@ -119,17 +125,19 @@ MOCKABLE_FUNCTION_WITH_RETURNS(, FILE_READ_ASYNC_RESULT, file_read_async, FILE_H **SRS_FILE_LINUX_43_045: [** `file_read_async` shall allocate a struct to hold `handle`, `destination`, `user_callback` and `user_context`. **]** -**SRS_FILE_LINUX_43_008: [** `file_read_async` shall allocate a `sigevent` struct with `SIGEV_THREAD` as `sigev_notify`, `user_context` as `sigev_value`, `on_file_read_complete_linux` as `sigev_notify_function`, `NULL` as `sigev_notify_attributes`. **]** +**SRS_FILE_LINUX_43_009: [** `file_read_async` shall allocate an `aiocb` struct with the file descriptor from `file_handle` as `aio_fildes`, `position` as `aio_offset`, the allocated buffer as `aio_buf`, `size` as `aio_nbytes`. **]** -**SRS_FILE_LINUX_43_009: [** `file_read_async` shall allocate an `aiocb` struct with `handle` as `aio_fildes`, `position` as `aio_offset`, the allocated buffer as `aio_buf`, `size` as `aio_nbytes`, and the allocated `sigevent` struct as `aio_sigevent`. **]** +**SRS_FILE_LINUX_43_008: [** `file_read_async` shall initialize the `sigevent` struct on the allocated `aiocb` struct with `SIGEV_THREAD` as `sigev_notify`, `user_context` as `sigev_value`, `on_file_read_complete_linux` as `sigev_notify_function`, `NULL` as `sigev_notify_attributes`. **]** **SRS_FILE_LINUX_43_010: [** `file_read_async` shall call `aio_read` with the allocated `aiocb` struct as `aiocbp`. **]** **SRS_FILE_LINUX_43_011: [** If `aio_read` fails, `file_read_async` shall return `FILE_READ_ASYNC_READ_ERROR`. **]** +**SRS_FILE_LINUX_43_057: [** If `aio_read` succeeds, `file_read_async` shall increment the pending asynchronous operations counter on `file_handle`. **]** + **SRS_FILE_LINUX_43_014: [** If `aio_read` succeeds, `file_read_async` shall return `FILE_READ_ASYNC_OK`. **]** -**SRS_FILE_LINUX_43_015: [** If there are any failures, `file_read_async` shall return `FILE_READ_ASYNC_ERROR`. **]** +**SRS_FILE_LINUX_43_015: [** If there are any other failures, `file_read_async` shall return `FILE_READ_ASYNC_ERROR`. **]** ## file_extend @@ -149,13 +157,20 @@ static void on_file_write_complete_linux( FILE_LINUX_WRITE* write_info); `on_file_write_complete_linux` is called when an asynchronous write operation completes. `on_file_write_complete_linux` calls the user-specified callback with the user-specified context and a bool indicating the success or failure of the asynchronous operation. -**SRS_FILE_LINUX_43_047: [** If `write_info` is `NULL`, `on_file_write_complete_linux` shall call `user_report_fault_callback` with `user_report_fault_context`. **]** +**SRS_FILE_LINUX_43_058: [** `on_file_write_complete_linux` shall decrement the pending asynchronous operations counter on the `FILE_HANDLE` contained in `write_info`. **]** -**SRS_FILE_LINUX_43_021: [** `on_file_write_complete_linux` shall recover the `aiocb` struct that was used to create the current asynchronous write operation. **]** +**SRS_FILE_LINUX_43_066: [** `on_file_write_complete_linux` shall wake all threads waiting on the address of the pending asynchronous operations counter. **]** **SRS_FILE_LINUX_43_022: [** `on_file_write_complete_linux` shall call `aio_return` to determine if the asynchronous write operation succeeded. **]** -**SRS_FILE_LINUX_43_023: [** If the asynchronous write operation did not succeed, `on_file_io_complete_linux` shall call `user_callback` with `user_context` and `false` as `is_successful`. **]** +**SRS_FILE_LINUX_43_062: [** `on_file_write_complete_linux` shall free the `aiocb` struct associated with the current asynchronous write operation. **]** + +**SRS_FILE_LINUX_43_063: [** `on_file_write_complete_linux` shall free `write_info`. **]** + +**SRS_FILE_LINUX_43_023: [** If the asynchronous write operation did not succeed, `on_file_write_complete_linux` shall call `user_callback` with `user_context` and `false` as `is_successful`. **]** + +**SRS_FILE_LINUX_43_064: [** If the number of bytes written are less than the bytes requested by the user, `on_file_write_complete_linux` shall call `user_callback` with `user_context` and `false` as `is_successful`. **]** + **SRS_FILE_LINUX_43_027: [** If the asynchronous write operation succeeded, `on_file_write_complete_linux` shall call `user_callback` with `user_context` and `true` as `is_successful`. **]** @@ -165,14 +180,21 @@ static void on_file_write_complete_linux( FILE_LINUX_WRITE* write_info); static void on_file_read_complete_linux( FILE_LINUX_READ* read_info); ``` -`on_file_read_complete_linux` is called when an asynchronous read operation completes. `on_file_write_complete_linux` calls the user-specified callback with the user-specified context and a bool indicating the success or failure of the asynchronous operation. +`on_file_read_complete_linux` is called when an asynchronous read operation completes. `on_file_read_complete_linux` calls the user-specified callback with the user-specified context and a bool indicating the success or failure of the asynchronous operation. + -**SRS_FILE_LINUX_43_046: [** If `read_info` is `NULL`, `on_file_write_complete_linux` shall call `user_report_fault_callback` with `user_report_fault_context`. **]** +**SRS_FILE_LINUX_43_059: [** `on_file_read_complete_linux` shall decrement the pending asynchronous operations counter on the `FILE_HANDLE` contained in `read_info`. **]** -**SRS_FILE_LINUX_43_039: [** `on_file_read_complete_linux` shall recover the `aiocb` struct that was used to create the current asynchronous read operation. **]** +**SRS_FILE_LINUX_43_067: [** `on_file_read_complete_linux` shall wake all threads waiting on the address of the pending asynchronous operations counter. **]** **SRS_FILE_LINUX_43_040: [** `on_file_read_complete_linux` shall call `aio_return` to determine if the asynchronous read operation succeeded. **]** -**SRS_FILE_LINUX_43_041: [** If the asynchronous read operation did not succeed, `on_file_io_complete_linux` shall call `user_callback` with `user_context` and `false` as `is_successful`. **]** +**SRS_FILE_LINUX_43_060: [** `on_file_read_complete_linux` shall free the `aiocb` struct associated with the current asynchronous read operation. **]** + +**SRS_FILE_LINUX_43_061: [** `on_file_read_complete_linux` shall free `read_info`. **]** + +**SRS_FILE_LINUX_43_041: [** If the asynchronous read operation did not succeed, `on_file_read_complete_linux` shall call `user_callback` with `user_context` and `false` as `is_successful`. **]** + +**SRS_FILE_LINUX_43_065: [** If the number of bytes read are less than the bytes requested by the user, `on_file_read_complete_linux` shall call `user_callback` with `user_context` and `false` as `is_successful`. **]** **SRS_FILE_LINUX_43_042: [** If the asynchronous read operation succeeded, `on_file_read_complete_linux` shall call `user_callback` with `user_context` and `false` as `is_successful`. **]** \ No newline at end of file diff --git a/linux/src/execution_engine_linux.c b/linux/src/execution_engine_linux.c new file mode 100644 index 00000000..632577b4 --- /dev/null +++ b/linux/src/execution_engine_linux.c @@ -0,0 +1,6 @@ +#include "azure_c_pal/execution_engine.h" + +EXECUTION_ENGINE_HANDLE execution_engine_create(void* execution_engine_parameters) +{ + return (EXECUTION_ENGINE_HANDLE)0; +} diff --git a/linux/src/file_linux.c b/linux/src/file_linux.c index cf7cba83..163c2e1e 100644 --- a/linux/src/file_linux.c +++ b/linux/src/file_linux.c @@ -1,21 +1,40 @@ // Copyright (C) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + + +#include "c_logging/xlogging.h" #include "c_pal/file.h" +#include "c_pal/interlocked.h" +#include "c_pal/sync.h" +#include "c_pal/gballoc.h" typedef struct FILE_HANDLE_DATA_TAG { - int handle; FILE_REPORT_FAULT user_report_fault_callback; void* user_report_fault_context; + int h_file; + volatile_atomic int32_t pending_io; }FILE_HANDLE_DATA; typedef struct FILE_LINUX_WRITE_TAG { FILE_HANDLE handle; FILE_CB user_callback; + struct aiocb* aiocbp; void* user_context; - const unsigned char* source; uint32_t size; }FILE_LINUX_WRITE; @@ -23,10 +42,388 @@ typedef struct FILE_LINUX_READ_TAG { FILE_HANDLE handle; FILE_CB user_callback; + struct aiocb* aiocbp; void* user_context; - unsigned char* destination; uint32_t size; }FILE_LINUX_READ; -static void on_file_write_complete_linux( FILE_LINUX_WRITE* write_info); -static void on_file_read_complete_linux( FILE_LINUX_READ* read_info); +static void on_file_write_complete_linux(__sigval_t sigval) +{ + FILE_LINUX_WRITE* write_info = (FILE_LINUX_WRITE*)sigval.sival_ptr; + uint32_t size = write_info->size; + + /*Codes_SRS_FILE_LINUX_43_058: [ on_file_write_complete_linux shall decrement the pending asynchronous operations counter on the FILE_HANDLE contained in write_info. ]*/ + (void)interlocked_decrement(&write_info->handle->pending_io); + /*Codes_SRS_FILE_LINUX_43_066: [ on_file_write_complete_linux shall wake all threads waiting on the address of the pending asynchronous operations counter. ]*/ + wake_by_address_all(&write_info->handle->pending_io); + + /*Codes_SRS_FILE_LINUX_43_022: [ on_file_write_complete_linux shall call aio_return to determine if the asynchronous write operation succeeded. ]*/ + int return_val = aio_return(write_info->aiocbp); + FILE_CB user_callback = write_info->user_callback; + void* user_context = write_info->user_context; + + /*Codes_SRS_FILE_LINUX_43_062: [ on_file_write_complete_linux shall free the aiocb struct associated with the current asynchronous write operation. ]*/ + free(write_info->aiocbp); + /*Codes_SRS_FILE_LINUX_43_063: [ on_file_write_complete_linux shall free write_info. ]*/ + free(write_info); + + bool succeeded; + if (return_val == -1) + { + /*Codes_SRS_FILE_LINUX_43_023: [ If the asynchronous write operation did not succeed, on_file_io_complete_linux shall call user_callback with user_context and false as is_successful. ]*/ + succeeded = false; + LogError("Error in asynchronous write operation, errno=%d", errno); + } + else if ((uint32_t)return_val != size) + { + /*Codes_SRS_FILE_LINUX_43_064: [ If the number of bytes written are less than the bytes requested by the user, on_file_write_complete_linux shall call user_callback with user_context and false as is_successful. ]*/ + succeeded = false; + LogError("All bytes were not written."); + } + else + { + /*Codes_SRS_FILE_LINUX_43_027: [ If the asynchronous write operation succeeded, on_file_write_complete_linux shall call user_callback with user_context and true as is_successful. ]*/ + succeeded = true; + } + user_callback(user_context, succeeded); +} + +static void on_file_read_complete_linux(__sigval_t sigval) +{ + FILE_LINUX_READ* read_info = (FILE_LINUX_READ*)sigval.sival_ptr; + uint32_t size = read_info->size; + + /*Codes_SRS_FILE_LINUX_43_059: [ on_file_read_complete_linux shall decrement the pending asynchronous operations counter on the FILE_HANDLE contained in read_info. ]*/ + (void)interlocked_decrement(&read_info->handle->pending_io); + /*Codes_SRS_FILE_LINUX_43_067: [ on_file_read_complete_linux shall wake all threads waiting on the address of the pending asynchronous operations counter. ]*/ + wake_by_address_all(&read_info->handle->pending_io); + + /*Codes_SRS_FILE_LINUX_43_040: [ on_file_read_complete_linux shall call aio_return to determine if the asynchronous read operation succeeded. ]*/ + int return_val = aio_return(read_info->aiocbp); + FILE_CB user_callback = read_info->user_callback; + void* user_context = read_info->user_context; + + /*Codes_SRS_FILE_LINUX_43_060: [ on_file_read_complete_linux shall free the aiocb struct associated with the current asynchronous read operation. ]*/ + free(read_info->aiocbp); + /*Codes_SRS_FILE_LINUX_43_061: [ on_file_read_complete_linux shall free read_info. ]*/ + free(read_info); + + bool succeeded; + if (return_val == -1) + { + /*Codes_SRS_FILE_LINUX_43_041: [ If the asynchronous read operation did not succeed, on_file_io_complete_linux shall call user_callback with user_context and false as is_successful. ]*/ + succeeded = false; + LogError("Error in asynchronous read operation, errno=%d", errno); + } + else if ((uint32_t)return_val != size) + { + /*Codes_SRS_FILE_LINUX_43_065: [ If the number of bytes read are less than the bytes requested by the user, on_file_read_complete_linux shall call user_callback with user_context and false as is_successful. ]*/ + succeeded = false; + LogError("All bytes were not read."); + } + else + { + /*Codes_SRS_FILE_LINUX_43_042: [ If the asynchronous read operation succeeded, on_file_read_complete_linux shall call user_callback with user_context and false as is_successful. ]*/ + succeeded = true; + } + user_callback(user_context, succeeded); +} + +IMPLEMENT_MOCKABLE_FUNCTION(, FILE_HANDLE, file_create, EXECUTION_ENGINE_HANDLE, execution_engine, const char*, full_file_name, FILE_REPORT_FAULT, user_report_fault_callback, void*, user_report_fault_context) +{ + (void)execution_engine; + FILE_HANDLE result; + if ( + /*Codes_SRS_FILE_43_002: [ If full_file_name is NULL then file_create shall fail and return NULL. ]*/ + /*Codes_SRS_FILE_LINUX_43_038: [ If full_file_name is NULL then file_create shall fail and return NULL. ]*/ + (full_file_name == NULL) || + /*Codes_SRS_FILE_43_037: [ If full_file_name is an empty string, file_create shall fail and return NULL. ]*/ + /*Codes_SRS_FILE_LINUX_43_050: [ If full_file_name is an empty string, file_create shall fail and return NULL. ]*/ + (full_file_name[0] == '\0') + ) + { + LogError("Invalid arguments to file_create: EXECUTION_ENGINE_HANDLE execution_engine=%p, const char* full_file_name=%s, FILE_REPORT_FAULT user_report_callback=%p, void* user_report_faul_context=%p", + execution_engine, MU_P_OR_NULL(full_file_name), user_report_fault_callback, user_report_fault_context); + result = NULL; + } + else + { + /*Codes_SRS_FILE_LINUX_43_029: [ file_create shall allocate a FILE_HANDLE. ]*/ + result = malloc(sizeof(FILE_HANDLE_DATA)); + if (result == NULL) + { + /*Codes_SRS_FILE_43_034: [ If there are any failures, file_create shall fail and return NULL. ]*/ + /*Codes_SRS_FILE_LINUX_43_053: [ If there are any other failures, file_create shall fail and return NULL. ]*/ + LogError("Failure in malloc"); + } + else + { + /*Codes_SRS_FILE_43_003: [ If a file with name full_file_name does not exist, file_create shall create a file with that name.]*/ + /*Codes_SRS_FILE_LINUX_43_001: [ file_create shall call open with full_file_name as pathname and flags O_CREAT, O_RDWR, O_DIRECT and O_LARGEFILE. ]*/ + result->h_file = open(full_file_name, O_CREAT | O_RDWR | __O_DIRECT | __O_LARGEFILE, 0777); + if ( result->h_file == -1) + { + /*Codes_SRS_FILE_43_034: [ If there are any failures, file_create shall fail and return NULL. ]*/ + /*Codes_SRS_FILE_LINUX_43_053: [ If there are any other failures, file_create shall fail and return NULL. ]*/ + LogError("Failure in open, full_file_name=%s, errno=%d", full_file_name, errno); + free(result); + result = NULL; + } + else + { + /*Codes_SRS_FILE_LINUX_43_002: [ file_create shall succeed and return a non-NULL value.]*/ + /*Codes_SRS_FILE_LINUX_43_055: [ file_create shall initialize a counter for pending asynchronous operations to 0. ]*/ + (void)interlocked_exchange(&result->pending_io, 0); + result->user_report_fault_callback = user_report_fault_callback; + result->user_report_fault_context = user_report_fault_context; + } + } + } + return result; +} + + +IMPLEMENT_MOCKABLE_FUNCTION(, void, file_destroy, FILE_HANDLE, handle) +{ + + if (handle == NULL) + { + /*Codes_SRS_FILE_43_005: [ If handle is NULL, file_destroy shall return. ]*/ + /*Codes_SRS_FILE_LINUX_43_036: [ If handle is NULL, file_destroy shall return. ]*/ + LogError("Invalid argument to file_destroy: FILE_HANDLE=%p", handle); + } + else + { + /*Codes_SRS_FILE_43_006: [ file_destroy shall wait for all pending I/O operations to complete. ]*/ + /*Codes_SRS_FILE_LINUX_43_054: [ file_destroy shall wait for the pending asynchronous operations counter to become equal to zero. ]*/ + int32_t pending = interlocked_add(&handle->pending_io, 0); + while (pending != 0) + { + wait_on_address(&handle->pending_io, &pending, UINT32_MAX); + pending = interlocked_add(&handle->pending_io, 0); + } + /*Codes_SRS_FILE_LINUX_43_003: [ file_destroy shall call close.]*/ + if (close(handle->h_file) == -1) + { + LogError("failure in close, FILE_HANDLE=%p, errno=%d", handle, errno); + } + /*Codes_SRS_FILE_LINUX_43_030: [ file_destroy shall free the FILE_HANDLE. ]*/ + free(handle); + } +} + +IMPLEMENT_MOCKABLE_FUNCTION(, FILE_WRITE_ASYNC_RESULT, file_write_async, FILE_HANDLE, handle, const unsigned char*, source, uint32_t, size, uint64_t, position, FILE_CB, user_callback, void*, user_context) +{ + FILE_WRITE_ASYNC_RESULT result; + if + ( + /*Codes_SRS_FILE_43_009: [ If handle is NULL then file_write_async shall fail and return FILE_WRITE_ASYNC_INVALID_ARGS. ]*/ + /*Codes_SRS_FILE_LINUX_43_031: [ If handle is NULL then file_write_async shall fail and return FILE_WRITE_ASYNC_INVALID_ARGS. ]*/ + (handle == NULL) || + /*Codes_SRS_FILE_43_010: [ If source is NULL then file_write_async shall fail and return FILE_WRITE_ASYNC_INVALID_ARGS. ]*/ + /*Codes_SRS_FILE_LINUX_43_032: [ If source is NULL then file_write_async shall fail and return FILE_WRITE_ASYNC_INVALID_ARGS. ]*/ + (source == NULL) || + /*Codes_SRS_FILE_43_012: [ If user_callback is NULL then file_write_async shall fail and return FILE_WRITE_ASYNC_INVALID_ARGS. ]*/ + /*Codes_SRS_FILE_LINUX_43_049: [ If user_callback is NULL then file_write_async shall fail and return FILE_WRITE_ASYNC_INVALID_ARGS. ]*/ + (user_callback == NULL)|| + /*Codes_SRS_FILE_43_040: [ If position + size is greater than INT64_MAX, then file_write_async shall fail and return FILE_WRITE_ASYNC_INVALID_ARGS. ]*/ + /*Codes_SRS_FILE_LINUX_43_051: [ If position + size is greater than INT64_MAX, then file_write_async shall fail and return FILE_WRITE_ASYNC_INVALID_ARGS. ]*/ + ((position + size) > INT64_MAX)|| + /*Codes_SRS_FILE_43_042: [ If size is 0 then file_write_async shall fail and return FILE_WRITE_ASYNC_INVALID_ARGS. ]*/ + /*Codes_SRS_FILE_LINUX_43_048: [ If size is 0 then file_write_async shall fail and return FILE_WRITE_ASYNC_INVALID_ARGS. ]*/ + (size == 0) + ) + { + LogError("Invalid arguments to file_write_async: FILE_HANDLE file_handle=%p, const unsigned char* source=%p, uin32_t size=%" PRIu32 ", uint64_t position=%" PRIu64 ", FILE_CB user_callback=%p, void* user_context=%p", + handle, source, size, position, user_callback, user_context); + result = FILE_WRITE_ASYNC_INVALID_ARGS; + } + else + { + bool callback_will_be_called; + /*Codes_SRS_FILE_LINUX_43_019: [ file_write_async shall allocate a struct to hold handle, source, size, user_callback and user_context. ]*/ + FILE_LINUX_WRITE* io_context = malloc(sizeof(FILE_LINUX_WRITE)); + if (io_context == NULL) + { + /*Codes_SRS_FILE_43_015: [ If there are any failures, file_write_async shall fail and return FILE_WRITE_ASYNC_ERROR. ]*/ + LogError("failure in malloc"); + result = FILE_WRITE_ASYNC_ERROR; + } + else + { + io_context->handle = handle; + io_context->size = size; + io_context->user_callback = user_callback; + io_context->user_context = user_context; + + /*Codes_SRS_FILE_LINUX_43_005: [ file_write_async shall allocate an aiocb struct with the file descriptor from file_handle as aio_fildes, position as aio_offset, source as aio_buf, size as aio_nbytes. ]*/ + io_context->aiocbp = malloc(sizeof(struct aiocb)); + if (io_context->aiocbp == NULL) + { + /*Codes_SRS_FILE_43_015: [ If there are any failures, file_write_async shall fail and return FILE_WRITE_ASYNC_ERROR. ]*/ + /*Codes_SRS_FILE_LINUX_43_013: [ If there are any other failures, file_write_async shall return FILE_WRITE_ASYNC_ERROR. ]*/ + LogError("Failure in malloc."); + result = FILE_WRITE_ASYNC_ERROR; + } + else + { + + (void)memset(io_context->aiocbp, 0, sizeof(struct aiocb)); + io_context->aiocbp->aio_fildes = handle->h_file; + io_context->aiocbp->aio_buf = (unsigned char*)source; + io_context->aiocbp->aio_nbytes = size; + io_context->aiocbp->aio_offset = position; + + /*Codes_SRS_FILE_LINUX_43_004: [ file_write_async shall initialize the sigevent struct on the allocated aiocb struct with SIGEV_THREAD as sigev_notify, the allocated struct as sigev_value, on_file_write_complete_linux as sigev_notify_function, NULL as sigev_notify_attributes. ]*/ + (void)memset(&io_context->aiocbp->aio_sigevent, 0, sizeof(struct sigevent)); + io_context->aiocbp->aio_sigevent.sigev_notify = SIGEV_THREAD; + io_context->aiocbp->aio_sigevent.sigev_value.sival_ptr = io_context; + io_context->aiocbp->aio_sigevent.sigev_notify_function = on_file_write_complete_linux; + io_context->aiocbp->aio_sigevent.sigev_notify_attributes = NULL; + + /*Codes_SRS_FILE_43_014: [ file_write_async shall enqueue a write request to write source's content to the position offset in the file. ]*/ + /*Codes_SRS_FILE_43_041: [ If position + size is greater than the size of the file and the call to write is successfull, file_write_async shall grow the file to accomodate the write. ]*/ + /*Codes_SRS_FILE_LINUX_43_006: [ file_write_async shall call aio_write with the allocated aiocb struct as aiocbp.]*/ + if (aio_write(io_context->aiocbp) == -1) + { + /*Codes_SRS_FILE_43_035: [ If the call to write the file fails, file_write_async shall fail and return FILE_WRITE_ASYNC_WRITE_ERROR. ]*/ + /*Codes_SRS_FILE_LINUX_43_012: [ If aio_write fails, file_write_async shall return FILE_WRITE_ASYNC_WRITE_ERROR. ]*/ + LogError("Failure in aio_write, errno=%d", errno); + callback_will_be_called = false; + result = FILE_WRITE_ASYNC_WRITE_ERROR; + } + else + { + /*Codes_SRS_FILE_43_008: [ file_write_async shall call user_call_back passing user_context and success depending on the success of the asynchronous write operation.]*/ + /*Codes_SRS_FILE_43_030: [ file_write_async shall succeed and return FILE_WRITE_ASYNC_OK. ]*/ + /*Codes_SRS_FILE_LINUX_43_007: [ If aio_write succeeds, file_write_async shall return FILE_WRITE_ASYNC_OK. ]*/ + /*Codes_SRS_FILE_LINUX_43_056: [ If aio_write succeeds, file_write_async shall increment the pending asynchronous operations counter on file_handle. ]*/ + (void)interlocked_increment(&handle->pending_io); + callback_will_be_called = true; + result = FILE_WRITE_ASYNC_OK; + } + if (!callback_will_be_called) + { + free(io_context->aiocbp); + } + } + if (!callback_will_be_called) + { + free(io_context); + } + } + } + return result; +} + +IMPLEMENT_MOCKABLE_FUNCTION(, FILE_READ_ASYNC_RESULT, file_read_async, FILE_HANDLE, handle, unsigned char*, destination, uint32_t, size, uint64_t, position, FILE_CB, user_callback, void*, user_context) +{ + FILE_READ_ASYNC_RESULT result; + if + ( + /*Codes_SRS_FILE_43_017: [ If handle is NULL then file_read_async shall fail and return FILE_READ_ASYNC_INVALID_ARGS. ]*/ + /*Codes_SRS_FILE_LINUX_43_034: [ If handle is NULL then file_read_async shall fail and return FILE_READ_ASYNC_INVALID_ARGS. ]*/ + (handle == NULL) || + /*Codes_SRS_FILE_43_032: [ If destination is NULL then file_read_async shall fail and return FILE_READ_ASYNC_INVALID_ARGS. ]*/ + /*Codes_SRS_FILE_LINUX_43_043: [ IfdestinationisNULLthenfile_read_asyncshall fail and returnFILE_READ_ASYNC_INVALID_ARGS`. ]*/ + (destination == NULL) || + /*Codes_SRS_FILE_43_020: [ If user_callback is NULL then file_read_async shall fail and return FILE_READ_ASYNC_INVALID_ARGS. ]*/ + /*Codes_SRS_FILE_LINUX_43_035: [ If user_callback is NULL then file_read_async shall fail and return FILE_READ_ASYNC_INVALID_ARGS. ]*/ + (user_callback == NULL)|| + /*Codes_SRS_FILE_43_043: [ If size is 0 then file_read_async shall fail and return FILE_READ_ASYNC_INVALID_ARGS. ]*/ + /*Codes_SRS_FILE_LINUX_43_052: [ If size is 0 then file_read_async shall fail and return FILE_READ_ASYNC_INVALID_ARGS. ]*/ + (size == 0) + ) + { + LogError("Invalid arguments to file_read_async: FILE_HANDLE file_handle=%p, unsigned char* destination=%p, uin32_t size=%" PRIu32 ", uint64_t position=%" PRIu64 ", FILE_CB user_callback=%p, void* user_context=%p", + handle, destination, size, position, user_callback, user_context); + result = FILE_READ_ASYNC_INVALID_ARGS; + } + else + { + bool callback_will_be_called; + /*Codes_SRS_FILE_LINUX_43_045: [ file_read_async shall allocate a struct to hold handle, destination, user_callback and user_context. ]*/ + FILE_LINUX_READ* io_context = malloc(sizeof(FILE_LINUX_READ)); + if (io_context == NULL) + { + /*Codes_SRS_FILE_43_022: [ If there are any failures then file_read_async shall fail and return FILE_READ_ASYNC_ERROR. ]*/ + /*Codes_SRS_FILE_LINUX_43_015: [ If there are any other failures, file_read_async shall return FILE_READ_ASYNC_ERROR. ]*/ + LogError("failure in malloc"); + callback_will_be_called = false; + result = FILE_WRITE_ASYNC_ERROR; + } + else + { + io_context->handle = handle; + io_context->size = size; + io_context->user_callback = user_callback; + io_context->user_context = user_context; + + /*Codes_SRS_FILE_LINUX_43_009: [ file_read_async shall allocate an aiocb struct with the file descriptor from file_handle as aio_fildes, position as aio_offset, the allocated buffer as aio_buf, size as aio_nbytes. ]*/ + io_context->aiocbp = malloc(sizeof(struct aiocb)); + if (io_context->aiocbp == NULL) + { + /*Codes_SRS_FILE_43_022: [ If there are any failures then file_read_async shall fail and return FILE_READ_ASYNC_ERROR. ]*/ + /*Codes_SRS_FILE_LINUX_43_015: [ If there are any other failures, file_read_async shall return FILE_READ_ASYNC_ERROR. ]*/ + LogError("failure in malloc"); + callback_will_be_called = false; + result = FILE_WRITE_ASYNC_ERROR; + } + else + { + (void)memset(io_context->aiocbp, 0, sizeof(struct aiocb)); + io_context->aiocbp->aio_fildes = handle->h_file; + io_context->aiocbp->aio_buf = destination; + io_context->aiocbp->aio_nbytes = size; + io_context->aiocbp->aio_offset = position; + + /*Codes_SRS_FILE_LINUX_43_008: [ file_read_async shall initialize the sigevent struct on the allocated aiocb struct with SIGEV_THREAD as sigev_notify, user_context as sigev_value, on_file_read_complete_linux as sigev_notify_function, NULL as sigev_notify_attributes. ]*/ + (void)memset(&io_context->aiocbp->aio_sigevent, 0, sizeof(struct sigevent)); + io_context->aiocbp->aio_sigevent.sigev_notify = SIGEV_THREAD; + io_context->aiocbp->aio_sigevent.sigev_value.sival_ptr = io_context; + io_context->aiocbp->aio_sigevent.sigev_notify_function = on_file_read_complete_linux; + io_context->aiocbp->aio_sigevent.sigev_notify_attributes = NULL; + + /*Codes_SRS_FILE_43_021: [ file_read_async shall enqueue a read request to read handle's content at position offset and write it to destination. ]*/ + /*Codes_SRS_FILE_43_039: [ If position + size exceeds the size of the file, user_callback shall be called with success as false. ]*/ + /*Codes_SRS_FILE_LINUX_43_010: [ file_read_async shall call aio_read with the allocated aiocb struct as aiocbp. ]*/ + if (aio_read(io_context->aiocbp) == -1) + { + /*Codes_SRS_FILE_43_036: [ If the call to read the file fails, file_read_async shall fail and return FILE_READ_ASYNC_READ_ERROR. ]*/ + /*Codes_SRS_FILE_LINUX_43_011: [ If aio_read fails, file_read_async shall return FILE_READ_ASYNC_READ_ERROR. ]*/ + LogError("Failure in aio_read, errno=%d", errno); + callback_will_be_called = false; + result = FILE_READ_ASYNC_READ_ERROR; + } + else + { + /*Codes_SRS_FILE_43_016: [ file_read_async shall call user_callback passing user_context and success depending on the success of the asynchronous read operation.]*/ + /*Codes_SRS_FILE_43_031: [ file_read_async shall succeed and return FILE_READ_ASYNC_OK. ]*/ + /*Codes_SRS_FILE_LINUX_43_057: [ If aio_read succeeds, file_read_async shall increment the pending asynchronous operations counter on file_handle. ]*/ + /*Codes_SRS_FILE_LINUX_43_014: [ If aio_read succeeds, file_read_async shall return FILE_READ_ASYNC_OK. ]*/ + (void)interlocked_increment(&handle->pending_io); + callback_will_be_called = true; + result = FILE_READ_ASYNC_OK; + } + if (!callback_will_be_called) + { + free(io_context->aiocbp); + } + } + if (!callback_will_be_called) + { + free(io_context); + } + } + } + return result; +} + +IMPLEMENT_MOCKABLE_FUNCTION(, int, file_extend, FILE_HANDLE, handle, uint64_t, desired_size) +{ + (void)handle; + (void)desired_size; + /*Codes_SRS_FILE_LINUX_43_018: [ file_extend shall return 0. ]*/ + return 0; +} + diff --git a/linux/tests/CMakeLists.txt b/linux/tests/CMakeLists.txt index f07b5a2e..2ae29f8a 100644 --- a/linux/tests/CMakeLists.txt +++ b/linux/tests/CMakeLists.txt @@ -3,6 +3,7 @@ # unit tests if(${run_unittests}) build_test_folder(interlocked_linux_ut) + build_test_folder(file_linux_ut) build_test_folder(uniqueid_ut) build_test_folder(linux_reals_ut) build_test_folder(sync_linux_ut) diff --git a/linux/tests/file_linux_ut/CMakeLists.txt b/linux/tests/file_linux_ut/CMakeLists.txt new file mode 100644 index 00000000..4dc4d6df --- /dev/null +++ b/linux/tests/file_linux_ut/CMakeLists.txt @@ -0,0 +1,22 @@ +#Copyright (c) Microsoft. All rights reserved. +#Licensed under the MIT license. See LICENSE file in the project root for full license information. + +cmake_minimum_required(VERSION 2.8.11) + +compileAsC11() +set(theseTestsName file_linux_ut) + +set(${theseTestsName}_test_files +${theseTestsName}.c +) + +set(${theseTestsName}_c_files +mock_file.c +) + +set(${theseTestsName}_h_files +../../../interfaces/inc/azure_c_pal/file.h +mock_file.h +) + +build_c_tests(${theseTestsName} ON "tests/azure_c_pal/linux" ADDITIONAL_LIBS pal_interfaces) diff --git a/linux/tests/file_linux_ut/file_linux_ut.c b/linux/tests/file_linux_ut/file_linux_ut.c new file mode 100644 index 00000000..a66ad224 --- /dev/null +++ b/linux/tests/file_linux_ut/file_linux_ut.c @@ -0,0 +1,949 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#ifdef __cplusplus +#include +#include +#else +#include +#include +#include +#endif + +#include +#include +#include + +#include "azure_macro_utils/macro_utils.h" + +void* real_malloc(size_t size) +{ + return malloc(size); +} + +void real_free(void* ptr) +{ + free(ptr); +} + +#include "testrunnerswitcher.h" +#include "umock_c/umock_c.h" +#include "umock_c/umocktypes_bool.h" +#include "umock_c/umocktypes_stdint.h" +#include "umock_c/umock_c_negative_tests.h" + + +#define ENABLE_MOCKS + +#include "azure_c_pal/gballoc.h" +#include "azure_c_pal/interlocked.h" +#include "azure_c_pal/sync.h" +#include "mock_file.h" + +MOCKABLE_FUNCTION(, void, mock_user_callback, void*, user_context, bool, is_successful); + +#undef ENABLE_MOCKS + +#include "azure_c_pal/file.h" + +static TEST_MUTEX_HANDLE g_testByTest; + +MU_DEFINE_ENUM_STRINGS(UMOCK_C_ERROR_CODE, UMOCK_C_ERROR_CODE_VALUES) + +TEST_DEFINE_ENUM_TYPE(FILE_WRITE_ASYNC_RESULT, FILE_WRITE_ASYNC_RESULT) +IMPLEMENT_UMOCK_C_ENUM_TYPE(FILE_WRITE_ASYNC_RESULT, FILE_WRITE_ASYNC_VALUES) + +TEST_DEFINE_ENUM_TYPE(FILE_READ_ASYNC_RESULT, FILE_READ_ASYNC_RESULT) +IMPLEMENT_UMOCK_C_ENUM_TYPE(FILE_READ_ASYNC_RESULT, FILE_READ_ASYNC_VALUES) + +#define FILE_IO_ASYNC_VALUES \ + \ + FILE_READ_ASYNC +MU_DEFINE_ENUM(FILE_IO_ASYNC_TYPE, FILE_IO_ASYNC_VALUES); + +static void on_umock_c_error(UMOCK_C_ERROR_CODE error_code) +{ + ASSERT_FAIL("umock_c reported error :%" PRI_MU_ENUM "", MU_ENUM_VALUE(UMOCK_C_ERROR_CODE, error_code)); +} + +static int fake_fildes = 42; +static EXECUTION_ENGINE_HANDLE fake_execution_engine = (EXECUTION_ENGINE_HANDLE)43; + +static void setup_file_create_expectations(const char* filename) +{ + STRICT_EXPECTED_CALL(malloc(IGNORED_ARG)); + STRICT_EXPECTED_CALL(mock_open(filename, O_CREAT | O_RDWR | __O_DIRECT | __O_LARGEFILE)); + STRICT_EXPECTED_CALL(interlocked_exchange(IGNORED_ARG, 0)) + .CallCannotFail(); +} + +static FILE_HANDLE get_file_handle(const char* filename) +{ + setup_file_create_expectations(filename); + + FILE_HANDLE file_handle = file_create(fake_execution_engine, filename, NULL, NULL); + ASSERT_IS_NOT_NULL(file_handle); + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); + + umock_c_reset_all_calls(); + return file_handle; +} + + +static FILE_HANDLE start_file_write_async(const unsigned char* buffer, uint32_t size, uint64_t position, FILE_CB user_callback, void* user_context, void** captured_aiocbp, void (**captured_callback)(__sigval_t), __sigval_t* captured_write_context) +{ + FILE_HANDLE file_handle = get_file_handle("test_file.txt"); + + STRICT_EXPECTED_CALL(malloc(IGNORED_ARG)); + STRICT_EXPECTED_CALL(malloc(sizeof(struct aiocb))) + .CaptureReturn(captured_aiocbp); + STRICT_EXPECTED_CALL(mock_aio_write(IGNORED_ARG)) + .ValidateArgumentValue_aiocbp(captured_aiocbp); + STRICT_EXPECTED_CALL(interlocked_increment(IGNORED_ARG)); + + FILE_WRITE_ASYNC_RESULT result = file_write_async(file_handle, buffer, size, position, user_callback, user_context); + + *captured_callback = ((struct aiocb*)(*captured_aiocbp))->aio_sigevent.sigev_notify_function; + *captured_write_context = ((struct aiocb*)(*captured_aiocbp))->aio_sigevent.sigev_value; + + ASSERT_ARE_EQUAL(FILE_WRITE_ASYNC_RESULT, FILE_WRITE_ASYNC_OK, result); + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); + umock_c_reset_all_calls(); + return file_handle; +} + +static FILE_HANDLE start_file_read_async(unsigned char* buffer, uint32_t size, uint64_t position, FILE_CB user_callback, void* user_context, void** captured_aiocbp, void (**captured_callback)(__sigval_t), __sigval_t* captured_read_context) +{ + FILE_HANDLE file_handle = get_file_handle("test_file.txt"); + + STRICT_EXPECTED_CALL(malloc(IGNORED_ARG)); + STRICT_EXPECTED_CALL(malloc(sizeof(struct aiocb))) + .CaptureReturn(captured_aiocbp); + STRICT_EXPECTED_CALL(mock_aio_read(IGNORED_ARG)) + .ValidateArgumentValue_aiocbp(captured_aiocbp); + STRICT_EXPECTED_CALL(interlocked_increment(IGNORED_ARG)); + + FILE_READ_ASYNC_RESULT result = file_read_async(file_handle, buffer, size, position, user_callback, user_context); + + *captured_callback = ((struct aiocb*)(*captured_aiocbp))->aio_sigevent.sigev_notify_function; + *captured_read_context = ((struct aiocb*)(*captured_aiocbp))->aio_sigevent.sigev_value; + + ASSERT_ARE_EQUAL(FILE_READ_ASYNC_RESULT, FILE_READ_ASYNC_OK, result); + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); + umock_c_reset_all_calls(); + return file_handle; +} + +static void call_callback(struct aiocb* aiocbp) +{ + aiocbp->aio_sigevent.sigev_notify_function(aiocbp->aio_sigevent.sigev_value); +} + +BEGIN_TEST_SUITE(file_linux_unittests) + +TEST_SUITE_INITIALIZE(suite_init) +{ + g_testByTest = TEST_MUTEX_CREATE(); + ASSERT_IS_NOT_NULL(g_testByTest); + ASSERT_ARE_EQUAL(int, 0, umock_c_init(on_umock_c_error)); + ASSERT_ARE_EQUAL(int, 0, umocktypes_bool_register_types()); + ASSERT_ARE_EQUAL(int, 0, umocktypes_stdint_register_types()); + + REGISTER_GLOBAL_MOCK_HOOK(malloc, real_malloc); + REGISTER_GLOBAL_MOCK_HOOK(free, real_free); + + REGISTER_TYPE(FILE_WRITE_ASYNC_RESULT, FILE_WRITE_ASYNC_RESULT); + REGISTER_TYPE(FILE_READ_ASYNC_RESULT, FILE_READ_ASYNC_RESULT); + + REGISTER_GLOBAL_MOCK_FAIL_RETURN(malloc, NULL); + REGISTER_GLOBAL_MOCK_RETURNS(mock_open, fake_fildes, -1); + REGISTER_GLOBAL_MOCK_RETURNS(mock_close, 0, -1); + REGISTER_GLOBAL_MOCK_FAIL_RETURN(mock_aio_write, -1); + REGISTER_GLOBAL_MOCK_FAIL_RETURN(mock_aio_read, -1); + REGISTER_GLOBAL_MOCK_FAIL_RETURN(mock_aio_return, -1); +} + +TEST_SUITE_CLEANUP(TestClassCleanup) +{ + umock_c_deinit(); + + TEST_MUTEX_DESTROY(g_testByTest); +} + +TEST_FUNCTION_INITIALIZE(f) +{ + if (TEST_MUTEX_ACQUIRE(g_testByTest)) + { + ASSERT_FAIL("our mutex is ABANDONED. Failure in test framework"); + } + + umock_c_reset_all_calls(); + umock_c_negative_tests_init(); +} + +TEST_FUNCTION_CLEANUP(cleans) +{ + umock_c_negative_tests_deinit(); + TEST_MUTEX_RELEASE(g_testByTest); +} + +/*Tests_SRS_FILE_43_002: [ If full_file_name is NULL then file_create shall fail and return NULL. ]*/ +/*Tests_SRS_FILE_LINUX_43_038: [ If full_file_name is NULL then file_create shall fail and return NULL. ]*/ +TEST_FUNCTION(file_create_fails_on_null_full_file_name) +{ + ///arrange + ///act + FILE_HANDLE return_val = file_create(fake_execution_engine, NULL, NULL, NULL); + ///assert + ASSERT_IS_NULL(return_val); + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); +} + +/*Tests_SRS_FILE_43_037: [ If full_file_name is an empty string, file_create shall fail and return NULL. ]*/ +/*Tests_SRS_FILE_LINUX_43_050: [ If full_file_name is an empty string, file_create shall fail and return NULL. ]*/ +TEST_FUNCTION(file_create_fails_on_empty_full_file_name) +{ + ///arrange + ///act + FILE_HANDLE return_val = file_create(fake_execution_engine, "", NULL, NULL); + ///assert + ASSERT_IS_NULL(return_val); + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); +} + +/*Tests_SRS_FILE_LINUX_43_029: [ file_create shall allocate a FILE_HANDLE. ]*/ +/*Tests_SRS_FILE_LINUX_43_055: [ file_create shall initialize a counter for pending asynchronous operations to 0. ]*/ +/*Tests_SRS_FILE_LINUX_43_001: [ file_create shall call open with full_file_name as pathname and flags O_CREAT, O_RDWR, O_DIRECT and O_LARGEFILE. ]*/ +/*Tests_SRS_FILE_LINUX_43_002: [ file_create shall succeed and return a non-NULL value.]*/ +TEST_FUNCTION(file_create_succeeds) +{ + ///arrange + char* filename = "file_create_succeeds.txt"; + setup_file_create_expectations(filename); + + ///act + FILE_HANDLE file_handle = file_create(fake_execution_engine, filename, NULL, NULL); + + ///assert + ASSERT_IS_NOT_NULL(file_handle); + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); + + ///cleanup + file_destroy(file_handle); +} + +/*Tests_SRS_FILE_43_034: [ If there are any failures, file_create shall fail and return NULL. ]*/ +/*Tests_SRS_FILE_LINUX_43_053: [ If there are any other failures, file_create shall fail and return NULL. ]*/ +TEST_FUNCTION(file_create_fails) +{ + ///arrange + const char filename[] = "file_create_succeeds.txt"; + + setup_file_create_expectations(filename); + + umock_c_negative_tests_snapshot(); + for (size_t i = 0; i < umock_c_negative_tests_call_count(); ++i) + { + if (umock_c_negative_tests_can_call_fail(i)) + { + umock_c_negative_tests_reset(); + umock_c_negative_tests_fail_call(i); + + ///act + FILE_HANDLE file_handle = file_create(fake_execution_engine, filename, NULL, NULL); + + ///assert + ASSERT_IS_NULL(file_handle); + } + } +} + +/*Tests_SRS_FILE_43_005: [ If handle is NULL, file_destroy shall return. ]*/ +/*Tests_SRS_FILE_LINUX_43_036: [ If handle is NULL, file_destroy shall return. ]*/ +TEST_FUNCTION(file_destroy_called_with_null_handle) +{ + ///arrange + + ///act + file_destroy(NULL); + + ///assert + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); +} + +/*Tests_SRS_FILE_43_006: [ file_destroy shall wait for all pending I/O operations to complete. ]*/ +/*Tests_SRS_FILE_43_007: [ file_destroy shall close the file handle handle. ]*/ +/*Tests_SRS_FILE_LINUX_43_054: [ file_destroy shall wait for the pending asynchronous operations counter to become equal to zero. ]*/ +/*Tests_SRS_FILE_LINUX_43_003: [ file_destroy shall call close.]*/ +/*Tests_SRS_FILE_LINUX_43_030: [ file_destroy shall free the FILE_HANDLE. ]*/ +TEST_FUNCTION(file_destroy_succeeds) +{ + + ///arrange + const char* filename = "file_destroy_succeeds.txt"; + setup_file_create_expectations(filename); + + FILE_HANDLE file_handle = file_create(fake_execution_engine, filename, NULL, NULL); + + ASSERT_IS_NOT_NULL(file_handle); + umock_c_reset_all_calls(); + + STRICT_EXPECTED_CALL(interlocked_add(IGNORED_ARG, 0)); + STRICT_EXPECTED_CALL(wait_on_address(IGNORED_ARG, IGNORED_ARG, UINT32_MAX)); + STRICT_EXPECTED_CALL(mock_close(fake_fildes)); + STRICT_EXPECTED_CALL(free(file_handle)); + + ///act + file_destroy(file_handle); + + ///assert + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); +} + +/*Tests_SRS_FILE_43_009: [ If handle is NULL then file_write_async shall fail and return FILE_WRITE_ASYNC_INVALID_ARGS. ]*/ +/*Tests_SRS_FILE_LINUX_43_031: [ If handle is NULL then file_write_async shall fail and return FILE_WRITE_ASYNC_INVALID_ARGS. ]*/ +TEST_FUNCTION(file_write_async_fails_with_null_handle) +{ + ///arrange + unsigned char source[10]; + + ///act + FILE_WRITE_ASYNC_RESULT result = file_write_async(NULL, source, 1, 1, mock_user_callback, NULL); + + ///assert + ASSERT_ARE_EQUAL(FILE_WRITE_ASYNC_RESULT, FILE_WRITE_ASYNC_INVALID_ARGS, result); + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); +} + +/*Tests_SRS_FILE_43_010: [ If source is NULL then file_write_async shall fail and return FILE_WRITE_ASYNC_INVALID_ARGS. ]*/ +/*Tests_SRS_FILE_LINUX_43_032: [ If source is NULL then file_write_async shall fail and return FILE_WRITE_ASYNC_INVALID_ARGS. ]*/ +TEST_FUNCTION(file_write_async_fails_with_null_source) +{ + ///arrange + FILE_HANDLE file_handle = get_file_handle("file_write_async_fails_with_null_source.txt"); + + ///act + FILE_WRITE_ASYNC_RESULT result = file_write_async(file_handle, NULL, 1, 1, mock_user_callback, NULL); + + ///assert + ASSERT_ARE_EQUAL(FILE_WRITE_ASYNC_RESULT, FILE_WRITE_ASYNC_INVALID_ARGS, result); + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); + + ///cleanup + file_destroy(file_handle); +} + +/*Tests_SRS_FILE_43_012: [ If user_callback is NULL then file_write_async shall fail and return FILE_WRITE_ASYNC_INVALID_ARGS. ]*/ +/*Tests_SRS_FILE_LINUX_43_049: [ If user_callback is NULL then file_write_async shall fail and return FILE_WRITE_ASYNC_INVALID_ARGS. ]*/ +TEST_FUNCTION(file_write_async_fails_with_null_user_callback) +{ + ///arrange + FILE_HANDLE file_handle = get_file_handle("file_write_async_fails_with_null_user_callback.txt"); + unsigned char source[10]; + + ///act + FILE_WRITE_ASYNC_RESULT result = file_write_async(file_handle, source, 1, 1, NULL, NULL); + + ///assert + ASSERT_ARE_EQUAL(FILE_WRITE_ASYNC_RESULT, FILE_WRITE_ASYNC_INVALID_ARGS, result); + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); + + ///cleanup + file_destroy(file_handle); +} + +/*Tests_SRS_FILE_43_040: [ If position + size is greater than INT64_MAX, then file_write_async shall fail and return FILE_WRITE_ASYNC_INVALID_ARGS. ]*/ +/*Tests_SRS_FILE_LINUX_43_051: [ If position + size is greater than INT64_MAX, then file_write_async shall fail and return FILE_WRITE_ASYNC_INVALID_ARGS. ]*/ +TEST_FUNCTION(file_write_async_fails_if_write_overflows_max_size) +{ + ///arrange + FILE_HANDLE file_handle = get_file_handle("file_write_async_fails_if_write_overflows_max_size.txt"); + unsigned char source[10]; + + ///act + FILE_WRITE_ASYNC_RESULT result = file_write_async(file_handle, source, 1, INT64_MAX, mock_user_callback, NULL); + + ///assert + ASSERT_ARE_EQUAL(FILE_WRITE_ASYNC_RESULT, FILE_WRITE_ASYNC_INVALID_ARGS, result); + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); + + ///cleanup + file_destroy(file_handle); +} + +/*Tests_SRS_FILE_43_042: [ If size is 0 then file_write_async shall fail and return FILE_WRITE_ASYNC_INVALID_ARGS. ]*/ +/*Tests_SRS_FILE_LINUX_43_048: [ If size is 0 then file_write_async shall fail and return FILE_WRITE_ASYNC_INVALID_ARGS. ]*/ +TEST_FUNCTION(file_write_async_fails_if_size_is_zero) +{ + ///arrange + FILE_HANDLE file_handle = get_file_handle("file_write_async_fails_if_size_is_zero.txt"); + unsigned char source[10]; + + ///act + FILE_WRITE_ASYNC_RESULT result = file_write_async(file_handle, source, 0, INT64_MAX, mock_user_callback, NULL); + + ///assert + ASSERT_ARE_EQUAL(FILE_WRITE_ASYNC_RESULT, FILE_WRITE_ASYNC_INVALID_ARGS, result); + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); + + ///cleanup + file_destroy(file_handle); +} + +/*Tests_SRS_FILE_LINUX_43_019: [ file_write_async shall allocate a struct to hold handle, source, size, user_callback and user_context. ]*/ +/*Tests_SRS_FILE_LINUX_43_004: [ file_write_async shall initialize the sigevent struct on the allocated aiocb struct with SIGEV_THREAD as sigev_notify, the allocated struct as sigev_value, on_file_write_complete_linux as sigev_notify_function, NULL as sigev_notify_attributes. ]*/ +/*Tests_SRS_FILE_LINUX_43_005: [ file_write_async shall allocate an aiocb struct with the file descriptor from file_handle as aio_fildes, position as aio_offset, source as aio_buf, size as aio_nbytes. ]*/ +/*Tests_SRS_FILE_LINUX_43_006: [ file_write_async shall call aio_write with the allocated aiocb struct as aiocbp.]*/ +/*Tests_SRS_FILE_LINUX_43_056: [ If aio_write succeeds, file_write_async shall increment the pending asynchronous operations counter on file_handle. ]*/ +/*Tests_SRS_FILE_LINUX_43_007: [ If aio_write succeeds, file_write_async shall return FILE_WRITE_ASYNC_OK. ]*/ +TEST_FUNCTION(file_write_async_succeeds_asynchronously) +{ + ///arrange + FILE_HANDLE file_handle = get_file_handle("file_write_async_succeeds_asynchronously.txt"); + unsigned char source[10]; + uint32_t size = 10; + uint64_t position = 5; + + void* captured_aiocbp; + + STRICT_EXPECTED_CALL(malloc(IGNORED_ARG)); + STRICT_EXPECTED_CALL(malloc(sizeof(struct aiocb))) + .CaptureReturn(&captured_aiocbp); + STRICT_EXPECTED_CALL(mock_aio_write(IGNORED_ARG)) + .ValidateArgumentValue_aiocbp(&captured_aiocbp); + STRICT_EXPECTED_CALL(interlocked_increment(IGNORED_ARG)); + + ///act + FILE_WRITE_ASYNC_RESULT result = file_write_async(file_handle, source, size, position, mock_user_callback, NULL); + + ///assert + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); + ASSERT_ARE_EQUAL(FILE_WRITE_ASYNC_RESULT, FILE_WRITE_ASYNC_OK, result); + ASSERT_ARE_EQUAL(int, SIGEV_THREAD, ((struct aiocb*)captured_aiocbp)->aio_sigevent.sigev_notify); + ASSERT_ARE_EQUAL(uint64_t, position, ((struct aiocb*)captured_aiocbp)->aio_offset); + ASSERT_IS_NULL(((struct aiocb*)captured_aiocbp)->aio_sigevent.sigev_notify_attributes); + + ///cleanup + call_callback(captured_aiocbp); + file_destroy(file_handle); +} + +/*Tests_SRS_FILE_43_035: [ If the call to write the file fails, file_write_async shall fail and return FILE_WRITE_ASYNC_WRITE_ERROR. ]*/ +/*Tests_SRS_FILE_LINUX_43_019: [ file_write_async shall allocate a struct to hold handle, source, size, user_callback and user_context. ]*/ +/*Tests_SRS_FILE_LINUX_43_004: [ file_write_async shall initialize the sigevent struct on the allocated aiocb struct with SIGEV_THREAD as sigev_notify, the allocated struct as sigev_value, on_file_write_complete_linux as sigev_notify_function, NULL as sigev_notify_attributes. ]*/ +/*Tests_SRS_FILE_LINUX_43_006: [ file_write_async shall call aio_write with the allocated aiocb struct as aiocbp.]*/ +/*Tests_SRS_FILE_LINUX_43_012: [ If aio_write fails, file_write_async shall return FILE_WRITE_ASYNC_WRITE_ERROR. ]*/ +TEST_FUNCTION(file_write_async_fails_synchronously) +{ + ///arrange + FILE_HANDLE file_handle = get_file_handle("file_write_async_fails_synchronously.txt"); + unsigned char source[10]; + uint32_t size = 10; + uint64_t position = 5; + + void* io_context; + void* captured_aiocbp; + + STRICT_EXPECTED_CALL(malloc(IGNORED_ARG)) + .CaptureReturn(&io_context); + STRICT_EXPECTED_CALL(malloc(sizeof(struct aiocb))) + .CaptureReturn(&captured_aiocbp); + STRICT_EXPECTED_CALL(mock_aio_write(IGNORED_ARG)) + .SetReturn(-1); + STRICT_EXPECTED_CALL(free(IGNORED_ARG)) + .ValidateArgumentValue_ptr(&captured_aiocbp); + STRICT_EXPECTED_CALL(free(IGNORED_ARG)) + .ValidateArgumentValue_ptr(&io_context); + ///act + FILE_WRITE_ASYNC_RESULT result = file_write_async(file_handle, source, size, position, mock_user_callback, NULL); + + ///assert + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); + ASSERT_ARE_EQUAL(FILE_WRITE_ASYNC_RESULT, FILE_WRITE_ASYNC_WRITE_ERROR, result); + + ///cleanup + file_destroy(file_handle); +} + +/*Tests_SRS_FILE_43_015: [ If there are any failures, file_write_async shall fail and return FILE_WRITE_ASYNC_ERROR. ]*/ +/*Tests_SRS_FILE_LINUX_43_013: [ If there are any other failures, file_write_async shall return FILE_WRITE_ASYNC_ERROR. ]*/ +TEST_FUNCTION(file_write_async_fails) +{ + ///arrange + FILE_HANDLE file_handle = get_file_handle("file_write_async_fails.txt"); + unsigned char source[10]; + uint32_t size = 10; + uint64_t position = 5; + void* io; + + STRICT_EXPECTED_CALL(malloc(IGNORED_ARG)); + STRICT_EXPECTED_CALL(malloc(sizeof(struct aiocb))); + STRICT_EXPECTED_CALL(mock_aio_write(IGNORED_ARG)) + .CallCannotFail(); + + umock_c_negative_tests_snapshot(); + for (size_t i = 0; i < umock_c_negative_tests_call_count(); ++i) + { + if (umock_c_negative_tests_can_call_fail(i)) + { + umock_c_negative_tests_reset(); + umock_c_negative_tests_fail_call(i); + + ///act + FILE_WRITE_ASYNC_RESULT result = file_write_async(file_handle, source, size, position, mock_user_callback, NULL); + + ///assert + ASSERT_ARE_EQUAL(FILE_WRITE_ASYNC_RESULT, FILE_WRITE_ASYNC_ERROR, result); + } + } + + ///cleanup + file_destroy(file_handle); +} + +/*Tests_SRS_FILE_43_017: [ If handle is NULL then file_read_async shall fail and return FILE_READ_ASYNC_INVALID_ARGS. ]*/ +/*Tests_SRS_FILE_LINUX_43_034: [ If handle is NULL then file_read_async shall fail and return FILE_READ_ASYNC_INVALID_ARGS. ]*/ +TEST_FUNCTION(file_read_async_fails_with_null_handle) +{ + ///arrange + unsigned char destination[10]; + + ///act + FILE_READ_ASYNC_RESULT result = file_read_async(NULL, destination, 1, 1, mock_user_callback, NULL); + + ///assert + ASSERT_ARE_EQUAL(FILE_READ_ASYNC_RESULT, FILE_READ_ASYNC_INVALID_ARGS, result); +} + +/*Tests_SRS_FILE_43_032: [ If destination is NULL then file_read_async shall fail and return FILE_READ_ASYNC_INVALID_ARGS. ]*/ +/*Tests_SRS_FILE_LINUX_43_043: [ IfdestinationisNULLthenfile_read_asyncshall fail and returnFILE_READ_ASYNC_INVALID_ARGS`. ]*/ +TEST_FUNCTION(file_read_async_fails_with_null_destination) +{ + ///arrange + FILE_HANDLE file_handle = get_file_handle("file_read_async_fails_with_null_destination.txt"); + + ///act + FILE_READ_ASYNC_RESULT result = file_read_async(file_handle, NULL, 1, 1, mock_user_callback, NULL); + + ///assert + ASSERT_ARE_EQUAL(FILE_READ_ASYNC_RESULT, FILE_READ_ASYNC_INVALID_ARGS, result); + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); + + ///cleanup + file_destroy(file_handle); +} + +/*Tests_SRS_FILE_43_020: [ If user_callback is NULL then file_read_async shall fail and return FILE_READ_ASYNC_INVALID_ARGS. ]*/ +/*Tests_SRS_FILE_LINUX_43_035: [ If user_callback is NULL then file_read_async shall fail and return FILE_READ_ASYNC_INVALID_ARGS. ]*/ +TEST_FUNCTION(file_read_async_fails_with_null_user_callback) +{ + ///arrange + FILE_HANDLE file_handle = get_file_handle("file_read_async_fails_with_null_user_callback.txt"); + unsigned char destination[10]; + + ///act + FILE_READ_ASYNC_RESULT result = file_read_async(file_handle, destination, 1, 1, NULL, NULL); + + ///assert + ASSERT_ARE_EQUAL(FILE_READ_ASYNC_RESULT, FILE_READ_ASYNC_INVALID_ARGS, result); + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); + + ///cleanup + file_destroy(file_handle); +} + +/*Tests_SRS_FILE_43_043: [ If size is 0 then file_read_async shall fail and return FILE_READ_ASYNC_INVALID_ARGS. ]*/ +/*Tests_SRS_FILE_LINUX_43_052: [ If size is 0 then file_read_async shall fail and return FILE_READ_ASYNC_INVALID_ARGS. ]*/ +TEST_FUNCTION(file_read_async_fails_if_size_is_zero) +{ + ///arrange + FILE_HANDLE file_handle = get_file_handle("file_read_async_fails_if_size_is_zero.txt"); + unsigned char source[10]; + + ///act + FILE_READ_ASYNC_RESULT result = file_read_async(file_handle, source, 0, INT64_MAX, mock_user_callback, NULL); + + ///assert + ASSERT_ARE_EQUAL(FILE_READ_ASYNC_RESULT, FILE_READ_ASYNC_INVALID_ARGS, result); + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); + + ///cleanup + file_destroy(file_handle); +} + +/*Tests_SRS_FILE_LINUX_43_045: [ file_read_async shall allocate a struct to hold handle, destination, user_callback and user_context. ]*/ +/*Tests_SRS_FILE_LINUX_43_009: [ file_read_async shall allocate an aiocb struct with the file descriptor from file_handle as aio_fildes, position as aio_offset, the allocated buffer as aio_buf, size as aio_nbytes. ]*/ +/*Tests_SRS_FILE_LINUX_43_008: [ file_read_async shall initialize the sigevent struct on the allocated aiocb struct with SIGEV_THREAD as sigev_notify, user_context as sigev_value, on_file_read_complete_linux as sigev_notify_function, NULL as sigev_notify_attributes. ]*/ +/*Tests_SRS_FILE_LINUX_43_010: [ file_read_async shall call aio_read with the allocated aiocb struct as aiocbp. ]*/ +/*Tests_SRS_FILE_LINUX_43_057: [ If aio_read succeeds, file_read_async shall increment the pending asynchronous operations counter on file_handle. ]*/ +/*Tests_SRS_FILE_LINUX_43_014: [ If aio_read succeeds, file_read_async shall return FILE_READ_ASYNC_OK. ]*/ +TEST_FUNCTION(file_read_async_succeeds_asynchronously) +{ + ///arrange + FILE_HANDLE file_handle = get_file_handle("file_read_async_succeeds_asynchronously.txt"); + unsigned char destination[10]; + uint32_t size = 10; + uint64_t position = 5; + + void* captured_aiocbp; + + STRICT_EXPECTED_CALL(malloc(IGNORED_ARG)); + STRICT_EXPECTED_CALL(malloc(sizeof(struct aiocb))) + .CaptureReturn(&captured_aiocbp); + STRICT_EXPECTED_CALL(mock_aio_read(IGNORED_ARG)) + .ValidateArgumentValue_aiocbp(&captured_aiocbp); + STRICT_EXPECTED_CALL(interlocked_increment(IGNORED_ARG)); + + ///act + FILE_READ_ASYNC_RESULT result = file_read_async(file_handle, destination, size, position, mock_user_callback, NULL); + + ///assert + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); + ASSERT_ARE_EQUAL(FILE_READ_ASYNC_RESULT, FILE_READ_ASYNC_OK, result); + ASSERT_ARE_EQUAL(int, SIGEV_THREAD, ((struct aiocb*)captured_aiocbp)->aio_sigevent.sigev_notify); + ASSERT_ARE_EQUAL(uint64_t, position, ((struct aiocb*)captured_aiocbp)->aio_offset); + ASSERT_IS_NULL(((struct aiocb*)captured_aiocbp)->aio_sigevent.sigev_notify_attributes); + + ///cleanup + call_callback(captured_aiocbp); + file_destroy(file_handle); +} + +/*Tests_SRS_FILE_43_036: [ If the call to read the file fails, file_read_async shall fail and return FILE_READ_ASYNC_READ_ERROR. ]*/ +/*Tests_SRS_FILE_LINUX_43_045: [ file_read_async shall allocate a struct to hold handle, destination, user_callback and user_context. ]*/ +/*Tests_SRS_FILE_LINUX_43_009: [ file_read_async shall allocate an aiocb struct with the file descriptor from file_handle as aio_fildes, position as aio_offset, the allocated buffer as aio_buf, size as aio_nbytes. ]*/ +/*Tests_SRS_FILE_LINUX_43_008: [ file_read_async shall initialize the sigevent struct on the allocated aiocb struct with SIGEV_THREAD as sigev_notify, user_context as sigev_value, on_file_read_complete_linux as sigev_notify_function, NULL as sigev_notify_attributes. ]*/ +/*Tests_SRS_FILE_LINUX_43_010: [ file_read_async shall call aio_read with the allocated aiocb struct as aiocbp. ]*/ +/*Tests_SRS_FILE_LINUX_43_011: [ If aio_read fails, file_read_async shall return FILE_READ_ASYNC_READ_ERROR. ]*/ +TEST_FUNCTION(file_read_async_fails_synchronously) +{ + ///arrange + FILE_HANDLE file_handle = get_file_handle("file_read_async_fails_synchronously.txt"); + unsigned char source[10]; + uint32_t size = 10; + uint64_t position = 5; + + void* io_context; + void* captured_aiocbp; + + STRICT_EXPECTED_CALL(malloc(IGNORED_ARG)) + .CaptureReturn(&io_context); + STRICT_EXPECTED_CALL(malloc(sizeof(struct aiocb))) + .CaptureReturn(&captured_aiocbp); + STRICT_EXPECTED_CALL(mock_aio_read(IGNORED_ARG)) + .SetReturn(-1); + STRICT_EXPECTED_CALL(free(IGNORED_ARG)) + .ValidateArgumentValue_ptr(&captured_aiocbp); + STRICT_EXPECTED_CALL(free(IGNORED_ARG)) + .ValidateArgumentValue_ptr(&io_context); + ///act + FILE_READ_ASYNC_RESULT result = file_read_async(file_handle, source, size, position, mock_user_callback, NULL); + + ///assert + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); + ASSERT_ARE_EQUAL(FILE_READ_ASYNC_RESULT, FILE_READ_ASYNC_READ_ERROR, result); + + ///cleanup + file_destroy(file_handle); +} + +/*Tests_SRS_FILE_43_022: [ If there are any failures then file_read_async shall fail and return FILE_READ_ASYNC_ERROR. ]*/ +/*Tests_SRS_FILE_LINUX_43_015: [ If there are any other failures, file_read_async shall return FILE_READ_ASYNC_ERROR. ]*/ +TEST_FUNCTION(file_read_async_fails) +{ + ///arrange + FILE_HANDLE file_handle = get_file_handle("file_read_async_fails.txt"); + unsigned char source[10]; + uint32_t size = 10; + uint64_t position = 5; + void* io; + + STRICT_EXPECTED_CALL(malloc(IGNORED_ARG)); + STRICT_EXPECTED_CALL(malloc(sizeof(struct aiocb))); + STRICT_EXPECTED_CALL(mock_aio_read(IGNORED_ARG)) + .CallCannotFail(); + + umock_c_negative_tests_snapshot(); + for (size_t i = 0; i < umock_c_negative_tests_call_count(); ++i) + { + if (umock_c_negative_tests_can_call_fail(i)) + { + umock_c_negative_tests_reset(); + umock_c_negative_tests_fail_call(i); + + ///act + FILE_READ_ASYNC_RESULT result = file_read_async(file_handle, source, size, position, mock_user_callback, NULL); + + ///assert + ASSERT_ARE_EQUAL(FILE_READ_ASYNC_RESULT, FILE_READ_ASYNC_ERROR, result); + } + } + ///cleanup + file_destroy(file_handle); +} + +/*Tests_SRS_FILE_LINUX_43_018: [ file_extend shall return 0. ]*/ +TEST_FUNCTION(file_extend_returns_zero) +{ + ///arrange + FILE_HANDLE file_handle = get_file_handle("file_extend_returns_zero.txt"); + ///act + int return_val = file_extend(file_handle, 0); + + ///assert + ASSERT_ARE_EQUAL(int, 0, return_val); + + ///cleanup + file_destroy(file_handle); +} + +/*Tests_SRS_FILE_LINUX_43_058: [ on_file_write_complete_linux shall decrement the pending asynchronous operations counter on the FILE_HANDLE contained in write_info. ]*/ +/*Tests_SRS_FILE_LINUX_43_066: [ on_file_write_complete_linux shall wake all threads waiting on the address of the pending asynchronous operations counter. ]*/ +/*Tests_SRS_FILE_LINUX_43_022: [ on_file_write_complete_linux shall call aio_return to determine if the asynchronous write operation succeeded. ]*/ +/*Tests_SRS_FILE_LINUX_43_062: [ on_file_write_complete_linux shall free the aiocb struct associated with the current asynchronous write operation. ]*/ +/*Tests_SRS_FILE_LINUX_43_063: [ on_file_write_complete_linux shall free write_info. ]*/ +/*Tests_SRS_FILE_LINUX_43_027: [ If the asynchronous write operation succeeded, on_file_write_complete_linux shall call user_callback with user_context and true as is_successful. ]*/ +/*Tests_SRS_FILE_LINUX_43_027: [ If the asynchronous write operation succeeded, on_file_write_complete_linux shall call user_callback with user_context and true as is_successful. ]*/ +TEST_FUNCTION(on_file_write_complete_linux_calls_callback_successfully) +{ + ///arrange + unsigned char source[10]; + uint64_t position = 11; + void* user_context = (void*)20; + + void* captured_aiocbp; + void (*captured_callback)(__sigval_t); + __sigval_t captured_write_context; + + FILE_HANDLE file_handle = start_file_write_async(source, sizeof(source), position, mock_user_callback, user_context, &captured_aiocbp, &captured_callback, &captured_write_context); + + + STRICT_EXPECTED_CALL(interlocked_decrement(IGNORED_ARG)); + STRICT_EXPECTED_CALL(wake_by_address_all(IGNORED_ARG)); + STRICT_EXPECTED_CALL(mock_aio_return(IGNORED_ARG)) + .ValidateArgumentValue_aiocbp(&captured_aiocbp) + .SetReturn(sizeof(source)); + STRICT_EXPECTED_CALL(free(IGNORED_ARG)) + .ValidateArgumentValue_ptr(&captured_aiocbp); + STRICT_EXPECTED_CALL(free(IGNORED_ARG)) + .ValidateArgumentValue_ptr(&captured_write_context.sival_ptr); + STRICT_EXPECTED_CALL(mock_user_callback(user_context, true)); + ASSERT_ARE_EQUAL(uint64_t, position, ((struct aiocb*)captured_aiocbp)->aio_offset); + + ///act + captured_callback(captured_write_context); + + ///assert + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); + + ///cleanup + file_destroy(file_handle); +} + + +/*Tests_SRS_FILE_LINUX_43_058: [ on_file_write_complete_linux shall decrement the pending asynchronous operations counter on the FILE_HANDLE contained in write_info. ]*/ +/*Tests_SRS_FILE_LINUX_43_066: [ on_file_write_complete_linux shall wake all threads waiting on the address of the pending asynchronous operations counter. ]*/ +/*Tests_SRS_FILE_LINUX_43_022: [ on_file_write_complete_linux shall call aio_return to determine if the asynchronous write operation succeeded. ]*/ +/*Tests_SRS_FILE_LINUX_43_062: [ on_file_write_complete_linux shall free the aiocb struct associated with the current asynchronous write operation. ]*/ +/*Tests_SRS_FILE_LINUX_43_063: [ on_file_write_complete_linux shall free write_info. ]*/ +/*Tests_SRS_FILE_LINUX_43_023: [ If the asynchronous write operation did not succeed, on_file_write_complete_linux shall call user_callback with user_context and false as is_successful. ]*/ +TEST_FUNCTION(on_file_write_complete_linux_calls_callback_unsuccessfully_because_io_failed) +{ + ///arrange + unsigned char source[10]; + uint64_t position = 11; + void* user_context = (void*)20; + + void* captured_aiocbp; + void (*captured_callback)(__sigval_t); + __sigval_t captured_write_context; + + FILE_HANDLE file_handle = start_file_write_async(source, sizeof(source), position, mock_user_callback, user_context, &captured_aiocbp, &captured_callback, &captured_write_context); + + STRICT_EXPECTED_CALL(interlocked_decrement(IGNORED_ARG)); + STRICT_EXPECTED_CALL(wake_by_address_all(IGNORED_ARG)); + STRICT_EXPECTED_CALL(mock_aio_return(IGNORED_ARG)) + .ValidateArgumentValue_aiocbp(&captured_aiocbp) + .SetReturn(-1); + STRICT_EXPECTED_CALL(free(IGNORED_ARG)) + .ValidateArgumentValue_ptr(&captured_aiocbp); + STRICT_EXPECTED_CALL(free(IGNORED_ARG)) + .ValidateArgumentValue_ptr(&captured_write_context.sival_ptr); + STRICT_EXPECTED_CALL(mock_user_callback(user_context, false)); + ASSERT_ARE_EQUAL(uint64_t, position, ((struct aiocb*)captured_aiocbp)->aio_offset); + + ///act + captured_callback(captured_write_context); + + ///assert + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); + + ///cleanup + file_destroy(file_handle); +} + +/*Tests_SRS_FILE_LINUX_43_058: [ on_file_write_complete_linux shall decrement the pending asynchronous operations counter on the FILE_HANDLE contained in write_info. ]*/ +/*Tests_SRS_FILE_LINUX_43_066: [ on_file_write_complete_linux shall wake all threads waiting on the address of the pending asynchronous operations counter. ]*/ +/*Tests_SRS_FILE_LINUX_43_022: [ on_file_write_complete_linux shall call aio_return to determine if the asynchronous write operation succeeded. ]*/ +/*Tests_SRS_FILE_LINUX_43_062: [ on_file_write_complete_linux shall free the aiocb struct associated with the current asynchronous write operation. ]*/ +/*Tests_SRS_FILE_LINUX_43_063: [ on_file_write_complete_linux shall free write_info. ]*/ +/*Tests_SRS_FILE_LINUX_43_064: [ If the number of bytes written are less than the bytes requested by the user, on_file_write_complete_linux shall call user_callback with user_context and false as is_successful. ]*/ +TEST_FUNCTION(on_file_write_complete_linux_calls_callback_unsuccessfully_because_num_bytes_is_less) +{ + ///arrange + unsigned char source[10]; + uint64_t position = 11; + void* user_context = (void*)20; + + void* captured_aiocbp; + void (*captured_callback)(__sigval_t); + __sigval_t captured_write_context; + + FILE_HANDLE file_handle = start_file_write_async(source, sizeof(source), position, mock_user_callback, user_context, &captured_aiocbp, &captured_callback, &captured_write_context); + + STRICT_EXPECTED_CALL(interlocked_decrement(IGNORED_ARG)); + STRICT_EXPECTED_CALL(wake_by_address_all(IGNORED_ARG)); + STRICT_EXPECTED_CALL(mock_aio_return(IGNORED_ARG)) + .ValidateArgumentValue_aiocbp(&captured_aiocbp) + .SetReturn(sizeof(source)-1); + STRICT_EXPECTED_CALL(free(IGNORED_ARG)) + .ValidateArgumentValue_ptr(&captured_aiocbp); + STRICT_EXPECTED_CALL(free(IGNORED_ARG)) + .ValidateArgumentValue_ptr(&captured_write_context.sival_ptr); + STRICT_EXPECTED_CALL(mock_user_callback(user_context, false)); + ASSERT_ARE_EQUAL(uint64_t, position, ((struct aiocb*)captured_aiocbp)->aio_offset); + + ///act + captured_callback(captured_write_context); + + ///assert + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); + + ///cleanup + file_destroy(file_handle); +} + +/*Tests_SRS_FILE_LINUX_43_059: [ on_file_read_complete_linux shall decrement the pending asynchronous operations counter on the FILE_HANDLE contained in read_info. ]*/ +/*Tests_SRS_FILE_LINUX_43_067: [ on_file_read_complete_linux shall wake all threads waiting on the address of the pending asynchronous operations counter. ]*/ +/*Tests_SRS_FILE_LINUX_43_040: [ on_file_read_complete_linux shall call aio_return to determine if the asynchronous read operation succeeded. ]*/ +/*Tests_SRS_FILE_LINUX_43_060: [ on_file_read_complete_linux shall free the aiocb struct associated with the current asynchronous read operation. ]*/ +/*Tests_SRS_FILE_LINUX_43_061: [ on_file_read_complete_linux shall free read_info. ]*/ +/*Tests_SRS_FILE_LINUX_43_042: [ If the asynchronous read operation succeeded, on_file_read_complete_linux shall call user_callback with user_context and false as is_successful. ]*/ +TEST_FUNCTION(on_file_read_complete_linux_calls_callback_successfully) +{ + ///arrange + unsigned char source[10]; + uint64_t position = 11; + void* user_context = (void*)20; + + void* captured_aiocbp; + void (*captured_callback)(__sigval_t); + __sigval_t captured_write_context; + + FILE_HANDLE file_handle = start_file_read_async(source, sizeof(source), position, mock_user_callback, user_context, &captured_aiocbp, &captured_callback, &captured_write_context); + + STRICT_EXPECTED_CALL(interlocked_decrement(IGNORED_ARG)); + STRICT_EXPECTED_CALL(wake_by_address_all(IGNORED_ARG)); + STRICT_EXPECTED_CALL(mock_aio_return(IGNORED_ARG)) + .ValidateArgumentValue_aiocbp(&captured_aiocbp) + .SetReturn(sizeof(source)); + STRICT_EXPECTED_CALL(free(IGNORED_ARG)) + .ValidateArgumentValue_ptr(&captured_aiocbp); + STRICT_EXPECTED_CALL(free(IGNORED_ARG)) + .ValidateArgumentValue_ptr(&captured_write_context.sival_ptr); + STRICT_EXPECTED_CALL(mock_user_callback(user_context, true)); + ASSERT_ARE_EQUAL(uint64_t, position, ((struct aiocb*)captured_aiocbp)->aio_offset); + + ///act + captured_callback(captured_write_context); + + ///assert + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); + + ///cleanup + file_destroy(file_handle); +} + +/*Tests_SRS_FILE_LINUX_43_059: [ on_file_read_complete_linux shall decrement the pending asynchronous operations counter on the FILE_HANDLE contained in read_info. ]*/ +/*Tests_SRS_FILE_LINUX_43_067: [ on_file_read_complete_linux shall wake all threads waiting on the address of the pending asynchronous operations counter. ]*/ +/*Tests_SRS_FILE_LINUX_43_040: [ on_file_read_complete_linux shall call aio_return to determine if the asynchronous read operation succeeded. ]*/ +/*Tests_SRS_FILE_LINUX_43_060: [ on_file_read_complete_linux shall free the aiocb struct associated with the current asynchronous read operation. ]*/ +/*Tests_SRS_FILE_LINUX_43_061: [ on_file_read_complete_linux shall free read_info. ]*/ +/*Tests_SRS_FILE_LINUX_43_041: [ If the asynchronous read operation did not succeed, on_file_read_complete_linux shall call user_callback with user_context and false as is_successful. ]*/ +TEST_FUNCTION(on_file_read_complete_linux_calls_callback_unsuccessfully_because_io_failed) +{ + ///arrange + unsigned char source[10]; + uint64_t position = 11; + void* user_context = (void*)20; + + void* captured_aiocbp; + void (*captured_callback)(__sigval_t); + __sigval_t captured_write_context; + + FILE_HANDLE file_handle = start_file_read_async(source, sizeof(source), position, mock_user_callback, user_context, &captured_aiocbp, &captured_callback, &captured_write_context); + + STRICT_EXPECTED_CALL(interlocked_decrement(IGNORED_ARG)); + STRICT_EXPECTED_CALL(wake_by_address_all(IGNORED_ARG)); + STRICT_EXPECTED_CALL(mock_aio_return(IGNORED_ARG)) + .ValidateArgumentValue_aiocbp(&captured_aiocbp) + .SetReturn(-1); + STRICT_EXPECTED_CALL(free(IGNORED_ARG)) + .ValidateArgumentValue_ptr(&captured_aiocbp); + STRICT_EXPECTED_CALL(free(IGNORED_ARG)) + .ValidateArgumentValue_ptr(&captured_write_context.sival_ptr); + STRICT_EXPECTED_CALL(mock_user_callback(user_context, false)); + ASSERT_ARE_EQUAL(uint64_t, position, ((struct aiocb*)captured_aiocbp)->aio_offset); + + ///act + captured_callback(captured_write_context); + + ///assert + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); + + ///cleanup + file_destroy(file_handle); +} + +/*Tests_SRS_FILE_LINUX_43_059: [ on_file_read_complete_linux shall decrement the pending asynchronous operations counter on the FILE_HANDLE contained in read_info. ]*/ +/*Tests_SRS_FILE_LINUX_43_067: [ on_file_read_complete_linux shall wake all threads waiting on the address of the pending asynchronous operations counter. ]*/ +/*Tests_SRS_FILE_LINUX_43_040: [ on_file_read_complete_linux shall call aio_return to determine if the asynchronous read operation succeeded. ]*/ +/*Tests_SRS_FILE_LINUX_43_060: [ on_file_read_complete_linux shall free the aiocb struct associated with the current asynchronous read operation. ]*/ +/*Tests_SRS_FILE_LINUX_43_061: [ on_file_read_complete_linux shall free read_info. ]*/ +/*Tests_SRS_FILE_LINUX_43_065: [ If the number of bytes read are less than the bytes requested by the user, on_file_read_complete_linux shall call user_callback with user_context and false as is_successful. ]*/ +TEST_FUNCTION(on_file_read_complete_linux_calls_callback_unsuccessfully_because_num_bytes_is_less) +{ + ///arrange + unsigned char source[10]; + uint64_t position = 11; + void* user_context = (void*)20; + + void* captured_aiocbp; + void (*captured_callback)(__sigval_t); + __sigval_t captured_write_context; + + FILE_HANDLE file_handle = start_file_read_async(source, sizeof(source), position, mock_user_callback, user_context, &captured_aiocbp, &captured_callback, &captured_write_context); + + STRICT_EXPECTED_CALL(interlocked_decrement(IGNORED_ARG)); + STRICT_EXPECTED_CALL(wake_by_address_all(IGNORED_ARG)); + STRICT_EXPECTED_CALL(mock_aio_return(IGNORED_ARG)) + .ValidateArgumentValue_aiocbp(&captured_aiocbp) + .SetReturn(sizeof(source)-1); + STRICT_EXPECTED_CALL(free(IGNORED_ARG)) + .ValidateArgumentValue_ptr(&captured_aiocbp); + STRICT_EXPECTED_CALL(free(IGNORED_ARG)) + .ValidateArgumentValue_ptr(&captured_write_context.sival_ptr); + STRICT_EXPECTED_CALL(mock_user_callback(user_context, false)); + ASSERT_ARE_EQUAL(uint64_t, position, ((struct aiocb*)captured_aiocbp)->aio_offset); + + ///act + captured_callback(captured_write_context); + + ///assert + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); + + ///cleanup + file_destroy(file_handle); +} + +END_TEST_SUITE(file_linux_unittests) diff --git a/linux/tests/file_linux_ut/main.c b/linux/tests/file_linux_ut/main.c new file mode 100644 index 00000000..b5520e5c --- /dev/null +++ b/linux/tests/file_linux_ut/main.c @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include +#include "testrunnerswitcher.h" + +int main(void) +{ + size_t failedTestCount = 0; + RUN_TEST_SUITE(file_linux_unittests, failedTestCount); + return (int)failedTestCount; +} diff --git a/linux/tests/file_linux_ut/mock_file.c b/linux/tests/file_linux_ut/mock_file.c new file mode 100644 index 00000000..21ccb040 --- /dev/null +++ b/linux/tests/file_linux_ut/mock_file.c @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +#include +#include +#include + +#include "mock_file.h" +#define open mock_open +#define close mock_close +#define aio_write mock_aio_write +#define aio_read mock_aio_read +#define aio_return mock_aio_return +#include "../../src/file_linux.c" diff --git a/linux/tests/file_linux_ut/mock_file.h b/linux/tests/file_linux_ut/mock_file.h new file mode 100644 index 00000000..5c27c062 --- /dev/null +++ b/linux/tests/file_linux_ut/mock_file.h @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include + +#include "umock_c/umock_c_prod.h" + +#ifdef __cplusplus +extern "C" { +#endif + +MOCKABLE_FUNCTION(, int, mock_open, const char*, pathname, int, flags, int, mode); +MOCKABLE_FUNCTION(, int, mock_close, int, fildes); +MOCKABLE_FUNCTION(, int, mock_aio_write, void*, aiocbp); +MOCKABLE_FUNCTION(, int, mock_aio_read, void*, aiocbp); +MOCKABLE_FUNCTION(, int, mock_aio_return, void*, aiocbp); +#ifdef __cplusplus +} +#endif + diff --git a/win32/src/file_win32.c b/win32/src/file_win32.c index f102dd71..9d0dcfe8 100644 --- a/win32/src/file_win32.c +++ b/win32/src/file_win32.c @@ -82,7 +82,6 @@ IMPLEMENT_MOCKABLE_FUNCTION(, FILE_HANDLE, file_create, EXECUTION_ENGINE_HANDLE, { FILE_HANDLE result; if ( - /*Codes_SRS_FILE_43_033: [ If execution_engine is NULL, file_create shall fail and return NULL. ]*/ /*Codes_SRS_FILE_WIN32_43_040: [ If execution_engine is NULL, file_create shall fail and return NULL. ]*/ (execution_engine == NULL) || /*Codes_SRS_FILE_43_002: [ If full_file_name is NULL then file_create shall fail and return NULL. ]*/ diff --git a/win32/tests/file_win32_ut/file_win32_ut.c b/win32/tests/file_win32_ut/file_win32_ut.c index 1381abec..52725b65 100644 --- a/win32/tests/file_win32_ut/file_win32_ut.c +++ b/win32/tests/file_win32_ut/file_win32_ut.c @@ -213,7 +213,6 @@ TEST_FUNCTION_CLEANUP(cleans) TEST_MUTEX_RELEASE(g_testByTest); } -/*Tests_SRS_FILE_43_033: [ If execution_engine is NULL, file_create shall fail and return NULL. ]*/ /*Tests_SRS_FILE_WIN32_43_040: [ If execution_engine is NULL, file_create shall fail and return NULL. ]*/ TEST_FUNCTION(file_create_fails_on_null_execution_engine) { From 8ece425c6a0ea62213ec61b5e2c25567b20aa066 Mon Sep 17 00:00:00 2001 From: parth21999 Date: Fri, 24 Jul 2020 14:00:29 -0400 Subject: [PATCH 02/12] changed sigval type --- linux/src/file_linux.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux/src/file_linux.c b/linux/src/file_linux.c index 163c2e1e..26afaa63 100644 --- a/linux/src/file_linux.c +++ b/linux/src/file_linux.c @@ -47,7 +47,7 @@ typedef struct FILE_LINUX_READ_TAG uint32_t size; }FILE_LINUX_READ; -static void on_file_write_complete_linux(__sigval_t sigval) +static void on_file_write_complete_linux(sigval_t sigval) { FILE_LINUX_WRITE* write_info = (FILE_LINUX_WRITE*)sigval.sival_ptr; uint32_t size = write_info->size; @@ -88,7 +88,7 @@ static void on_file_write_complete_linux(__sigval_t sigval) user_callback(user_context, succeeded); } -static void on_file_read_complete_linux(__sigval_t sigval) +static void on_file_read_complete_linux(sigval_t sigval) { FILE_LINUX_READ* read_info = (FILE_LINUX_READ*)sigval.sival_ptr; uint32_t size = read_info->size; From 658e016d58f8f2cae5225d88ea3c280e70c019a2 Mon Sep 17 00:00:00 2001 From: parth21999 Date: Fri, 24 Jul 2020 14:13:43 -0400 Subject: [PATCH 03/12] activating unit tests --- linux/src/file_linux.c | 2 +- linux/tests/file_linux_ut/file_linux_ut.c | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/linux/src/file_linux.c b/linux/src/file_linux.c index 26afaa63..2f5018e5 100644 --- a/linux/src/file_linux.c +++ b/linux/src/file_linux.c @@ -160,7 +160,7 @@ IMPLEMENT_MOCKABLE_FUNCTION(, FILE_HANDLE, file_create, EXECUTION_ENGINE_HANDLE, { /*Codes_SRS_FILE_43_003: [ If a file with name full_file_name does not exist, file_create shall create a file with that name.]*/ /*Codes_SRS_FILE_LINUX_43_001: [ file_create shall call open with full_file_name as pathname and flags O_CREAT, O_RDWR, O_DIRECT and O_LARGEFILE. ]*/ - result->h_file = open(full_file_name, O_CREAT | O_RDWR | __O_DIRECT | __O_LARGEFILE, 0777); + result->h_file = open(full_file_name, O_CREAT | O_RDWR | __O_DIRECT | __O_LARGEFILE, 0700); if ( result->h_file == -1) { /*Codes_SRS_FILE_43_034: [ If there are any failures, file_create shall fail and return NULL. ]*/ diff --git a/linux/tests/file_linux_ut/file_linux_ut.c b/linux/tests/file_linux_ut/file_linux_ut.c index a66ad224..04676a68 100644 --- a/linux/tests/file_linux_ut/file_linux_ut.c +++ b/linux/tests/file_linux_ut/file_linux_ut.c @@ -72,7 +72,7 @@ static EXECUTION_ENGINE_HANDLE fake_execution_engine = (EXECUTION_ENGINE_HANDLE) static void setup_file_create_expectations(const char* filename) { STRICT_EXPECTED_CALL(malloc(IGNORED_ARG)); - STRICT_EXPECTED_CALL(mock_open(filename, O_CREAT | O_RDWR | __O_DIRECT | __O_LARGEFILE)); + STRICT_EXPECTED_CALL(mock_open(filename, O_CREAT | O_RDWR | __O_DIRECT | __O_LARGEFILE, 0700)); STRICT_EXPECTED_CALL(interlocked_exchange(IGNORED_ARG, 0)) .CallCannotFail(); } @@ -288,8 +288,11 @@ TEST_FUNCTION(file_destroy_succeeds) ASSERT_IS_NOT_NULL(file_handle); umock_c_reset_all_calls(); - STRICT_EXPECTED_CALL(interlocked_add(IGNORED_ARG, 0)); + STRICT_EXPECTED_CALL(interlocked_add(IGNORED_ARG, 0)) + .SetReturn(1); STRICT_EXPECTED_CALL(wait_on_address(IGNORED_ARG, IGNORED_ARG, UINT32_MAX)); + STRICT_EXPECTED_CALL(interlocked_add(IGNORED_ARG, 0)) + .SetReturn(0); STRICT_EXPECTED_CALL(mock_close(fake_fildes)); STRICT_EXPECTED_CALL(free(file_handle)); From 367ac72cb0efd5046b0ebe4208f7ed6abbc2c6b3 Mon Sep 17 00:00:00 2001 From: parth21999 Date: Fri, 24 Jul 2020 15:12:14 -0400 Subject: [PATCH 04/12] changed __sigval_t to sigval_t in ut --- linux/tests/file_linux_ut/file_linux_ut.c | 28 +++++++++++------------ 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/linux/tests/file_linux_ut/file_linux_ut.c b/linux/tests/file_linux_ut/file_linux_ut.c index 04676a68..f6650043 100644 --- a/linux/tests/file_linux_ut/file_linux_ut.c +++ b/linux/tests/file_linux_ut/file_linux_ut.c @@ -90,7 +90,7 @@ static FILE_HANDLE get_file_handle(const char* filename) } -static FILE_HANDLE start_file_write_async(const unsigned char* buffer, uint32_t size, uint64_t position, FILE_CB user_callback, void* user_context, void** captured_aiocbp, void (**captured_callback)(__sigval_t), __sigval_t* captured_write_context) +static FILE_HANDLE start_file_write_async(const unsigned char* buffer, uint32_t size, uint64_t position, FILE_CB user_callback, void* user_context, void** captured_aiocbp, void (**captured_callback)(sigval_t), sigval_t* captured_write_context) { FILE_HANDLE file_handle = get_file_handle("test_file.txt"); @@ -112,7 +112,7 @@ static FILE_HANDLE start_file_write_async(const unsigned char* buffer, uint32_t return file_handle; } -static FILE_HANDLE start_file_read_async(unsigned char* buffer, uint32_t size, uint64_t position, FILE_CB user_callback, void* user_context, void** captured_aiocbp, void (**captured_callback)(__sigval_t), __sigval_t* captured_read_context) +static FILE_HANDLE start_file_read_async(unsigned char* buffer, uint32_t size, uint64_t position, FILE_CB user_callback, void* user_context, void** captured_aiocbp, void (**captured_callback)(sigval_t), sigval_t* captured_read_context) { FILE_HANDLE file_handle = get_file_handle("test_file.txt"); @@ -715,8 +715,8 @@ TEST_FUNCTION(on_file_write_complete_linux_calls_callback_successfully) void* user_context = (void*)20; void* captured_aiocbp; - void (*captured_callback)(__sigval_t); - __sigval_t captured_write_context; + void (*captured_callback)(sigval_t); + sigval_t captured_write_context; FILE_HANDLE file_handle = start_file_write_async(source, sizeof(source), position, mock_user_callback, user_context, &captured_aiocbp, &captured_callback, &captured_write_context); @@ -758,8 +758,8 @@ TEST_FUNCTION(on_file_write_complete_linux_calls_callback_unsuccessfully_because void* user_context = (void*)20; void* captured_aiocbp; - void (*captured_callback)(__sigval_t); - __sigval_t captured_write_context; + void (*captured_callback)(sigval_t); + sigval_t captured_write_context; FILE_HANDLE file_handle = start_file_write_async(source, sizeof(source), position, mock_user_callback, user_context, &captured_aiocbp, &captured_callback, &captured_write_context); @@ -799,8 +799,8 @@ TEST_FUNCTION(on_file_write_complete_linux_calls_callback_unsuccessfully_because void* user_context = (void*)20; void* captured_aiocbp; - void (*captured_callback)(__sigval_t); - __sigval_t captured_write_context; + void (*captured_callback)(sigval_t); + sigval_t captured_write_context; FILE_HANDLE file_handle = start_file_write_async(source, sizeof(source), position, mock_user_callback, user_context, &captured_aiocbp, &captured_callback, &captured_write_context); @@ -840,8 +840,8 @@ TEST_FUNCTION(on_file_read_complete_linux_calls_callback_successfully) void* user_context = (void*)20; void* captured_aiocbp; - void (*captured_callback)(__sigval_t); - __sigval_t captured_write_context; + void (*captured_callback)(sigval_t); + sigval_t captured_write_context; FILE_HANDLE file_handle = start_file_read_async(source, sizeof(source), position, mock_user_callback, user_context, &captured_aiocbp, &captured_callback, &captured_write_context); @@ -881,8 +881,8 @@ TEST_FUNCTION(on_file_read_complete_linux_calls_callback_unsuccessfully_because_ void* user_context = (void*)20; void* captured_aiocbp; - void (*captured_callback)(__sigval_t); - __sigval_t captured_write_context; + void (*captured_callback)(sigval_t); + sigval_t captured_write_context; FILE_HANDLE file_handle = start_file_read_async(source, sizeof(source), position, mock_user_callback, user_context, &captured_aiocbp, &captured_callback, &captured_write_context); @@ -922,8 +922,8 @@ TEST_FUNCTION(on_file_read_complete_linux_calls_callback_unsuccessfully_because_ void* user_context = (void*)20; void* captured_aiocbp; - void (*captured_callback)(__sigval_t); - __sigval_t captured_write_context; + void (*captured_callback)(sigval_t); + sigval_t captured_write_context; FILE_HANDLE file_handle = start_file_read_async(source, sizeof(source), position, mock_user_callback, user_context, &captured_aiocbp, &captured_callback, &captured_write_context); From 9da677280cdfbbe3e1ca9163c326a69af66fcfd5 Mon Sep 17 00:00:00 2001 From: parth21999 Date: Fri, 24 Jul 2020 18:12:45 -0400 Subject: [PATCH 05/12] setting callback_will_be_called in error path --- linux/src/file_linux.c | 1 + 1 file changed, 1 insertion(+) diff --git a/linux/src/file_linux.c b/linux/src/file_linux.c index 2f5018e5..df415f7c 100644 --- a/linux/src/file_linux.c +++ b/linux/src/file_linux.c @@ -263,6 +263,7 @@ IMPLEMENT_MOCKABLE_FUNCTION(, FILE_WRITE_ASYNC_RESULT, file_write_async, FILE_HA /*Codes_SRS_FILE_43_015: [ If there are any failures, file_write_async shall fail and return FILE_WRITE_ASYNC_ERROR. ]*/ /*Codes_SRS_FILE_LINUX_43_013: [ If there are any other failures, file_write_async shall return FILE_WRITE_ASYNC_ERROR. ]*/ LogError("Failure in malloc."); + callback_will_be_called = false; result = FILE_WRITE_ASYNC_ERROR; } else From ac4df489cd5190ec31909745bce7cb5fa3a7f644 Mon Sep 17 00:00:00 2001 From: Matt Durak Date: Fri, 31 Jul 2020 11:45:41 -0700 Subject: [PATCH 06/12] Making a small fix --- interfaces/tests/file_int/file_int.c | 1 + linux/src/file_linux.c | 9 +++---- linux/tests/file_linux_ut/file_linux_ut.c | 32 ++++++++++++----------- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/interfaces/tests/file_int/file_int.c b/interfaces/tests/file_int/file_int.c index cd3a03e6..43812e33 100644 --- a/interfaces/tests/file_int/file_int.c +++ b/interfaces/tests/file_int/file_int.c @@ -403,6 +403,7 @@ TEST_FUNCTION(perform_operations_open_write_close_open_read_close) // cleanup execution_engine_dec_ref(execution_engine); + (void)delete_file(filename); } /*Tests_SRS_FILE_43_039: [ If position + size exceeds the size of the file, user_callback shall be called with success as false. ]*/ diff --git a/linux/src/file_linux.c b/linux/src/file_linux.c index df415f7c..1711b364 100644 --- a/linux/src/file_linux.c +++ b/linux/src/file_linux.c @@ -13,13 +13,12 @@ #include #include - - #include "c_logging/xlogging.h" #include "c_pal/file.h" #include "c_pal/interlocked.h" #include "c_pal/sync.h" -#include "c_pal/gballoc.h" +#include "c_pal/gballoc_hl.h" +#include "c_pal/gballoc_hl_redirect.h" typedef struct FILE_HANDLE_DATA_TAG { @@ -240,7 +239,6 @@ IMPLEMENT_MOCKABLE_FUNCTION(, FILE_WRITE_ASYNC_RESULT, file_write_async, FILE_HA } else { - bool callback_will_be_called; /*Codes_SRS_FILE_LINUX_43_019: [ file_write_async shall allocate a struct to hold handle, source, size, user_callback and user_context. ]*/ FILE_LINUX_WRITE* io_context = malloc(sizeof(FILE_LINUX_WRITE)); if (io_context == NULL) @@ -251,6 +249,8 @@ IMPLEMENT_MOCKABLE_FUNCTION(, FILE_WRITE_ASYNC_RESULT, file_write_async, FILE_HA } else { + bool callback_will_be_called; + io_context->handle = handle; io_context->size = size; io_context->user_callback = user_callback; @@ -268,7 +268,6 @@ IMPLEMENT_MOCKABLE_FUNCTION(, FILE_WRITE_ASYNC_RESULT, file_write_async, FILE_HA } else { - (void)memset(io_context->aiocbp, 0, sizeof(struct aiocb)); io_context->aiocbp->aio_fildes = handle->h_file; io_context->aiocbp->aio_buf = (unsigned char*)source; diff --git a/linux/tests/file_linux_ut/file_linux_ut.c b/linux/tests/file_linux_ut/file_linux_ut.c index f6650043..8805dad0 100644 --- a/linux/tests/file_linux_ut/file_linux_ut.c +++ b/linux/tests/file_linux_ut/file_linux_ut.c @@ -35,7 +35,8 @@ void real_free(void* ptr) #define ENABLE_MOCKS -#include "azure_c_pal/gballoc.h" +#include "azure_c_pal/gballoc_hl.h" +#include "azure_c_pal/gballoc_hl_redirect.h" #include "azure_c_pal/interlocked.h" #include "azure_c_pal/sync.h" #include "mock_file.h" @@ -89,8 +90,9 @@ static FILE_HANDLE get_file_handle(const char* filename) return file_handle; } +typedef void (*AIO_CALLBACK_FUNC)(__sigval_t sv); -static FILE_HANDLE start_file_write_async(const unsigned char* buffer, uint32_t size, uint64_t position, FILE_CB user_callback, void* user_context, void** captured_aiocbp, void (**captured_callback)(sigval_t), sigval_t* captured_write_context) +static FILE_HANDLE start_file_write_async(const unsigned char* buffer, uint32_t size, uint64_t position, FILE_CB user_callback, void* user_context, void** captured_aiocbp, AIO_CALLBACK_FUNC* captured_callback, __sigval_t* captured_write_context) { FILE_HANDLE file_handle = get_file_handle("test_file.txt"); @@ -112,7 +114,7 @@ static FILE_HANDLE start_file_write_async(const unsigned char* buffer, uint32_t return file_handle; } -static FILE_HANDLE start_file_read_async(unsigned char* buffer, uint32_t size, uint64_t position, FILE_CB user_callback, void* user_context, void** captured_aiocbp, void (**captured_callback)(sigval_t), sigval_t* captured_read_context) +static FILE_HANDLE start_file_read_async(unsigned char* buffer, uint32_t size, uint64_t position, FILE_CB user_callback, void* user_context, void** captured_aiocbp, AIO_CALLBACK_FUNC* captured_callback, __sigval_t* captured_read_context) { FILE_HANDLE file_handle = get_file_handle("test_file.txt"); @@ -715,8 +717,8 @@ TEST_FUNCTION(on_file_write_complete_linux_calls_callback_successfully) void* user_context = (void*)20; void* captured_aiocbp; - void (*captured_callback)(sigval_t); - sigval_t captured_write_context; + AIO_CALLBACK_FUNC captured_callback; + __sigval_t captured_write_context; FILE_HANDLE file_handle = start_file_write_async(source, sizeof(source), position, mock_user_callback, user_context, &captured_aiocbp, &captured_callback, &captured_write_context); @@ -758,8 +760,8 @@ TEST_FUNCTION(on_file_write_complete_linux_calls_callback_unsuccessfully_because void* user_context = (void*)20; void* captured_aiocbp; - void (*captured_callback)(sigval_t); - sigval_t captured_write_context; + AIO_CALLBACK_FUNC captured_callback; + __sigval_t captured_write_context; FILE_HANDLE file_handle = start_file_write_async(source, sizeof(source), position, mock_user_callback, user_context, &captured_aiocbp, &captured_callback, &captured_write_context); @@ -799,8 +801,8 @@ TEST_FUNCTION(on_file_write_complete_linux_calls_callback_unsuccessfully_because void* user_context = (void*)20; void* captured_aiocbp; - void (*captured_callback)(sigval_t); - sigval_t captured_write_context; + AIO_CALLBACK_FUNC captured_callback; + __sigval_t captured_write_context; FILE_HANDLE file_handle = start_file_write_async(source, sizeof(source), position, mock_user_callback, user_context, &captured_aiocbp, &captured_callback, &captured_write_context); @@ -840,8 +842,8 @@ TEST_FUNCTION(on_file_read_complete_linux_calls_callback_successfully) void* user_context = (void*)20; void* captured_aiocbp; - void (*captured_callback)(sigval_t); - sigval_t captured_write_context; + AIO_CALLBACK_FUNC captured_callback; + __sigval_t captured_write_context; FILE_HANDLE file_handle = start_file_read_async(source, sizeof(source), position, mock_user_callback, user_context, &captured_aiocbp, &captured_callback, &captured_write_context); @@ -881,8 +883,8 @@ TEST_FUNCTION(on_file_read_complete_linux_calls_callback_unsuccessfully_because_ void* user_context = (void*)20; void* captured_aiocbp; - void (*captured_callback)(sigval_t); - sigval_t captured_write_context; + AIO_CALLBACK_FUNC captured_callback; + __sigval_t captured_write_context; FILE_HANDLE file_handle = start_file_read_async(source, sizeof(source), position, mock_user_callback, user_context, &captured_aiocbp, &captured_callback, &captured_write_context); @@ -922,8 +924,8 @@ TEST_FUNCTION(on_file_read_complete_linux_calls_callback_unsuccessfully_because_ void* user_context = (void*)20; void* captured_aiocbp; - void (*captured_callback)(sigval_t); - sigval_t captured_write_context; + AIO_CALLBACK_FUNC captured_callback; + __sigval_t captured_write_context; FILE_HANDLE file_handle = start_file_read_async(source, sizeof(source), position, mock_user_callback, user_context, &captured_aiocbp, &captured_callback, &captured_write_context); From 97255c8b88ea30b5e21999c9bffdd2e8bebae73d Mon Sep 17 00:00:00 2001 From: Matt Durak Date: Fri, 31 Jul 2020 11:55:01 -0700 Subject: [PATCH 07/12] Fixing build error on gate --- linux/tests/file_linux_ut/file_linux_ut.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/linux/tests/file_linux_ut/file_linux_ut.c b/linux/tests/file_linux_ut/file_linux_ut.c index 8805dad0..a616ce77 100644 --- a/linux/tests/file_linux_ut/file_linux_ut.c +++ b/linux/tests/file_linux_ut/file_linux_ut.c @@ -90,9 +90,9 @@ static FILE_HANDLE get_file_handle(const char* filename) return file_handle; } -typedef void (*AIO_CALLBACK_FUNC)(__sigval_t sv); +typedef void (*AIO_CALLBACK_FUNC)(sigval_t sv); -static FILE_HANDLE start_file_write_async(const unsigned char* buffer, uint32_t size, uint64_t position, FILE_CB user_callback, void* user_context, void** captured_aiocbp, AIO_CALLBACK_FUNC* captured_callback, __sigval_t* captured_write_context) +static FILE_HANDLE start_file_write_async(const unsigned char* buffer, uint32_t size, uint64_t position, FILE_CB user_callback, void* user_context, void** captured_aiocbp, AIO_CALLBACK_FUNC* captured_callback, sigval_t* captured_write_context) { FILE_HANDLE file_handle = get_file_handle("test_file.txt"); @@ -114,7 +114,7 @@ static FILE_HANDLE start_file_write_async(const unsigned char* buffer, uint32_t return file_handle; } -static FILE_HANDLE start_file_read_async(unsigned char* buffer, uint32_t size, uint64_t position, FILE_CB user_callback, void* user_context, void** captured_aiocbp, AIO_CALLBACK_FUNC* captured_callback, __sigval_t* captured_read_context) +static FILE_HANDLE start_file_read_async(unsigned char* buffer, uint32_t size, uint64_t position, FILE_CB user_callback, void* user_context, void** captured_aiocbp, AIO_CALLBACK_FUNC* captured_callback, sigval_t* captured_read_context) { FILE_HANDLE file_handle = get_file_handle("test_file.txt"); @@ -718,7 +718,7 @@ TEST_FUNCTION(on_file_write_complete_linux_calls_callback_successfully) void* captured_aiocbp; AIO_CALLBACK_FUNC captured_callback; - __sigval_t captured_write_context; + sigval_t captured_write_context; FILE_HANDLE file_handle = start_file_write_async(source, sizeof(source), position, mock_user_callback, user_context, &captured_aiocbp, &captured_callback, &captured_write_context); @@ -761,7 +761,7 @@ TEST_FUNCTION(on_file_write_complete_linux_calls_callback_unsuccessfully_because void* captured_aiocbp; AIO_CALLBACK_FUNC captured_callback; - __sigval_t captured_write_context; + sigval_t captured_write_context; FILE_HANDLE file_handle = start_file_write_async(source, sizeof(source), position, mock_user_callback, user_context, &captured_aiocbp, &captured_callback, &captured_write_context); @@ -802,7 +802,7 @@ TEST_FUNCTION(on_file_write_complete_linux_calls_callback_unsuccessfully_because void* captured_aiocbp; AIO_CALLBACK_FUNC captured_callback; - __sigval_t captured_write_context; + sigval_t captured_write_context; FILE_HANDLE file_handle = start_file_write_async(source, sizeof(source), position, mock_user_callback, user_context, &captured_aiocbp, &captured_callback, &captured_write_context); @@ -843,7 +843,7 @@ TEST_FUNCTION(on_file_read_complete_linux_calls_callback_successfully) void* captured_aiocbp; AIO_CALLBACK_FUNC captured_callback; - __sigval_t captured_write_context; + sigval_t captured_write_context; FILE_HANDLE file_handle = start_file_read_async(source, sizeof(source), position, mock_user_callback, user_context, &captured_aiocbp, &captured_callback, &captured_write_context); @@ -884,7 +884,7 @@ TEST_FUNCTION(on_file_read_complete_linux_calls_callback_unsuccessfully_because_ void* captured_aiocbp; AIO_CALLBACK_FUNC captured_callback; - __sigval_t captured_write_context; + sigval_t captured_write_context; FILE_HANDLE file_handle = start_file_read_async(source, sizeof(source), position, mock_user_callback, user_context, &captured_aiocbp, &captured_callback, &captured_write_context); @@ -925,7 +925,7 @@ TEST_FUNCTION(on_file_read_complete_linux_calls_callback_unsuccessfully_because_ void* captured_aiocbp; AIO_CALLBACK_FUNC captured_callback; - __sigval_t captured_write_context; + sigval_t captured_write_context; FILE_HANDLE file_handle = start_file_read_async(source, sizeof(source), position, mock_user_callback, user_context, &captured_aiocbp, &captured_callback, &captured_write_context); From a13aef60347154e6681f5aeb673e7881afd36683 Mon Sep 17 00:00:00 2001 From: Matt Durak Date: Fri, 31 Jul 2020 12:15:53 -0700 Subject: [PATCH 08/12] Use new cmake function --- linux/tests/file_linux_ut/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux/tests/file_linux_ut/CMakeLists.txt b/linux/tests/file_linux_ut/CMakeLists.txt index 4dc4d6df..57b66657 100644 --- a/linux/tests/file_linux_ut/CMakeLists.txt +++ b/linux/tests/file_linux_ut/CMakeLists.txt @@ -19,4 +19,4 @@ set(${theseTestsName}_h_files mock_file.h ) -build_c_tests(${theseTestsName} ON "tests/azure_c_pal/linux" ADDITIONAL_LIBS pal_interfaces) +build_test_artifacts(${theseTestsName} ON "tests/azure_c_pal/linux" ADDITIONAL_LIBS pal_interfaces) From 9da9aedbe11d4490f5d89b79a73bb7e2774efd32 Mon Sep 17 00:00:00 2001 From: Matt Durak Date: Fri, 7 Aug 2020 08:29:05 -0700 Subject: [PATCH 09/12] Some small test changes --- interfaces/tests/file_int/file_int.c | 47 ++++++++++++----------- linux/tests/file_linux_ut/file_linux_ut.c | 18 ++++----- 2 files changed, 33 insertions(+), 32 deletions(-) diff --git a/interfaces/tests/file_int/file_int.c b/interfaces/tests/file_int/file_int.c index 43812e33..9126ed3d 100644 --- a/interfaces/tests/file_int/file_int.c +++ b/interfaces/tests/file_int/file_int.c @@ -36,7 +36,7 @@ typedef struct WRITE_COMPLETE_CONTEXT_TAG int32_t pre_callback_value; volatile_atomic int32_t value; int32_t post_callback_value; - bool did_write_succeed; + volatile_atomic int32_t did_write_succeed; }WRITE_COMPLETE_CONTEXT; typedef struct READ_COMPLETE_CONTEXT_TAG @@ -44,14 +44,14 @@ typedef struct READ_COMPLETE_CONTEXT_TAG int32_t pre_callback_value; volatile_atomic int32_t value; int32_t post_callback_value; - bool did_read_succeed; + volatile_atomic int32_t did_read_succeed; }READ_COMPLETE_CONTEXT; static void write_callback(void* context, bool is_successful) { WRITE_COMPLETE_CONTEXT* write_context = (WRITE_COMPLETE_CONTEXT*)context; ASSERT_ARE_EQUAL(int32_t, write_context->pre_callback_value, interlocked_add(&write_context->value, 0)); - write_context->did_write_succeed = is_successful; + (void)interlocked_exchange(&write_context->did_write_succeed, is_successful ? 1 : 0); (void)interlocked_exchange(&write_context->value, write_context->post_callback_value); wake_by_address_single(&write_context->value); } @@ -60,7 +60,7 @@ static void read_callback(void* context, bool is_successful) { READ_COMPLETE_CONTEXT* read_context = (READ_COMPLETE_CONTEXT*)context; ASSERT_ARE_EQUAL(int32_t, read_context->pre_callback_value, interlocked_add(&read_context->value, 0)); - read_context->did_read_succeed = is_successful; + (void)interlocked_exchange(&read_context->did_read_succeed, is_successful ? 1 : 0); (void)interlocked_exchange(&read_context->value, read_context->post_callback_value); wake_by_address_single(&read_context->value); } @@ -180,7 +180,7 @@ TEST_FUNCTION(write_to_a_file_and_read_from_it) ///assert wait_on_address_helper(&write_context.value, write_context.pre_callback_value, UINT32_MAX); ASSERT_ARE_EQUAL(int32_t, write_context.post_callback_value, interlocked_or(&write_context.value, 0), "value should be post_callback_value"); - ASSERT_IS_TRUE(write_context.did_write_succeed); + ASSERT_ARE_EQUAL(int32_t, 1, interlocked_add(&write_context.did_write_succeed, 0)); ///act ASSERT_ARE_EQUAL(FILE_READ_ASYNC_RESULT, FILE_READ_ASYNC_OK, file_read_async(file_handle, destination, sizeof(destination), 0, read_callback, &read_context)); @@ -188,7 +188,7 @@ TEST_FUNCTION(write_to_a_file_and_read_from_it) ///assert wait_on_address_helper(&read_context.value, read_context.pre_callback_value, UINT32_MAX); ASSERT_ARE_EQUAL(int32_t, read_context.post_callback_value, interlocked_or(&read_context.value, 0), "value should be post_callback_value"); - ASSERT_IS_TRUE(read_context.did_read_succeed); + ASSERT_ARE_EQUAL(int32_t, 1, interlocked_add(&read_context.did_read_succeed, 0)); ASSERT_ARE_EQUAL(char_ptr, source, destination); //cleanup @@ -240,11 +240,11 @@ TEST_FUNCTION(write_twice_to_a_file_contiguously_and_read_from_it) ///assert wait_on_address_helper(&write_context1.value, write_context1.pre_callback_value, UINT32_MAX); ASSERT_ARE_EQUAL(int32_t, write_context1.post_callback_value, interlocked_or(&write_context1.value, 0), "value should be post_callback_value"); - ASSERT_IS_TRUE(write_context1.did_write_succeed); + ASSERT_ARE_EQUAL(int32_t, 1, interlocked_add(&write_context1.did_write_succeed, 0)); wait_on_address_helper(&write_context2.value, write_context2.pre_callback_value, UINT32_MAX); ASSERT_ARE_EQUAL(int32_t, write_context2.post_callback_value, interlocked_or(&write_context2.value, 0), "value should be post_callback_value"); - ASSERT_IS_TRUE(write_context2.did_write_succeed); + ASSERT_ARE_EQUAL(int32_t, 1, interlocked_add(&write_context2.did_write_succeed, 0)); ///act ASSERT_ARE_EQUAL(FILE_READ_ASYNC_RESULT, FILE_READ_ASYNC_OK, file_read_async(file_handle, destination, sizeof(destination), 0, read_callback, &read_context)); @@ -252,7 +252,7 @@ TEST_FUNCTION(write_twice_to_a_file_contiguously_and_read_from_it) ///assert wait_on_address_helper(&read_context.value, read_context.pre_callback_value, UINT32_MAX); ASSERT_ARE_EQUAL(int32_t, read_context.post_callback_value, interlocked_or(&read_context.value, 0), "value should be post_callback_value"); - ASSERT_IS_TRUE(read_context.did_read_succeed); + ASSERT_ARE_EQUAL(int32_t, 1, interlocked_add(&read_context.did_read_succeed, 0)); ASSERT_ARE_EQUAL(char_ptr, "abcdefgh", destination); //cleanup @@ -315,11 +315,11 @@ TEST_FUNCTION(write_twice_to_a_file_non_contiguously_and_read_from_it) ///assert wait_on_address_helper(&write_context1.value, write_context1.pre_callback_value, UINT32_MAX); ASSERT_ARE_EQUAL(int32_t, write_context1.post_callback_value, interlocked_or(&write_context1.value, 0), "value should be post_callback_value"); - ASSERT_IS_TRUE(write_context1.did_write_succeed); + ASSERT_ARE_EQUAL(int32_t, 1, interlocked_add(&write_context1.did_write_succeed, 0)); wait_on_address_helper(&write_context2.value, write_context2.pre_callback_value, UINT32_MAX); ASSERT_ARE_EQUAL(int32_t, write_context2.post_callback_value, interlocked_or(&write_context2.value, 0), "value should be post_callback_value"); - ASSERT_IS_TRUE(write_context2.did_write_succeed); + ASSERT_ARE_EQUAL(int32_t, 1, interlocked_add(&write_context2.did_write_succeed, 0)); ///act ASSERT_ARE_EQUAL(FILE_READ_ASYNC_RESULT, FILE_READ_ASYNC_OK, file_read_async(file_handle, destination1, sizeof(destination1), 0, read_callback, &read_context1)); @@ -328,11 +328,11 @@ TEST_FUNCTION(write_twice_to_a_file_non_contiguously_and_read_from_it) ///assert wait_on_address_helper(&read_context1.value, read_context1.pre_callback_value, UINT32_MAX); ASSERT_ARE_EQUAL(int32_t, read_context1.post_callback_value, interlocked_or(&read_context1.value, 0), "value should be post_callback_value"); - ASSERT_IS_TRUE(read_context1.did_read_succeed); + ASSERT_ARE_EQUAL(int32_t, 1, interlocked_add(&read_context1.did_read_succeed, 0)); wait_on_address_helper(&read_context2.value, read_context2.pre_callback_value, UINT32_MAX); ASSERT_ARE_EQUAL(int32_t, read_context2.post_callback_value, interlocked_or(&read_context2.value, 0), "value should be post_callback_value"); - ASSERT_IS_TRUE(read_context2.did_read_succeed); + ASSERT_ARE_EQUAL(int32_t, 1, interlocked_add(&read_context2.did_read_succeed, 0)); ASSERT_ARE_EQUAL(char_ptr, source1, destination1); ASSERT_ARE_EQUAL(char_ptr, source2, destination2); @@ -386,7 +386,7 @@ TEST_FUNCTION(perform_operations_open_write_close_open_read_close) ///assert ASSERT_ARE_EQUAL(int32_t, write_context.post_callback_value, interlocked_or(&write_context.value, 0), "value should be post_callback_value"); - ASSERT_IS_TRUE(write_context.did_write_succeed); + ASSERT_ARE_EQUAL(int32_t, 1, interlocked_add(&write_context.did_write_succeed, 0)); ///act FILE_HANDLE file_handle2 = file_create(execution_engine, filename, NULL, NULL); @@ -398,7 +398,7 @@ TEST_FUNCTION(perform_operations_open_write_close_open_read_close) ///assert wait_on_address_helper(&read_context.value, read_context.pre_callback_value, UINT32_MAX); ASSERT_ARE_EQUAL(int32_t, read_context.post_callback_value, interlocked_or(&read_context.value, 0), "value should be post_callback_value"); - ASSERT_IS_TRUE(read_context.did_read_succeed); + ASSERT_ARE_EQUAL(int32_t, 1, interlocked_add(&read_context.did_read_succeed, 0)); ASSERT_ARE_EQUAL(char_ptr, source, destination); // cleanup @@ -436,7 +436,7 @@ TEST_FUNCTION(read_across_eof_fails) wait_on_address_helper(&write_context.value, write_context.pre_callback_value, UINT32_MAX); ASSERT_ARE_EQUAL(int32_t, write_context.post_callback_value, interlocked_or(&write_context.value, 0), "value should be post_callback_value"); - ASSERT_IS_TRUE(write_context.did_write_succeed); + ASSERT_ARE_EQUAL(int32_t, 1, interlocked_add(&write_context.did_write_succeed, 0)); ///act file_read_async(file_handle, destination, sizeof(destination), read_position, read_callback, &read_context); @@ -444,7 +444,7 @@ TEST_FUNCTION(read_across_eof_fails) ///assert wait_on_address_helper(&read_context.value, read_context.pre_callback_value, UINT32_MAX); ASSERT_ARE_EQUAL(int32_t, read_context.post_callback_value, interlocked_or(&read_context.value, 0), "value should be post_callback_value"); - ASSERT_IS_FALSE(read_context.did_read_succeed); + ASSERT_ARE_EQUAL(int32_t, 1, interlocked_add(&read_context.did_read_succeed, 0)); //cleanup file_destroy(file_handle); @@ -479,7 +479,7 @@ TEST_FUNCTION(read_beyond_eof_fails) wait_on_address_helper(&write_context.value, write_context.pre_callback_value, UINT32_MAX); ASSERT_ARE_EQUAL(int32_t, write_context.post_callback_value, interlocked_or(&write_context.value, 0), "value should be post_callback_value"); - ASSERT_IS_TRUE(write_context.did_write_succeed); + ASSERT_ARE_EQUAL(int32_t, 1, interlocked_add(&write_context.did_write_succeed, 0)); ///act file_read_async(file_handle, destination, sizeof(destination), read_position, read_callback, &read_context); @@ -487,7 +487,7 @@ TEST_FUNCTION(read_beyond_eof_fails) ///assert wait_on_address_helper(&read_context.value, read_context.pre_callback_value, UINT32_MAX); ASSERT_ARE_EQUAL(int32_t, read_context.post_callback_value, interlocked_or(&read_context.value, 0), "value should be post_callback_value"); - ASSERT_IS_FALSE(read_context.did_read_succeed); + ASSERT_ARE_EQUAL(int32_t, 1, interlocked_add(&read_context.did_read_succeed, 0)); //cleanup file_destroy(file_handle); @@ -534,7 +534,7 @@ TEST_FUNCTION(large_simultaneous_writes_succeed) { wait_on_address_helper(&contexts[i].value, contexts[i].pre_callback_value, UINT32_MAX); ASSERT_ARE_EQUAL(int32_t, contexts[i].post_callback_value, interlocked_or(&contexts[i].value, 0), "value should be post_callback_value"); - ASSERT_IS_TRUE(contexts[i].did_write_succeed); + ASSERT_ARE_EQUAL(int32_t, 1, interlocked_add(&contexts[i].did_write_succeed, 0)); } ///assert @@ -548,7 +548,7 @@ TEST_FUNCTION(large_simultaneous_writes_succeed) ASSERT_ARE_EQUAL(FILE_READ_ASYNC_RESULT, FILE_WRITE_ASYNC_OK, file_read_async(file_handle, destination, block_size * num_blocks, 0, read_callback, &read_context)); wait_on_address_helper(&read_context.value, read_context.pre_callback_value, UINT32_MAX); ASSERT_ARE_EQUAL(int32_t, read_context.post_callback_value, interlocked_or(&read_context.value, 0), "value should be post_callback_value"); - ASSERT_IS_TRUE(read_context.did_read_succeed); + ASSERT_ARE_EQUAL(int32_t, 1, interlocked_add(&read_context.did_read_succeed, 0)); for (int i = 0; i < num_blocks; ++i) { @@ -617,14 +617,14 @@ TEST_FUNCTION(large_simultaneous_reads_succeed) (void)interlocked_exchange(&contexts[i].value, contexts[i].pre_callback_value); contexts[i].post_callback_value = i; - ASSERT_ARE_EQUAL(FILE_READ_ASYNC_RESULT, FILE_WRITE_ASYNC_OK, file_read_async(file_handle, destinations[i], block_size, block_size * i, read_callback, &contexts[i])); + ASSERT_ARE_EQUAL(FILE_READ_ASYNC_RESULT, FILE_READ_ASYNC_OK, file_read_async(file_handle, destinations[i], block_size, block_size * i, read_callback, &contexts[i])); } for (int i = 0; i < num_blocks; ++i) { wait_on_address_helper(&contexts[i].value, contexts[i].pre_callback_value, UINT32_MAX); ASSERT_ARE_EQUAL(int32_t, contexts[i].post_callback_value, interlocked_or(&contexts[i].value, 0), "value should be post_callback_value"); - ASSERT_IS_TRUE(contexts[i].did_read_succeed); + ASSERT_ARE_EQUAL(int32_t, 1, interlocked_add(&contexts[i].did_read_succeed, 0)); } ///assert @@ -642,4 +642,5 @@ TEST_FUNCTION(large_simultaneous_reads_succeed) file_destroy(file_handle); (void)delete_file(filename); } + END_TEST_SUITE(file_int) diff --git a/linux/tests/file_linux_ut/file_linux_ut.c b/linux/tests/file_linux_ut/file_linux_ut.c index a616ce77..8805dad0 100644 --- a/linux/tests/file_linux_ut/file_linux_ut.c +++ b/linux/tests/file_linux_ut/file_linux_ut.c @@ -90,9 +90,9 @@ static FILE_HANDLE get_file_handle(const char* filename) return file_handle; } -typedef void (*AIO_CALLBACK_FUNC)(sigval_t sv); +typedef void (*AIO_CALLBACK_FUNC)(__sigval_t sv); -static FILE_HANDLE start_file_write_async(const unsigned char* buffer, uint32_t size, uint64_t position, FILE_CB user_callback, void* user_context, void** captured_aiocbp, AIO_CALLBACK_FUNC* captured_callback, sigval_t* captured_write_context) +static FILE_HANDLE start_file_write_async(const unsigned char* buffer, uint32_t size, uint64_t position, FILE_CB user_callback, void* user_context, void** captured_aiocbp, AIO_CALLBACK_FUNC* captured_callback, __sigval_t* captured_write_context) { FILE_HANDLE file_handle = get_file_handle("test_file.txt"); @@ -114,7 +114,7 @@ static FILE_HANDLE start_file_write_async(const unsigned char* buffer, uint32_t return file_handle; } -static FILE_HANDLE start_file_read_async(unsigned char* buffer, uint32_t size, uint64_t position, FILE_CB user_callback, void* user_context, void** captured_aiocbp, AIO_CALLBACK_FUNC* captured_callback, sigval_t* captured_read_context) +static FILE_HANDLE start_file_read_async(unsigned char* buffer, uint32_t size, uint64_t position, FILE_CB user_callback, void* user_context, void** captured_aiocbp, AIO_CALLBACK_FUNC* captured_callback, __sigval_t* captured_read_context) { FILE_HANDLE file_handle = get_file_handle("test_file.txt"); @@ -718,7 +718,7 @@ TEST_FUNCTION(on_file_write_complete_linux_calls_callback_successfully) void* captured_aiocbp; AIO_CALLBACK_FUNC captured_callback; - sigval_t captured_write_context; + __sigval_t captured_write_context; FILE_HANDLE file_handle = start_file_write_async(source, sizeof(source), position, mock_user_callback, user_context, &captured_aiocbp, &captured_callback, &captured_write_context); @@ -761,7 +761,7 @@ TEST_FUNCTION(on_file_write_complete_linux_calls_callback_unsuccessfully_because void* captured_aiocbp; AIO_CALLBACK_FUNC captured_callback; - sigval_t captured_write_context; + __sigval_t captured_write_context; FILE_HANDLE file_handle = start_file_write_async(source, sizeof(source), position, mock_user_callback, user_context, &captured_aiocbp, &captured_callback, &captured_write_context); @@ -802,7 +802,7 @@ TEST_FUNCTION(on_file_write_complete_linux_calls_callback_unsuccessfully_because void* captured_aiocbp; AIO_CALLBACK_FUNC captured_callback; - sigval_t captured_write_context; + __sigval_t captured_write_context; FILE_HANDLE file_handle = start_file_write_async(source, sizeof(source), position, mock_user_callback, user_context, &captured_aiocbp, &captured_callback, &captured_write_context); @@ -843,7 +843,7 @@ TEST_FUNCTION(on_file_read_complete_linux_calls_callback_successfully) void* captured_aiocbp; AIO_CALLBACK_FUNC captured_callback; - sigval_t captured_write_context; + __sigval_t captured_write_context; FILE_HANDLE file_handle = start_file_read_async(source, sizeof(source), position, mock_user_callback, user_context, &captured_aiocbp, &captured_callback, &captured_write_context); @@ -884,7 +884,7 @@ TEST_FUNCTION(on_file_read_complete_linux_calls_callback_unsuccessfully_because_ void* captured_aiocbp; AIO_CALLBACK_FUNC captured_callback; - sigval_t captured_write_context; + __sigval_t captured_write_context; FILE_HANDLE file_handle = start_file_read_async(source, sizeof(source), position, mock_user_callback, user_context, &captured_aiocbp, &captured_callback, &captured_write_context); @@ -925,7 +925,7 @@ TEST_FUNCTION(on_file_read_complete_linux_calls_callback_unsuccessfully_because_ void* captured_aiocbp; AIO_CALLBACK_FUNC captured_callback; - sigval_t captured_write_context; + __sigval_t captured_write_context; FILE_HANDLE file_handle = start_file_read_async(source, sizeof(source), position, mock_user_callback, user_context, &captured_aiocbp, &captured_callback, &captured_write_context); From 75ec896543107aaf3456e60c8ccc950a3645c0bb Mon Sep 17 00:00:00 2001 From: Matt Durak Date: Wed, 18 Nov 2020 15:28:27 -0800 Subject: [PATCH 10/12] Fixing some issues after rebase --- linux/src/execution_engine_linux.c | 4 ++- linux/tests/file_linux_ut/CMakeLists.txt | 4 +-- linux/tests/file_linux_ut/file_linux_ut.c | 38 +++++++++++------------ 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/linux/src/execution_engine_linux.c b/linux/src/execution_engine_linux.c index 632577b4..5c6be66c 100644 --- a/linux/src/execution_engine_linux.c +++ b/linux/src/execution_engine_linux.c @@ -1,4 +1,6 @@ -#include "azure_c_pal/execution_engine.h" +// Copyright (C) Microsoft Corporation. All rights reserved. + +#include "c_pal/execution_engine.h" EXECUTION_ENGINE_HANDLE execution_engine_create(void* execution_engine_parameters) { diff --git a/linux/tests/file_linux_ut/CMakeLists.txt b/linux/tests/file_linux_ut/CMakeLists.txt index 57b66657..f4bdc449 100644 --- a/linux/tests/file_linux_ut/CMakeLists.txt +++ b/linux/tests/file_linux_ut/CMakeLists.txt @@ -15,8 +15,8 @@ mock_file.c ) set(${theseTestsName}_h_files -../../../interfaces/inc/azure_c_pal/file.h +../../../interfaces/inc/c_pal/file.h mock_file.h ) -build_test_artifacts(${theseTestsName} ON "tests/azure_c_pal/linux" ADDITIONAL_LIBS pal_interfaces) +build_test_artifacts(${theseTestsName} ON "tests/c_pal/linux" ADDITIONAL_LIBS pal_interfaces) diff --git a/linux/tests/file_linux_ut/file_linux_ut.c b/linux/tests/file_linux_ut/file_linux_ut.c index 8805dad0..f73ca79e 100644 --- a/linux/tests/file_linux_ut/file_linux_ut.c +++ b/linux/tests/file_linux_ut/file_linux_ut.c @@ -35,17 +35,17 @@ void real_free(void* ptr) #define ENABLE_MOCKS -#include "azure_c_pal/gballoc_hl.h" -#include "azure_c_pal/gballoc_hl_redirect.h" -#include "azure_c_pal/interlocked.h" -#include "azure_c_pal/sync.h" +#include "c_pal/gballoc_hl.h" +#include "c_pal/gballoc_hl_redirect.h" +#include "c_pal/interlocked.h" +#include "c_pal/sync.h" #include "mock_file.h" MOCKABLE_FUNCTION(, void, mock_user_callback, void*, user_context, bool, is_successful); #undef ENABLE_MOCKS -#include "azure_c_pal/file.h" +#include "c_pal/file.h" static TEST_MUTEX_HANDLE g_testByTest; @@ -105,7 +105,7 @@ static FILE_HANDLE start_file_write_async(const unsigned char* buffer, uint32_t FILE_WRITE_ASYNC_RESULT result = file_write_async(file_handle, buffer, size, position, user_callback, user_context); - *captured_callback = ((struct aiocb*)(*captured_aiocbp))->aio_sigevent.sigev_notify_function; + *captured_callback = ((struct aiocb*)(*captured_aiocbp))->aio_sigevent.sigev_notify_function; *captured_write_context = ((struct aiocb*)(*captured_aiocbp))->aio_sigevent.sigev_value; ASSERT_ARE_EQUAL(FILE_WRITE_ASYNC_RESULT, FILE_WRITE_ASYNC_OK, result); @@ -127,7 +127,7 @@ static FILE_HANDLE start_file_read_async(unsigned char* buffer, uint32_t size, u FILE_READ_ASYNC_RESULT result = file_read_async(file_handle, buffer, size, position, user_callback, user_context); - *captured_callback = ((struct aiocb*)(*captured_aiocbp))->aio_sigevent.sigev_notify_function; + *captured_callback = ((struct aiocb*)(*captured_aiocbp))->aio_sigevent.sigev_notify_function; *captured_read_context = ((struct aiocb*)(*captured_aiocbp))->aio_sigevent.sigev_value; ASSERT_ARE_EQUAL(FILE_READ_ASYNC_RESULT, FILE_READ_ASYNC_OK, result); @@ -229,7 +229,7 @@ TEST_FUNCTION(file_create_succeeds) ///assert ASSERT_IS_NOT_NULL(file_handle); ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); - + ///cleanup file_destroy(file_handle); } @@ -240,7 +240,7 @@ TEST_FUNCTION(file_create_fails) { ///arrange const char filename[] = "file_create_succeeds.txt"; - + setup_file_create_expectations(filename); umock_c_negative_tests_snapshot(); @@ -408,7 +408,7 @@ TEST_FUNCTION(file_write_async_succeeds_asynchronously) unsigned char source[10]; uint32_t size = 10; uint64_t position = 5; - + void* captured_aiocbp; STRICT_EXPECTED_CALL(malloc(IGNORED_ARG)); @@ -465,7 +465,7 @@ TEST_FUNCTION(file_write_async_fails_synchronously) ///assert ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); ASSERT_ARE_EQUAL(FILE_WRITE_ASYNC_RESULT, FILE_WRITE_ASYNC_WRITE_ERROR, result); - + ///cleanup file_destroy(file_handle); } @@ -485,7 +485,7 @@ TEST_FUNCTION(file_write_async_fails) STRICT_EXPECTED_CALL(malloc(sizeof(struct aiocb))); STRICT_EXPECTED_CALL(mock_aio_write(IGNORED_ARG)) .CallCannotFail(); - + umock_c_negative_tests_snapshot(); for (size_t i = 0; i < umock_c_negative_tests_call_count(); ++i) { @@ -533,7 +533,7 @@ TEST_FUNCTION(file_read_async_fails_with_null_destination) ///assert ASSERT_ARE_EQUAL(FILE_READ_ASYNC_RESULT, FILE_READ_ASYNC_INVALID_ARGS, result); ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); - + ///cleanup file_destroy(file_handle); } @@ -552,7 +552,7 @@ TEST_FUNCTION(file_read_async_fails_with_null_user_callback) ///assert ASSERT_ARE_EQUAL(FILE_READ_ASYNC_RESULT, FILE_READ_ASYNC_INVALID_ARGS, result); ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); - + ///cleanup file_destroy(file_handle); } @@ -571,7 +571,7 @@ TEST_FUNCTION(file_read_async_fails_if_size_is_zero) ///assert ASSERT_ARE_EQUAL(FILE_READ_ASYNC_RESULT, FILE_READ_ASYNC_INVALID_ARGS, result); ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); - + ///cleanup file_destroy(file_handle); } @@ -589,7 +589,7 @@ TEST_FUNCTION(file_read_async_succeeds_asynchronously) unsigned char destination[10]; uint32_t size = 10; uint64_t position = 5; - + void* captured_aiocbp; STRICT_EXPECTED_CALL(malloc(IGNORED_ARG)); @@ -647,7 +647,7 @@ TEST_FUNCTION(file_read_async_fails_synchronously) ///assert ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); ASSERT_ARE_EQUAL(FILE_READ_ASYNC_RESULT, FILE_READ_ASYNC_READ_ERROR, result); - + ///cleanup file_destroy(file_handle); } @@ -667,7 +667,7 @@ TEST_FUNCTION(file_read_async_fails) STRICT_EXPECTED_CALL(malloc(sizeof(struct aiocb))); STRICT_EXPECTED_CALL(mock_aio_read(IGNORED_ARG)) .CallCannotFail(); - + umock_c_negative_tests_snapshot(); for (size_t i = 0; i < umock_c_negative_tests_call_count(); ++i) { @@ -722,7 +722,7 @@ TEST_FUNCTION(on_file_write_complete_linux_calls_callback_successfully) FILE_HANDLE file_handle = start_file_write_async(source, sizeof(source), position, mock_user_callback, user_context, &captured_aiocbp, &captured_callback, &captured_write_context); - + STRICT_EXPECTED_CALL(interlocked_decrement(IGNORED_ARG)); STRICT_EXPECTED_CALL(wake_by_address_all(IGNORED_ARG)); STRICT_EXPECTED_CALL(mock_aio_return(IGNORED_ARG)) From 8dd63bd1edc6ab56864bcc2e2099bfdda7c35165 Mon Sep 17 00:00:00 2001 From: Matt Durak Date: Wed, 18 Nov 2020 15:30:14 -0800 Subject: [PATCH 11/12] Fix file_int --- interfaces/tests/file_int/file_int.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/interfaces/tests/file_int/file_int.c b/interfaces/tests/file_int/file_int.c index 9126ed3d..3d1b938f 100644 --- a/interfaces/tests/file_int/file_int.c +++ b/interfaces/tests/file_int/file_int.c @@ -176,7 +176,7 @@ TEST_FUNCTION(write_to_a_file_and_read_from_it) ///act ASSERT_ARE_EQUAL(FILE_WRITE_ASYNC_RESULT, FILE_WRITE_ASYNC_OK, file_write_async(file_handle, source, size, 0, write_callback, &write_context)); - + ///assert wait_on_address_helper(&write_context.value, write_context.pre_callback_value, UINT32_MAX); ASSERT_ARE_EQUAL(int32_t, write_context.post_callback_value, interlocked_or(&write_context.value, 0), "value should be post_callback_value"); @@ -236,7 +236,7 @@ TEST_FUNCTION(write_twice_to_a_file_contiguously_and_read_from_it) ///act ASSERT_ARE_EQUAL(FILE_WRITE_ASYNC_RESULT, FILE_WRITE_ASYNC_OK, file_write_async(file_handle, source1, size, 0, write_callback, &write_context1)); ASSERT_ARE_EQUAL(FILE_WRITE_ASYNC_RESULT, FILE_WRITE_ASYNC_OK, file_write_async(file_handle, source2, size, 4, write_callback, &write_context2)); - + ///assert wait_on_address_helper(&write_context1.value, write_context1.pre_callback_value, UINT32_MAX); ASSERT_ARE_EQUAL(int32_t, write_context1.post_callback_value, interlocked_or(&write_context1.value, 0), "value should be post_callback_value"); @@ -311,7 +311,7 @@ TEST_FUNCTION(write_twice_to_a_file_non_contiguously_and_read_from_it) ///act ASSERT_ARE_EQUAL(FILE_WRITE_ASYNC_RESULT, FILE_WRITE_ASYNC_OK, file_write_async(file_handle, source1, size, 0, write_callback, &write_context1)); ASSERT_ARE_EQUAL(FILE_WRITE_ASYNC_RESULT, FILE_WRITE_ASYNC_OK, file_write_async(file_handle, source2, size, second_write_position, write_callback, &write_context2)); - + ///assert wait_on_address_helper(&write_context1.value, write_context1.pre_callback_value, UINT32_MAX); ASSERT_ARE_EQUAL(int32_t, write_context1.post_callback_value, interlocked_or(&write_context1.value, 0), "value should be post_callback_value"); @@ -383,7 +383,7 @@ TEST_FUNCTION(perform_operations_open_write_close_open_read_close) ASSERT_ARE_EQUAL(FILE_WRITE_ASYNC_RESULT, FILE_WRITE_ASYNC_OK, file_write_async(file_handle1, source, size, 0, write_callback, &write_context)); wait_on_address_helper(&write_context.value, write_context.pre_callback_value, UINT32_MAX); file_destroy(file_handle1); - + ///assert ASSERT_ARE_EQUAL(int32_t, write_context.post_callback_value, interlocked_or(&write_context.value, 0), "value should be post_callback_value"); ASSERT_ARE_EQUAL(int32_t, 1, interlocked_add(&write_context.did_write_succeed, 0)); @@ -444,7 +444,7 @@ TEST_FUNCTION(read_across_eof_fails) ///assert wait_on_address_helper(&read_context.value, read_context.pre_callback_value, UINT32_MAX); ASSERT_ARE_EQUAL(int32_t, read_context.post_callback_value, interlocked_or(&read_context.value, 0), "value should be post_callback_value"); - ASSERT_ARE_EQUAL(int32_t, 1, interlocked_add(&read_context.did_read_succeed, 0)); + ASSERT_ARE_EQUAL(int32_t, 0, interlocked_add(&read_context.did_read_succeed, 0)); //cleanup file_destroy(file_handle); @@ -475,7 +475,7 @@ TEST_FUNCTION(read_beyond_eof_fails) FILE_HANDLE file_handle = file_create_helper(filename); ASSERT_ARE_EQUAL(FILE_WRITE_ASYNC_RESULT, FILE_WRITE_ASYNC_OK, file_write_async(file_handle, source, size, 0, write_callback, &write_context)); - + wait_on_address_helper(&write_context.value, write_context.pre_callback_value, UINT32_MAX); ASSERT_ARE_EQUAL(int32_t, write_context.post_callback_value, interlocked_or(&write_context.value, 0), "value should be post_callback_value"); @@ -527,7 +527,7 @@ TEST_FUNCTION(large_simultaneous_writes_succeed) contexts[i].post_callback_value = i; ASSERT_ARE_EQUAL(FILE_WRITE_ASYNC_RESULT, FILE_WRITE_ASYNC_OK, file_write_async(file_handle, sources[i], block_size, block_size * i, write_callback, &contexts[i])); - + } for (int i = 0; i < num_blocks; ++i) @@ -564,7 +564,7 @@ TEST_FUNCTION(large_simultaneous_writes_succeed) } file_destroy(file_handle); (void)delete_file(filename); -} +} /*Tests_SRS_FILE_43_003: [If a file with name full_file_name does not exist, file_create shall create a file with that name.]*/ From 604075a159ca8b75e404c6365d561a70b466f033 Mon Sep 17 00:00:00 2001 From: Matt Durak Date: Wed, 18 Nov 2020 15:42:03 -0800 Subject: [PATCH 12/12] Fixing file_int test. Fixing Linux build --- interfaces/tests/file_int/file_int.c | 2 +- linux/src/execution_engine_linux.c | 13 ++++++++++++- linux/src/file_linux.c | 2 +- linux/tests/file_linux_ut/file_linux_ut.c | 2 +- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/interfaces/tests/file_int/file_int.c b/interfaces/tests/file_int/file_int.c index 3d1b938f..ba00593f 100644 --- a/interfaces/tests/file_int/file_int.c +++ b/interfaces/tests/file_int/file_int.c @@ -487,7 +487,7 @@ TEST_FUNCTION(read_beyond_eof_fails) ///assert wait_on_address_helper(&read_context.value, read_context.pre_callback_value, UINT32_MAX); ASSERT_ARE_EQUAL(int32_t, read_context.post_callback_value, interlocked_or(&read_context.value, 0), "value should be post_callback_value"); - ASSERT_ARE_EQUAL(int32_t, 1, interlocked_add(&read_context.did_read_succeed, 0)); + ASSERT_ARE_EQUAL(int32_t, 0, interlocked_add(&read_context.did_read_succeed, 0)); //cleanup file_destroy(file_handle); diff --git a/linux/src/execution_engine_linux.c b/linux/src/execution_engine_linux.c index 5c6be66c..f6b0a046 100644 --- a/linux/src/execution_engine_linux.c +++ b/linux/src/execution_engine_linux.c @@ -4,5 +4,16 @@ EXECUTION_ENGINE_HANDLE execution_engine_create(void* execution_engine_parameters) { - return (EXECUTION_ENGINE_HANDLE)0; + (void)execution_engine_parameters; + return NULL; +} + +void execution_engine_dec_ref(EXECUTION_ENGINE_HANDLE execution_engine) +{ + (void)execution_engine; +} + +void execution_engine_inc_ref(EXECUTION_ENGINE_HANDLE execution_engine) +{ + (void)execution_engine; } diff --git a/linux/src/file_linux.c b/linux/src/file_linux.c index 1711b364..eeaf3df6 100644 --- a/linux/src/file_linux.c +++ b/linux/src/file_linux.c @@ -198,7 +198,7 @@ IMPLEMENT_MOCKABLE_FUNCTION(, void, file_destroy, FILE_HANDLE, handle) int32_t pending = interlocked_add(&handle->pending_io, 0); while (pending != 0) { - wait_on_address(&handle->pending_io, &pending, UINT32_MAX); + (void)wait_on_address(&handle->pending_io, pending, UINT32_MAX); pending = interlocked_add(&handle->pending_io, 0); } /*Codes_SRS_FILE_LINUX_43_003: [ file_destroy shall call close.]*/ diff --git a/linux/tests/file_linux_ut/file_linux_ut.c b/linux/tests/file_linux_ut/file_linux_ut.c index f73ca79e..f1017199 100644 --- a/linux/tests/file_linux_ut/file_linux_ut.c +++ b/linux/tests/file_linux_ut/file_linux_ut.c @@ -14,7 +14,7 @@ #include #include -#include "azure_macro_utils/macro_utils.h" +#include "macro_utils/macro_utils.h" void* real_malloc(size_t size) {