/*

 * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.

 

 * K-NET is licensed under the Mulan PSL v2.

 * You can use this software according to the terms and conditions of the Mulan PSL v2.

 * You may obtain a copy of Mulan PSL v2 at:

      http://license.coscl.org.cn/MulanPSL2

 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR

 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.

 * See the Mulan PSL v2 for more details.

 */



#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <stdint.h>

#include <stdarg.h>

#include <inttypes.h>

#include <sys/queue.h>

#include <errno.h>

#include <signal.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <sys/un.h>

#include <sys/epoll.h>

#include <sys/stat.h>

#include <stdbool.h>

#include <netinet/in.h>

#include "knet_types.h"

#include "knet_log.h"

#include "knet_rpc.h"



#include "securec.h"

#include "common.h"

#include "mock.h"



#define READY_EVENTS_NUM (2)

#define MAGIC_NUM 0x12348765

#define RPC_EXCEPTION (-2)

static int g_epollWaitCount = 0;

static int g_serverFd = 0;

static int g_recvCount = 0;



extern "C" {

int RpcRecvVarLenData(int fd, struct RpcPkgInfo *pkgInfo, struct KNET_RpcMessage *request);

int RpcHandleRecvBytes(ssize_t bytesRead);

void RpcHandleDisconnect(int epollFd, struct epoll_event *event);

int RpcMsgSendRecv(int fd, enum KNET_RpcModType mod, struct KNET_RpcMessage* request,

                               struct KNET_RpcMessage* response);

}



DTEST_CASE_F(RPC, TEST_KNET_RPC_Client_NORMAL, NULL, NULL)

{

    KTestMock *Mock = CreateMock();

    DT_ASSERT_NOT_EQUAL(Mock, NULL);

    Mock->Create(socket, TEST_GetFuncRetNegative(1));



    int mode = 0;

    struct KNET_RpcMessage knetRpcRequest;

    knetRpcRequest.dataLen = 1;

    knetRpcRequest.dataType = RPC_MSG_DATA_TYPE_FIXED_LEN;

    struct KNET_RpcMessage knetRpcResponse;

    int ret = KNET_RpcCall(mode, &knetRpcRequest, &knetRpcResponse);

    DT_ASSERT_EQUAL(ret, -1);



    Mock->Create(socket, TEST_GetFuncRetPositive(0));

    Mock->Create(strncpy_s, TEST_GetFuncRetNegative(1));

    ret = KNET_RpcCall(mode, &knetRpcRequest, &knetRpcResponse);

    DT_ASSERT_EQUAL(ret, -1);

    Mock->Delete(strncpy_s);



    Mock->Create(strncpy_s, TEST_GetFuncRetPositive(0));

    Mock->Create(connect, TEST_GetFuncRetPositive(0));

    Mock->Create(send, TEST_GetFuncRetPositive(1));

    Mock->Create(recv, TEST_GetFuncRetPositive(0));

    Mock->Create(close, TEST_GetFuncRetPositive(0));

    ret = KNET_RpcCall(mode, &knetRpcRequest, &knetRpcResponse);

    DT_ASSERT_EQUAL(ret, -1);



    knetRpcRequest.dataType = RPC_MSG_DATA_TYPE_VARIABLE_LEN;

    knetRpcRequest.dataLen = 0;

    ret = KNET_RpcCall(mode, &knetRpcRequest, &knetRpcResponse);

    DT_ASSERT_EQUAL(ret, -1);



    Mock->Delete(socket);

    Mock->Delete(connect);

    Mock->Delete(send);

    Mock->Delete(recv);

    Mock->Delete(strncpy_s);

    Mock->Delete(close);

    DeleteMock(Mock);

    g_recvCount = 0;

}



int Handler(int id, struct KNET_RpcMessage *knetRpcRequest, struct KNET_RpcMessage *knetRpcResponse)

{

    return 0;

}



DTEST_CASE_F(RPC, TEST_KNET_RPC_REG_NORMAL, NULL, NULL)

{

    enum KNET_RpcEventType event = 0;

    enum KNET_RpcModType mode = 0;



    int ret = KNET_RpcRegServer(event, mode, NULL);

    DT_ASSERT_EQUAL(ret, -1);



    ret = KNET_RpcRegServer(event, mode, &Handler);

    DT_ASSERT_EQUAL(ret, 0);

}



DTEST_CASE_F(RPC, TEST_KNET_RPC_DES_NORMAL, NULL, NULL)

{

    enum KNET_RpcEventType event = 0;

    enum KNET_RpcModType mode = 0;



    KNET_RpcDesServer(-1, mode);

    KNET_RpcDesServer(event, mode);

}



struct RpcPkg {

    int mod;

    int ret;

    size_t dataLen;

    enum RpcMsgDataType dataType;

    char padding[4];

};



static int Function1(int sockfd, void *buf, size_t len, int flags)

{

    if (g_recvCount == 0 || g_recvCount == 1) {

        uint32_t num = MAGIC_NUM;

        int ret = memcpy_s(buf, sizeof(num), &num, sizeof(num));

        if (ret != 0) {

            return -1;

        }

        g_recvCount = g_recvCount + 1;

        return sizeof(num);

    } else {

        struct RpcPkg pkg = {0};

        pkg.mod = 0;

        pkg.dataLen = 1;

        pkg.dataType = RPC_MSG_DATA_TYPE_FIXED_LEN;

        int ret = memcpy_s(buf, sizeof(pkg), &pkg, sizeof(pkg));

        if (ret != 0) {

            return -1;

        }

        g_recvCount = g_recvCount + 1;

        return sizeof(pkg);

    }

}



