#include "storage/store.h" #include "sys/system.h" #include #include #include static int failures; #define CHECK(value) \ do \ { \ if (!(value)) \ { \ fprintf(stderr, "CHECK failed at line %d: %s\n", __LINE__, #value); \ failures++; \ } \ } \ while (0) static char * duplicate_string(const char *value) { const size_t length = strlen(value); char *copy = malloc(length + 1); if (copy != NULL) { memcpy(copy, value, length + 1); } return copy; } int main(void) { char *temporary_root = tiny_sys_temp_directory_create("tcm"); char *directory; char *log_path; char *temporary_path; char *lock_path; char *snapshot_path; tiny_store_t *store = NULL, *second = NULL; tiny_message_t input, first, second_message; tiny_store_status_t status; tiny_sys_file_t log; tiny_rebuild_report_t report; unsigned char byte; uint32_t count; tiny_store_health_t health; size_t operation; static const tiny_sys_test_operation_t rebuild_failures[] = { TINY_SYS_TEST_OPEN, TINY_SYS_TEST_RANDOM, TINY_SYS_TEST_WRITE, TINY_SYS_TEST_FLUSH, TINY_SYS_TEST_REPLACE }; CHECK(tiny_store_open(NULL, "unused") == TINY_STORE_IO_ERROR); store = (tiny_store_t *)(uintptr_t)1; CHECK(tiny_store_open(&store, NULL) == TINY_STORE_IO_ERROR && store == NULL); CHECK(tiny_store_entry_count(NULL) == 0); CHECK(tiny_store_entry(NULL, 0) == NULL); memset(&health, 0xff, sizeof(health)); tiny_store_health(NULL, &health); CHECK(health.active_messages == 0 && health.log_size == 0); CHECK(temporary_root != NULL); if (temporary_root == NULL) { return 1; } directory = tiny_sys_path_join(temporary_root, "日本語-memory"); CHECK(directory != NULL && tiny_sys_directory_create(directory) == TINY_SYS_OK); if (directory == NULL) { free(temporary_root); return 1; } log_path = tiny_sys_path_join(directory, "active.log"); temporary_path = tiny_sys_path_join(directory, "active.tmp"); lock_path = tiny_sys_path_join(directory, "store.lock"); snapshot_path = tiny_sys_path_join(directory, "snapshot.bin"); CHECK(log_path != NULL && temporary_path != NULL && lock_path != NULL && snapshot_path != NULL); status = tiny_store_open(&store, directory); CHECK(status == TINY_STORE_OK); CHECK(tiny_store_open(&second, directory) == TINY_STORE_BUSY); tiny_message_init(&input); tiny_message_init(&first); tiny_message_init(&second_message); input.session_id = duplicate_string("unit"); input.content = duplicate_string("first"); input.role = TINY_ROLE_USER; CHECK(tiny_store_write(store, &input, &first) == TINY_STORE_OK); free(input.content); input.content = duplicate_string("second"); CHECK(tiny_store_write(store, &input, &second_message) == TINY_STORE_OK); CHECK(strcmp(first.message_id, second_message.message_id) < 0); tiny_message_free(&input); tiny_message_free(&first); tiny_message_free(&second_message); tiny_store_close(store); store = NULL; CHECK(tiny_store_open(&store, directory) == TINY_STORE_OK); CHECK(tiny_store_entry_count(store) == 2); for (operation = 0; operation < sizeof(rebuild_failures) / sizeof(rebuild_failures[0]); ++operation) { tiny_sys_test_reset(); CHECK(tiny_sys_test_fail_after(rebuild_failures[operation], 1)); CHECK(tiny_store_rebuild(store, &report) != TINY_STORE_OK); CHECK(tiny_store_entry_count(store) == 2); tiny_sys_test_reset(); (void)tiny_sys_file_remove(temporary_path); } CHECK(tiny_sys_directory_create(temporary_path) == TINY_SYS_OK); CHECK(tiny_store_rebuild(store, &report) == TINY_STORE_IO_ERROR); CHECK(tiny_store_entry_count(store) == 2); CHECK(tiny_sys_directory_remove(temporary_path)); tiny_store_close(store); store = NULL; CHECK(tiny_sys_file_open(&log, log_path, TINY_SYS_FILE_READ_WRITE) == TINY_SYS_OK); CHECK(tiny_sys_file_seek(&log, -1, TINY_SYS_SEEK_END)); CHECK(tiny_sys_file_read(&log, &byte, 1, &count) && count == 1); byte ^= 0x5a; CHECK(tiny_sys_file_seek(&log, -1, TINY_SYS_SEEK_CURRENT)); CHECK(tiny_sys_file_write(&log, &byte, 1, &count) && count == 1); tiny_sys_file_close(&log); CHECK(tiny_store_open(&store, directory) == TINY_STORE_CORRUPT); (void)tiny_sys_file_remove(log_path); (void)tiny_sys_file_remove(temporary_path); (void)tiny_sys_file_remove(lock_path); (void)tiny_sys_file_remove(snapshot_path); (void)tiny_sys_directory_remove(directory); (void)tiny_sys_directory_remove(temporary_root); free(snapshot_path); free(lock_path); free(temporary_path); free(log_path); free(directory); free(temporary_root); return failures == 0 ? 0 : 1; }