#include <gtest/gtest.h>
#include <fcntl.h>
#include <set>
#include <string>
#include <cstring>
extern "C" {
#include "gr_api.h"
#include "gr_errno.h"
}
#define TEST_LOG_DIR "./test_log"
#define TEST_DIR "testdir1"
#define TEST_FILE1 "TEST_FILE_1"
#define TEST_FILE2 "TEST_FILE_2"
#define TEST_FILE3 "TEST_FILE_3"
#define ONE_GB 1024 * 1024 * 1024
#define SERVER_ADDR "127.0.0.1:19225"
int errorcode = 0;
const char *errormsg = NULL;
gr_instance_handle g_inst_handle = NULL;
gr_vfs_handle g_vfs_handle;
int handle1 = 0, handle2 = 0, handle3 = 0;
gr_param_t g_gr_param;
gr_file_handle file_handle1;
gr_file_handle file_handle2;
gr_file_handle file_handle3;
typedef enum en_gr_file_status {
GR_FILE_INIT,
GR_FILE_LOCK,
GR_FILE_APPEND,
GR_FILE_EXPIRED
} gr_file_status_t;
class FailureListener : public ::testing::EmptyTestEventListener {
public:
void OnTestEnd(const ::testing::TestInfo& test_info) override {
if (test_info.result()->Failed()) {
std::cout << "Test " << test_info.test_case_name() << "." << test_info.name() << " failed." << std::endl;
gr_get_error(&errorcode, &errormsg);
printf("errorcode: %d, errormsg: %s\n", errorcode, errormsg);
}
}
};
class GRApiTest : public ::testing::Test {
protected:
void SetUp() override {
strcpy(g_gr_param.log_home, "./testlog");
g_gr_param.log_level = 255;
g_gr_param.log_backup_file_count = 100;
g_gr_param.log_max_file_size = ONE_GB;
int result = gr_init(g_gr_param);
ASSERT_EQ(result, GR_SUCCESS) << "Failed to initialize logger";
}
void TearDown() override {
gr_exit();
}
};
TEST_F(GRApiTest, TestGRCreateInstance) {
EXPECT_EQ(gr_create_inst(SERVER_ADDR, &g_inst_handle), GR_SUCCESS);
}
TEST_F(GRApiTest, TestGRSetGetConf) {
char buf[100];
EXPECT_EQ(gr_set_conf(g_inst_handle, "LOG_LEVEL", "7"), GR_SUCCESS);
EXPECT_EQ(gr_get_conf(g_inst_handle, "LOG_LEVEL", buf), GR_SUCCESS);
EXPECT_EQ(strcmp(buf, "7"), 0);
EXPECT_EQ(gr_set_conf(g_inst_handle, "LOG_LEVEL", "255"), GR_SUCCESS);
EXPECT_EQ(gr_get_conf(g_inst_handle, "LOG_LEVEL", buf), GR_SUCCESS);
EXPECT_EQ(strcmp(buf, "255"), 0);
}
TEST_F(GRApiTest, TestGRIpWhiteListDynamicUpdate) {
char buf[256] = {0};
EXPECT_EQ(gr_get_conf(g_inst_handle, "IP_WHITE_LIST", buf), GR_SUCCESS);
std::string original(buf);
std::string updated = original;
if (!updated.empty()) {
updated.append(",");
}
updated.append("10.0.0.1");
EXPECT_EQ(gr_set_conf(g_inst_handle, "IP_WHITE_LIST", updated.c_str()), GR_SUCCESS);
memset(buf, 0, sizeof(buf));
EXPECT_EQ(gr_get_conf(g_inst_handle, "IP_WHITE_LIST", buf), GR_SUCCESS);
EXPECT_STREQ(buf, updated.c_str());
}
TEST_F(GRApiTest, TestGRVfsCreate) {
EXPECT_EQ(gr_vfs_create(g_inst_handle, TEST_DIR, 0), GR_SUCCESS);
EXPECT_NE(gr_vfs_create(g_inst_handle, TEST_DIR, 0), GR_SUCCESS);
}
TEST_F(GRApiTest, TestGRVfsMount) {
EXPECT_EQ(gr_vfs_mount(g_inst_handle, TEST_DIR, &g_vfs_handle), GR_SUCCESS);
}
TEST_F(GRApiTest, TestGRVfsExist) {
bool is_exist = false;
EXPECT_EQ(gr_vfs_exist(g_inst_handle, TEST_DIR, &is_exist), GR_SUCCESS);
EXPECT_EQ(is_exist, true);
EXPECT_EQ(gr_vfs_exist(g_inst_handle, "NON_EXISTENT_VFS", &is_exist), GR_SUCCESS);
EXPECT_EQ(is_exist, false);
EXPECT_EQ(gr_vfs_exist(g_inst_handle, "ANOTHER_NON_EXISTENT_VFS_12345", &is_exist), GR_SUCCESS);
EXPECT_EQ(is_exist, false);
EXPECT_EQ(gr_vfs_exist(g_inst_handle, "", &is_exist), GR_ERROR);
EXPECT_EQ(gr_vfs_exist(g_inst_handle, NULL, &is_exist), GR_ERROR);
EXPECT_EQ(gr_vfs_exist(g_inst_handle, TEST_DIR, NULL), GR_ERROR);
EXPECT_EQ(gr_vfs_exist(NULL, TEST_DIR, &is_exist), GR_ERROR);
}
TEST_F(GRApiTest, TestGRVfsCreateFiles) {
char file_name[256];
bool is_exist = false;
for (int i = 1; i <= 200; i++) {
snprintf(file_name, sizeof(file_name), "TEST_FILE_%d", i);
EXPECT_EQ(gr_file_create(g_vfs_handle, file_name, NULL), GR_SUCCESS);
}
EXPECT_EQ(gr_file_exist(g_vfs_handle, "TEST_FILE_1", &is_exist), GR_SUCCESS);
EXPECT_EQ(is_exist, true);
EXPECT_NE(gr_file_create(g_vfs_handle, "TEST_FILE_1", NULL), GR_SUCCESS);
}
TEST_F(GRApiTest, TestGRFileExist) {
bool is_exist = false;
EXPECT_EQ(gr_file_exist(g_vfs_handle, "TEST_FILE_1", &is_exist), GR_SUCCESS);
EXPECT_EQ(is_exist, true);
EXPECT_EQ(gr_file_exist(g_vfs_handle, "TEST_FILE_100", &is_exist), GR_SUCCESS);
EXPECT_EQ(is_exist, true);
EXPECT_EQ(gr_file_exist(g_vfs_handle, "TEST_FILE_200", &is_exist), GR_SUCCESS);
EXPECT_EQ(is_exist, true);
EXPECT_EQ(gr_file_exist(g_vfs_handle, "NON_EXISTENT_FILE", &is_exist), GR_SUCCESS);
EXPECT_EQ(is_exist, false);
EXPECT_EQ(gr_file_exist(g_vfs_handle, "TEST_FILE_999", &is_exist), GR_SUCCESS);
EXPECT_EQ(is_exist, false);
EXPECT_EQ(gr_file_exist(g_vfs_handle, "", &is_exist), GR_ERROR);
EXPECT_EQ(gr_file_exist(g_vfs_handle, "FILE_WITH_SPECIAL_CHARS_!@#$%", &is_exist), GR_ERROR);
}
TEST_F(GRApiTest, TestGRfileOpen) {
EXPECT_EQ(gr_file_open(g_vfs_handle, TEST_FILE1, O_RDWR | O_SYNC, &file_handle1), GR_SUCCESS);
EXPECT_EQ(gr_file_open(g_vfs_handle, TEST_FILE2, O_RDWR | O_SYNC, &file_handle2), GR_SUCCESS);
EXPECT_EQ(gr_file_open(g_vfs_handle, TEST_FILE3, O_RDWR | O_SYNC, &file_handle3), GR_SUCCESS);
}
TEST_F(GRApiTest, TestGRfileWriteReadLargeData) {
const int large_data_size = 100 * 1024;
char *large_data = new char[large_data_size];
memset(large_data, 'A', large_data_size);
EXPECT_EQ(gr_file_pwrite(g_vfs_handle, &file_handle1, large_data, large_data_size, 0), large_data_size);
char *read_buffer = new char[large_data_size];
EXPECT_EQ(gr_file_pread(g_vfs_handle, file_handle1, read_buffer, large_data_size, 0), large_data_size);
EXPECT_EQ(memcmp(large_data, read_buffer, large_data_size), 0);
delete[] large_data;
delete[] read_buffer;
}
TEST_F(GRApiTest, TestGRfileWriteRead) {
const char *data1 = "hello world 1";
const char *data2 = "hello world 2";
const char *data3 = "hello world 3";
EXPECT_EQ(gr_file_pwrite(g_vfs_handle, &file_handle1, data1, strlen(data1), 0), strlen(data1));
EXPECT_EQ(gr_file_pwrite(g_vfs_handle, &file_handle2, data2, strlen(data2), 0), strlen(data2));
EXPECT_EQ(gr_file_pwrite(g_vfs_handle, &file_handle3, data3, strlen(data3), 0), strlen(data3));
char buf1[100] = {0}, buf2[100] = {0}, buf3[100] = {0};
EXPECT_EQ(gr_file_pread(g_vfs_handle, file_handle1, buf1, strlen(data1), 0), strlen(data1));
EXPECT_EQ(gr_file_pread(g_vfs_handle, file_handle2, buf2, strlen(data2), 0), strlen(data2));
EXPECT_EQ(gr_file_pread(g_vfs_handle, file_handle3, buf3, strlen(data3), 0), strlen(data3));
}
TEST_F(GRApiTest, TestGRfileStat) {
long long offset = 0;
unsigned long long size = 0;
int mode = 0;
char *time = NULL;
EXPECT_EQ(gr_file_stat(g_vfs_handle, TEST_FILE1, &offset, &size, &mode, &time), GR_SUCCESS);
#ifndef ENABLE_WORM
EXPECT_EQ(offset, 100 * 1024);
EXPECT_EQ(size, 100 * 1024);
#else
EXPECT_EQ(mode, GR_FILE_APPEND);
#endif
}
TEST_F(GRApiTest, TestLogicalEofMetaPersistence) {
const char *vfs_name = TEST_DIR;
const char *file_name = "META_PERSIST_FILE";
const int write_size = 100 * 1024 + 123;
gr_instance_handle inst1 = NULL;
gr_vfs_handle vfs1;
gr_file_handle fh1;
EXPECT_EQ(gr_create_inst(SERVER_ADDR, &inst1), GR_SUCCESS);
EXPECT_EQ(gr_vfs_mount(inst1, vfs_name, &vfs1), GR_SUCCESS);
(void)gr_file_delete(vfs1, file_name, 0);
EXPECT_EQ(gr_file_create(vfs1, file_name, NULL), GR_SUCCESS);
EXPECT_EQ(gr_file_open(vfs1, file_name, O_RDWR | O_SYNC, &fh1), GR_SUCCESS);
std::string data(write_size, 'X');
EXPECT_EQ(gr_file_pwrite(vfs1, &fh1, data.data(), write_size, 0), write_size);
EXPECT_EQ(gr_file_close(vfs1, &fh1, false), GR_SUCCESS);
EXPECT_EQ(gr_vfs_unmount(&vfs1), GR_SUCCESS);
EXPECT_EQ(gr_delete_inst(inst1), GR_SUCCESS);
gr_instance_handle inst2 = NULL;
gr_vfs_handle vfs2;
EXPECT_EQ(gr_create_inst(SERVER_ADDR, &inst2), GR_SUCCESS);
EXPECT_EQ(gr_vfs_mount(inst2, vfs_name, &vfs2), GR_SUCCESS);
long long logical_offset = 0;
unsigned long long logical_size = 0;
int mode = 0;
char *time_str = NULL;
EXPECT_EQ(gr_file_stat(vfs2, file_name, &logical_offset, &logical_size, &mode, &time_str), GR_SUCCESS);
EXPECT_EQ(logical_offset, (long long)write_size);
EXPECT_EQ(logical_size, (unsigned long long)write_size);
EXPECT_EQ(gr_file_delete(vfs2, file_name, 0), GR_SUCCESS);
EXPECT_EQ(gr_vfs_unmount(&vfs2), GR_SUCCESS);
EXPECT_EQ(gr_delete_inst(inst2), GR_SUCCESS);
}
TEST_F(GRApiTest, TestGRfilePostpone) {
const char *time1 = "2099-07-23 10:00:00";
const char *time2 = "2099-07-24 11:00:00";
const char *time3 = "2099-07-22 23:00:00";
EXPECT_EQ(gr_file_postpone(g_vfs_handle, TEST_FILE1, time1), GR_SUCCESS);
EXPECT_EQ(gr_file_postpone(g_vfs_handle, TEST_FILE2, time2), GR_SUCCESS);
EXPECT_EQ(gr_file_postpone(g_vfs_handle, TEST_FILE3, time3), GR_SUCCESS);
}
TEST_F(GRApiTest, TestGRfileClose) {
EXPECT_EQ(gr_file_close(g_vfs_handle, &file_handle1, false), GR_SUCCESS);
EXPECT_EQ(gr_file_close(g_vfs_handle, &file_handle2, false), GR_SUCCESS);
EXPECT_EQ(gr_file_close(g_vfs_handle, &file_handle3, false), GR_SUCCESS);
}
TEST_F(GRApiTest, TestGRVfsQueryFileNum) {
int file_num = 0;
EXPECT_EQ(gr_vfs_query_file_num(g_vfs_handle, &file_num), GR_SUCCESS);
EXPECT_GE(file_num, 200);
#define MAX_FILES_PER_QUERY 100
gr_file_item_t file_info[MAX_FILES_PER_QUERY];
std::set<std::string> file_names;
int test_file_count = 0;
bool is_continue = false;
int consecutive_empty = 0;
const int MAX_CONSECUTIVE_EMPTY = 2;
while (test_file_count < 200 && consecutive_empty < MAX_CONSECUTIVE_EMPTY) {
memset(file_info, 0, sizeof(file_info));
int ret = gr_vfs_query_file_info(g_vfs_handle, file_info, is_continue);
if (ret != GR_SUCCESS) {
break;
}
bool found_any = false;
for (int i = 0; i < MAX_FILES_PER_QUERY; i++) {
if (file_info[i].name[0] == '\0') {
break;
}
found_any = true;
if (strncmp(file_info[i].name, "TEST_FILE_", 10) != 0) {
continue;
}
if (file_names.find(file_info[i].name) != file_names.end()) {
continue;
}
file_names.insert(file_info[i].name);
test_file_count++;
int num = atoi(file_info[i].name + 10);
EXPECT_GE(num, 1);
EXPECT_LE(num, 200);
}
if (found_any) {
consecutive_empty = 0;
} else {
consecutive_empty++;
}
is_continue = true;
}
EXPECT_GE(test_file_count, 180) << "Expected at least 180 TEST_FILE_ files, found " << test_file_count;
EXPECT_EQ(file_names.size(), test_file_count);
}
#ifdef ENABLE_WORM
TEST_F(GRApiTest, TestGRVfsDeleteFiles) {
EXPECT_EQ(gr_file_delete(g_vfs_handle, TEST_FILE1, 0), GR_ERROR);
EXPECT_EQ(gr_file_delete(g_vfs_handle, TEST_FILE2, 0), GR_ERROR);
}
TEST_F(GRApiTest, TestGRVfsForceDelete) {
EXPECT_EQ(gr_vfs_delete(g_inst_handle, TEST_DIR, 1), GR_ERROR);
}
#else
TEST_F(GRApiTest, TestGRVfsDeleteFiles) {
EXPECT_EQ(gr_file_delete(g_vfs_handle, TEST_FILE1, 0), GR_SUCCESS);
EXPECT_EQ(gr_file_delete(g_vfs_handle, TEST_FILE2, 0), GR_SUCCESS);
}
TEST_F(GRApiTest, TestGRVfsForceDelete) {
EXPECT_EQ(gr_vfs_delete(g_inst_handle, TEST_DIR, 1), GR_SUCCESS);
}
#endif
TEST_F(GRApiTest, TestGRVfsUnmount) {
EXPECT_EQ(gr_vfs_unmount(&g_vfs_handle), GR_SUCCESS);
}
TEST_F(GRApiTest, TestInvalidParamsBasic) {
gr_instance_handle inst = NULL;
EXPECT_NE(gr_create_inst("invalid_addr", &inst), GR_SUCCESS);
EXPECT_NE(gr_vfs_create(g_inst_handle, NULL, 0), GR_SUCCESS);
gr_get_error(&errorcode, &errormsg);
EXPECT_EQ(errorcode, ERR_GR_INVALID_PARAM);
EXPECT_NE(errormsg, nullptr);
EXPECT_NE(gr_vfs_mount(g_inst_handle, NULL, &g_vfs_handle), GR_SUCCESS);
gr_get_error(&errorcode, &errormsg);
EXPECT_EQ(errorcode, ERR_GR_INVALID_PARAM);
EXPECT_NE(gr_vfs_mount(g_inst_handle, TEST_DIR, NULL), GR_SUCCESS);
gr_get_error(&errorcode, &errormsg);
EXPECT_EQ(errorcode, ERR_GR_INVALID_PARAM);
bool is_exist = false;
EXPECT_NE(gr_vfs_exist(NULL, TEST_DIR, &is_exist), GR_SUCCESS);
gr_get_error(&errorcode, &errormsg);
EXPECT_EQ(errorcode, ERR_GR_INVALID_PARAM);
EXPECT_NE(gr_vfs_exist(g_inst_handle, NULL, &is_exist), GR_SUCCESS);
gr_get_error(&errorcode, &errormsg);
EXPECT_EQ(errorcode, ERR_GR_INVALID_PARAM);
EXPECT_NE(gr_vfs_exist(g_inst_handle, TEST_DIR, NULL), GR_SUCCESS);
gr_get_error(&errorcode, &errormsg);
EXPECT_EQ(errorcode, ERR_GR_INVALID_PARAM);
EXPECT_NE(gr_vfs_unmount(NULL), GR_SUCCESS);
EXPECT_NE(gr_set_conf(g_inst_handle, NULL, "1"), GR_SUCCESS);
gr_get_error(&errorcode, &errormsg);
EXPECT_EQ(errorcode, ERR_GR_INVALID_PARAM);
EXPECT_NE(gr_set_conf(g_inst_handle, "LOG_LEVEL", NULL), GR_SUCCESS);
gr_get_error(&errorcode, &errormsg);
EXPECT_EQ(errorcode, ERR_GR_INVALID_PARAM);
EXPECT_NE(gr_get_conf(g_inst_handle, NULL, (char*)""), GR_SUCCESS);
gr_get_error(&errorcode, &errormsg);
EXPECT_EQ(errorcode, ERR_GR_INVALID_PARAM);
}
TEST_F(GRApiTest, TestFileApiInvalidParams) {
EXPECT_NE(gr_file_create(g_vfs_handle, NULL, NULL), GR_SUCCESS);
gr_get_error(&errorcode, &errormsg);
EXPECT_EQ(errorcode, ERR_GR_INVALID_PARAM);
EXPECT_NE(gr_file_delete(g_vfs_handle, NULL, 0), GR_SUCCESS);
gr_get_error(&errorcode, &errormsg);
EXPECT_EQ(errorcode, ERR_GR_INVALID_PARAM);
bool is_exist_bool = false;
EXPECT_NE(gr_file_exist(g_vfs_handle, NULL, &is_exist_bool), GR_SUCCESS);
gr_get_error(&errorcode, &errormsg);
EXPECT_EQ(errorcode, ERR_GR_INVALID_PARAM);
EXPECT_NE(gr_file_exist(g_vfs_handle, TEST_FILE1, NULL), GR_SUCCESS);
gr_get_error(&errorcode, &errormsg);
EXPECT_EQ(errorcode, ERR_GR_INVALID_PARAM);
EXPECT_NE(gr_file_open(g_vfs_handle, TEST_FILE1, -1, &file_handle1), GR_SUCCESS);
gr_get_error(&errorcode, &errormsg);
EXPECT_NE(gr_file_open(g_vfs_handle, TEST_FILE1, O_RDWR, NULL), GR_SUCCESS);
gr_get_error(&errorcode, &errormsg);
EXPECT_EQ(errorcode, ERR_GR_INVALID_PARAM);
long long wret = gr_file_pwrite(g_vfs_handle, &file_handle1, NULL, 16, 0);
EXPECT_LT(wret, 0);
gr_get_error(&errorcode, &errormsg);
EXPECT_EQ(errorcode, ERR_GR_INVALID_PARAM);
long long rret = gr_file_pread(g_vfs_handle, file_handle1, NULL, 16, 0);
EXPECT_LT(rret, 0);
gr_get_error(&errorcode, &errormsg);
EXPECT_EQ(errorcode, ERR_GR_INVALID_PARAM);
char buf[8] = {0};
EXPECT_LT(gr_file_pread(g_vfs_handle, file_handle1, buf, sizeof(buf), -1), 0);
gr_get_error(&errorcode, &errormsg);
long long off = 0; unsigned long long size = 0; int mode = 0; char *time = NULL;
EXPECT_NE(gr_file_stat(g_vfs_handle, NULL, &off, &size, &mode, &time), GR_SUCCESS);
gr_get_error(&errorcode, &errormsg);
EXPECT_EQ(errorcode, ERR_GR_INVALID_PARAM);
gr_vfs_unmount(&g_vfs_handle);
}
TEST_F(GRApiTest, TestRepeatAndOrderErrors) {
gr_file_handle tmp_handle;
EXPECT_NE(gr_file_close(g_vfs_handle, &tmp_handle, false), GR_SUCCESS);
gr_vfs_handle tmp_vfs = g_vfs_handle;
EXPECT_NE(gr_vfs_unmount(&tmp_vfs), GR_SUCCESS);
}
#define DIR_CLEANUP_DEMO_VFS "testdir_dir_cleanup_demo"
#define DIR_CLEANUP_DISCONNECT_ROUNDS 5
TEST_F(GRApiTest, TestGRDirMapCleanupOnDisconnect) {
gr_instance_handle inst = NULL;
gr_vfs_handle vfs;
memset(&vfs, 0, sizeof(vfs));
int create_ret = gr_vfs_create(g_inst_handle, DIR_CLEANUP_DEMO_VFS, 0);
if (create_ret != GR_SUCCESS) {
gr_vfs_delete(g_inst_handle, DIR_CLEANUP_DEMO_VFS, 0);
ASSERT_EQ(gr_vfs_create(g_inst_handle, DIR_CLEANUP_DEMO_VFS, 0), GR_SUCCESS);
}
for (int i = 0; i < DIR_CLEANUP_DISCONNECT_ROUNDS; i++) {
ASSERT_EQ(gr_create_inst(SERVER_ADDR, &inst), GR_SUCCESS);
ASSERT_EQ(gr_vfs_mount(inst, DIR_CLEANUP_DEMO_VFS, &vfs), GR_SUCCESS);
gr_delete_inst(inst);
inst = NULL;
}
ASSERT_EQ(gr_create_inst(SERVER_ADDR, &inst), GR_SUCCESS);
ASSERT_EQ(gr_vfs_mount(inst, DIR_CLEANUP_DEMO_VFS, &vfs), GR_SUCCESS);
int file_num = 0;
EXPECT_EQ(gr_vfs_query_file_num(vfs, &file_num), GR_SUCCESS);
EXPECT_GE(file_num, 0);
EXPECT_EQ(gr_vfs_unmount(&vfs), GR_SUCCESS);
gr_delete_inst(inst);
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
::testing::TestEventListeners& listeners = ::testing::UnitTest::GetInstance()->listeners();
listeners.Append(new FailureListener);
return RUN_ALL_TESTS();
}