#include <gtest/gtest.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fcntl.h>
extern "C" {
#include "dss_api.h"
}
#define DSS_EVT_COUNT 11
static const char* g_dss_stat_event_names[DSS_EVT_COUNT] = {
"DSS Pread",
"DSS Pwrite",
"DSS Fread",
"DSS Fwrite",
"DSS Pread Sync Metadata",
"DSS Pwrite Sync Metadata",
"DSS Pread Disk",
"DSS Pwrite Disk",
"DSS File Open",
"DSS Stat",
"Find File Node On Server",
};
static const char *GetEnvOrNull(const char *name)
{
const char *val = std::getenv(name);
if (val == nullptr || std::strlen(val) == 0) {
return nullptr;
}
return val;
}
static bool BuildDssSvrPath(char *out, size_t out_size)
{
const char *svr_path_env = GetEnvOrNull("DSS_GTEST_SVR_PATH");
if (svr_path_env != nullptr) {
size_t len = std::strlen(svr_path_env);
if (len + 1 > out_size) {
std::printf("[DSSApiParamTest] DSS_GTEST_SVR_PATH too long, skip server connection test.\n");
return false;
}
std::memcpy(out, svr_path_env, len + 1);
return true;
}
const char *dss_home = GetEnvOrNull("DSS_HOME");
if (dss_home == nullptr) {
std::printf("[DSSApiParamTest] Neither DSS_GTEST_SVR_PATH nor DSS_HOME set, skip server connection test.\n");
return false;
}
int n = std::snprintf(out, out_size, "UDS:%s/.dss_unix_d_socket", dss_home);
if (n <= 0 || static_cast<size_t>(n) >= out_size) {
std::printf("[DSSApiParamTest] Failed to build UDS path from DSS_HOME, skip server connection test.\n");
return false;
}
return true;
}
static bool BuildTestFilePath(const char *suffix, char *out, size_t out_size)
{
const char *file_base = "+data/test";
int n = std::snprintf(out, out_size, "%s%s", file_base, suffix);
if (n <= 0 || static_cast<size_t>(n) >= out_size) {
std::printf("[DSSApiParamTest] Failed to build test file path from base=%s, suffix=%s.\n", file_base, suffix);
return false;
}
return true;
}
TEST(DSSApiParamTest, DreadNullItemOrResult) {
char svr_path[1024] = {0};
if (!BuildDssSvrPath(svr_path, sizeof(svr_path))) {
return;
}
if (dss_set_svr_path(svr_path) != DSS_SUCCESS) {
std::printf("[DSSApiParamTest] dss_set_svr_path failed (svr_path=%s), skip server connection test.\n", svr_path);
return;
}
dss_dirent_t item;
dss_dir_item_t result = nullptr;
dss_dir_handle fake_dir = (dss_dir_handle)0x1;
EXPECT_EQ(DSS_ERROR, dss_dread(fake_dir, nullptr, &result));
EXPECT_EQ(DSS_ERROR, dss_dread(fake_dir, &item, nullptr));
}
TEST(DSSApiParamTest, DreadNullDirValidParams) {
dss_dirent_t item;
dss_dir_item_t result = nullptr;
EXPECT_EQ(DSS_SUCCESS, dss_dread(nullptr, &item, &result));
EXPECT_EQ(nullptr, result);
}
TEST(DSSApiParamTest, StatNullItem) {
EXPECT_EQ(DSS_ERROR, dss_stat("/some/path", nullptr));
}
TEST(DSSApiParamTest, LstatNullItem) {
EXPECT_EQ(DSS_ERROR, dss_lstat("/some/path", nullptr));
}
TEST(DSSApiParamTest, FstatNullItem) {
EXPECT_EQ(DSS_ERROR, dss_fstat(123, nullptr));
}
TEST(DSSApiParamTest, ReadlinkInvalidBufsize) {
char buf[256];
EXPECT_EQ(DSS_ERROR, dss_readlink("/some/link", buf, 0));
EXPECT_EQ(DSS_ERROR, dss_readlink("/some/link", buf, -1));
}
TEST(DSSApiParamTest, PwriteNegativeSize) {
char buf[256] = {0};
EXPECT_EQ(DSS_ERROR, dss_pwrite(123, buf, -1, 0));
}
TEST(DSSApiParamTest, PreadNegativeSize) {
char buf[256];
int read_size = 0;
EXPECT_EQ(DSS_ERROR, dss_pread(123, buf, -1, 0, &read_size));
}
TEST(DSSApiParamTest, PreadNullReadSize) {
char buf[256];
EXPECT_EQ(DSS_ERROR, dss_pread(123, buf, 256, 0, nullptr));
}
TEST(DSSApiParamTest, IsMaintainNullPointer) {
EXPECT_EQ(DSS_ERROR, dss_is_maintain(nullptr));
}
TEST(DSSApiParamTest, CorrectReadWriteWithServer) {
char svr_path[1024] = {0};
if (!BuildDssSvrPath(svr_path, sizeof(svr_path))) {
return;
}
if (dss_set_svr_path(svr_path) != DSS_SUCCESS) {
std::printf("[DSSApiParamTest] dss_set_svr_path failed (svr_path=%s), skip read/write test.\n", svr_path);
return;
}
char file_path[1024] = {0};
if (!BuildTestFilePath("_param_rw", file_path, sizeof(file_path))) {
return;
}
(void)dss_fremove(file_path);
int ret = dss_fcreate(file_path, 0);
if (ret != DSS_SUCCESS) {
std::printf("[DSSApiParamTest] dss_fcreate failed (file_path=%s), skip read/write test.\n", file_path);
return;
}
int handle = -1;
ret = dss_fopen(file_path, O_RDWR, &handle);
if (ret != DSS_SUCCESS) {
std::printf("[DSSApiParamTest] dss_fopen failed (file_path=%s), skip read/write test.\n", file_path);
(void)dss_fremove(file_path);
return;
}
const char *write_data = "param rw test";
int write_size = static_cast<int>(std::strlen(write_data));
ret = dss_fwrite(handle, write_data, write_size);
ASSERT_EQ(DSS_SUCCESS, ret);
long long seek_ret = dss_fseek(handle, 0, SEEK_SET);
ASSERT_EQ(0, seek_ret);
ret = dss_fclose(handle);
ASSERT_EQ(DSS_SUCCESS, ret);
ret = dss_fremove(file_path);
ASSERT_EQ(DSS_SUCCESS, ret);
}
TEST(DSSApiParamTest, GetTimeStatValidParams) {
dss_time_stat_item_t time_stat[DSS_EVT_COUNT];
int ret = dss_get_time_stat(time_stat, DSS_EVT_COUNT);
if (ret == DSS_SUCCESS) {
printf("\n=== DSS Time Statistics ===\n");
printf("%-30s | %12s | %18s | %18s | %18s\n",
"Event Name", "Wait Count", "Total Wait Time(us)",
"Max Single Time(us)", "Avg Wait Time(us)");
printf("--------------------------------------------------------------------------------------------------------\n");
for (int i = 0; i < DSS_EVT_COUNT; i++) {
unsigned long long avg_time = 0;
if (time_stat[i].wait_count > 0) {
avg_time = time_stat[i].total_wait_time / time_stat[i].wait_count;
}
printf("%-30s | %12llu | %18llu | %18llu | %18llu\n",
g_dss_stat_event_names[i],
time_stat[i].wait_count,
time_stat[i].total_wait_time,
time_stat[i].max_single_time,
avg_time);
}
printf("========================================================================================================\n\n");
} else {
std::printf("[DSSApiParamTest] dss_get_time_stat failed (ret=%d), server may not be running.\n", ret);
}
SUCCEED();
}