static int Function2(int epfd, struct epoll_event *events, int maxevents, int timeout)

{

    if (g_epollWaitCount == 0) {

        events[0].data.fd = g_serverFd;

        events[1].data.fd = g_serverFd + 1;

        events[1].events = EPOLLIN;

        g_epollWaitCount = g_epollWaitCount + 1;

        return READY_EVENTS_NUM;

    } else if (g_epollWaitCount == 1) {

        errno = EINTR;

        g_epollWaitCount = g_epollWaitCount + 1;

        return -1;

    } else {

        errno = ENOMEM;

        g_epollWaitCount = g_epollWaitCount + 1;

        return -1;

    }

}



DTEST_CASE_F(RPC, TEST_KNET_RPC_RUN_NORMAL, NULL, NULL)

{

    KNET_RpcRegServer(1, 0, &Handler);

    KTestMock *Mock = CreateMock();

    DT_ASSERT_NOT_EQUAL(Mock, NULL);

    Mock->Create(socket, TEST_GetFuncRetNegative(1));

    int ret = KNET_RpcRun();

    DT_ASSERT_EQUAL(ret, -1);

    

    Mock->Create(socket, TEST_GetFuncRetPositive(0));

    Mock->Create(strncpy_s, TEST_GetFuncRetNegative(1));

    ret = KNET_RpcRun();

    DT_ASSERT_EQUAL(ret, -1);

    Mock->Delete(strncpy_s);



    Mock->Create(strncpy_s, TEST_GetFuncRetPositive(0));

    Mock->Create(unlink, TEST_GetFuncRetPositive(0));

    Mock->Create(bind, TEST_GetFuncRetPositive(0));

    Mock->Create(chmod, TEST_GetFuncRetPositive(0));

    Mock->Create(listen, TEST_GetFuncRetPositive(0));

    Mock->Create(epoll_create, TEST_GetFuncRetPositive(0));

    Mock->Create(epoll_ctl, TEST_GetFuncRetPositive(0));

    Mock->Create(epoll_wait, Function2);

    Mock->Create(accept, TEST_GetFuncRetPositive(0));

    Mock->Create(send, TEST_GetFuncRetPositive(1));

    Mock->Create(recv, Function1);

    Mock->Create(close, TEST_GetFuncRetPositive(0));

    ret = KNET_RpcRun();

    DT_ASSERT_EQUAL(ret, 0);



    Mock->Delete(socket);

    Mock->Delete(unlink);

    Mock->Delete(bind);

    Mock->Delete(chmod);

    Mock->Delete(listen);

    Mock->Delete(epoll_create);

    Mock->Delete(epoll_ctl);

    Mock->Delete(epoll_wait);

    Mock->Delete(send);

    Mock->Delete(recv);

    Mock->Delete(strncpy_s);

    Mock->Delete(close);

    Mock->Delete(accept);

    DeleteMock(Mock);

    g_recvCount = 0;

}



struct RpcPkgInfo {

    int mod;

    int ret;

    size_t dataLen;

    enum RpcMsgDataType dataType;

    char padding[4];

};



DTEST_CASE_F(RPC, TEST_KNET_RPC_RECV_NORMAL, NULL, NULL)

{

    KTestMock *Mock = CreateMock();

    DT_ASSERT_NOT_EQUAL(Mock, NULL);

    Mock->Create(recv, TEST_GetFuncRetPositive(1));



    struct KNET_RpcMessage request = { 0 };

    struct RpcPkgInfo pkgInfo = { 0 };

    pkgInfo.dataLen = -1;

    int ret = RpcRecvVarLenData(1, &pkgInfo, &request);

    DT_ASSERT_EQUAL(ret, RPC_EXCEPTION);



    pkgInfo.dataLen = 1;

    ret = RpcRecvVarLenData(1, &pkgInfo, &request);

    free(request.variableLenData);

    request.variableLenData = NULL;



    ret = RpcHandleRecvBytes(1);

    DT_ASSERT_EQUAL(ret, 0);



    Mock->Delete(recv);

    DeleteMock(Mock);

}



DTEST_CASE_F(RPC, TEST_KNET_RPC_HANDLE_DISCONNECT_NORMAL, NULL, NULL)

{

    KNET_RpcRegServer(KNET_RPC_EVENT_DISCONNECT, 0, &Handler);

    KTestMock *Mock = CreateMock();

    DT_ASSERT_NOT_EQUAL(Mock, NULL);

    Mock->Create(epoll_ctl, TEST_GetFuncRetNegative(1));



    struct epoll_event event = { 0 };

    RpcHandleDisconnect(0, &event);



    Mock->Delete(epoll_ctl);

    DeleteMock(Mock);

}



DTEST_CASE_F(RPC, TEST_KNET_RPC_MSG_SEND_RECV_NORMAL, NULL, NULL)

{

    struct KNET_RpcMessage request = { 0 };

    struct KNET_RpcMessage response = { 0 };

    int ret = RpcMsgSendRecv(0, 0, &request, &response);

    DT_ASSERT_EQUAL(ret, RPC_EXCEPTION);

}