Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

file linux implementation and unit tests #17

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
2 changes: 0 additions & 2 deletions interfaces/devdoc/file_requirements.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`. **]**
Expand Down
5 changes: 1 addition & 4 deletions interfaces/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
65 changes: 32 additions & 33 deletions interfaces/tests/file_int/file_int.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,22 @@ 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
{
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);
}
Expand All @@ -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);
}
Expand All @@ -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);

Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -178,19 +176,19 @@ 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");
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));

///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
Expand Down Expand Up @@ -238,23 +236,23 @@ 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");
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));

///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
Expand Down Expand Up @@ -313,15 +311,15 @@ 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");
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));
Expand All @@ -330,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);
Expand Down Expand Up @@ -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);
Expand All @@ -386,10 +383,10 @@ 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_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);
Expand All @@ -401,11 +398,12 @@ 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
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. ]*/
Expand Down Expand Up @@ -438,15 +436,15 @@ 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);

///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, 0, interlocked_add(&read_context.did_read_succeed, 0));

//cleanup
file_destroy(file_handle);
Expand Down Expand Up @@ -477,19 +475,19 @@ 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");
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);

///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, 0, interlocked_add(&read_context.did_read_succeed, 0));

//cleanup
file_destroy(file_handle);
Expand Down Expand Up @@ -529,14 +527,14 @@ 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)
{
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
Expand All @@ -550,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)
{
Expand All @@ -566,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.]*/
Expand Down Expand Up @@ -619,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
Expand All @@ -644,4 +642,5 @@ TEST_FUNCTION(large_simultaneous_reads_succeed)
file_destroy(file_handle);
(void)delete_file(filename);
}

END_TEST_SUITE(file_int)
28 changes: 26 additions & 2 deletions interfaces/tests/file_int/file_int_helpers_linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,36 @@

#ifdef __cplusplus
#include <cstdlib>
#include <cstdio>
#include <cstring>
#else
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#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;
}
1 change: 1 addition & 0 deletions linux/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
Loading