-- Copyright (c) 2025 Huawei Technologies Co., Ltd.
-- openUBMC is licensed under 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.

local lu = require 'luaunit'
local drive_collection = require 'drive.drive_collection'
local rpc_service_nvme_drive = require 'rpc_services.rpc_service_nvme_drive'
local task_mgmt = require 'mc.mdb.task_mgmt'
local nvme_admin_command = require 'nvme.nvme_mi_protocol.nvme_mi_admin_command'
local NVME_MI_OPTIONS = require 'nvme.nvme_mi_protocol.nvme_mi_def'

TEST_nvme_method = {}

--[[测试用例描述:GetSmartInfo方法调用测试
    预制条件:支持mctp的nvme mi硬盘对象加载
    操作步骤：
    调用获取SmartLog的rpc方法
    预期结果：
    1.返回成功
    2.报文解析符合预期]]
function TEST_nvme_method:test_get_smart_info_success()
    local rsp = '1236198646'
    drive_collection.get_instance().nvme_list[1] = {
        nvme_mi_mctp_obj = {
            queue = function (func)
                func()
            end,
            nvme_mi_obj = {
                SmartLog = function()
                    return {value = function ()
                        return rsp
                    end}
                end
            }
        },
        Slot = 8
    }
    local ok, ret = pcall(function ()
        return rpc_service_nvme_drive:get_smart_info('Drive_9_010102', 0)
    end)
    lu.assertIsTrue(ok)
    for i = #rsp, 1, -1 do
        lu.assertEquals(rsp:byte(i), ret[#rsp - i + 1])
    end
    drive_collection.get_instance().nvme_list[1] = nil
end

--[[测试用例描述:GetSmartInfo方法调用测试
    预制条件:支持mctp的nvme mi硬盘对象加载
    操作步骤：
    调用获取非标准SmartLog的rpc方法
    预期结果：
    1.返回成功
    2.报文解析符合预期]]
function TEST_nvme_method:test_get_vendor_smart_info_success()
    local rsp = '1236198646'
    drive_collection.get_instance().nvme_list[1] = {
        nvme_mi_mctp_obj = {
            queue = function (func)
                func()
            end,
            nvme_mi_obj = {
                RawRequest = function()
                    return {value = function ()
                        return rsp
                    end}
                end
            }
        },
        Slot = 8
    }
    local ok, ret = pcall(function ()
        return rpc_service_nvme_drive:get_smart_info('Drive_9_010102', 1)
    end)
    lu.assertIsTrue(ok)
    for i = #rsp, 1, -1 do
        lu.assertEquals(rsp:byte(i), ret[#rsp - i + 1])
    end
    drive_collection.get_instance().nvme_list[1] = nil
end

--[[测试用例描述:GetSmartInfo方法调用测试
    预制条件:支持mctp的nvme mi硬盘对象不支持mctp
    操作步骤：
    调用获取SmartLog的rpc方法
    预期结果：
    1.返回失败
    2.错误码符合预期]]
function TEST_nvme_method:test_get_smart_info_fail()
    drive_collection.get_instance().nvme_list[1] = {
        nvme_mi_mctp_obj = false,
        Slot = 66
    }
    local ok, err = pcall(function ()
        rpc_service_nvme_drive:get_smart_info('Drive_67_010102', 0)
    end)
    lu.assertIsFalse(ok)
    lu.assertEquals(err.name, 'ActionNotSupported')
    drive_collection.get_instance().nvme_list[1] = nil
end

--[[测试用例描述:GetSmartInfo方法调用测试
    预制条件:支持mctp的nvme mi硬盘对象加载但SmartLog返回nil
    操作步骤：
    调用获取SmartLog的rpc方法
    预期结果：
    1.返回失败
    2.错误码符合预期]]
function TEST_nvme_method:test_get_smart_info_nil_response()
    drive_collection.get_instance().nvme_list[1] = {
        nvme_mi_mctp_obj = {
            queue = function (func)
                func()
            end,
            nvme_mi_obj = {
                SmartLog = function()
                    return {value = function ()
                        return nil
                    end}
                end
            }
        },
        Slot = 8
    }
    local ok, err = pcall(function ()
        return rpc_service_nvme_drive:get_smart_info('Drive_9_010102', 0)
    end)
    lu.assertIsFalse(ok)
    lu.assertEquals(err.name, 'ActionNotSupported')
    drive_collection.get_instance().nvme_list[1] = nil
end

--[[测试用例描述:SendNvmeMICommand方法调用测试
    预制条件:支持mctp的nvme mi硬盘对象加载
    操作步骤：
    调用获取SendNvmeMICommand的rpc方法
    预期结果：
    1.返回成功
    2.报文解析符合预期]]
function TEST_nvme_method:test_send_nvmemi_command_success()
    local rsp = '\x00\x40\x00\x00'
    drive_collection.get_instance().nvme_list[1] = {
        nvme_mi_mctp_obj = {
            queue = function (func)
                func()
            end,
            nvme_mi_obj = {
                RawRequest = function()
                    return {value = function ()
                        return rsp
                    end}
                end
            }
        },
        Slot = 54
    }
    local ok, status, nvmersq, rsp_data = pcall(function ()
        return rpc_service_nvme_drive:send_nvmemi_command('Drive_55_010102', 4, 3, 0, {})
    end)
    lu.assertIsTrue(ok)
    lu.assertEquals(status, 0)
    lu.assertEquals(nvmersq, 64)
    lu.assertEquals(#rsp_data, 0)
    drive_collection.get_instance().nvme_list[1] = nil
end

--[[测试用例描述:SendNvmeMICommand方法调用测试
    预制条件:支持mctp的nvme mi硬盘对象不支持mctp
    操作步骤：
    调用获取SendNvmeMICommand的rpc方法
    预期结果：
    1.返回失败
    2.错误码符合预期]]
function TEST_nvme_method:test_send_nvmemi_command_fail()
    drive_collection.get_instance().nvme_list[1] = {
        nvme_mi_mctp_obj = false,
        Slot = 24
    }
    local ok, err = pcall(function ()
        rpc_service_nvme_drive:send_nvmemi_command('Drive_25_010102', 0)
    end)
    lu.assertIsFalse(ok)
    lu.assertEquals(err.name, 'ActionNotSupported')
    drive_collection.get_instance().nvme_list[1] = nil
end

--[[测试用例描述:SendNvmeMICommand方法调用测试
    预制条件:支持mctp的nvme mi硬盘对象加载但RawRequest返回nil
    操作步骤：
    调用获取SendNvmeMICommand的rpc方法
    预期结果：
    1.返回失败
    2.错误码符合预期]]
function TEST_nvme_method:test_send_nvmemi_command_nil_response()
    drive_collection.get_instance().nvme_list[1] = {
        nvme_mi_mctp_obj = {
            queue = function (func)
                func()
            end,
            nvme_mi_obj = {
                RawRequest = function()
                    return {value = function ()
                        return nil
                    end}
                end
            }
        },
        Slot = 54
    }
    local ok, err = pcall(function ()
        return rpc_service_nvme_drive:send_nvmemi_command('Drive_55_010102', 4, 3, 0, {})
    end)
    lu.assertIsFalse(ok)
    lu.assertEquals(err.name, 'ActionNotSupported')
    drive_collection.get_instance().nvme_list[1] = nil
end

--[[测试用例描述:GetIdentifyData方法调用测试
    预制条件:支持mctp的nvme mi硬盘对象加载
    操作步骤：
    调用获取GetIdentifyData的rpc方法
    预期结果：
    1.返回成功
    2.报文解析符合预期]]
function TEST_nvme_method:test_get_identify_data_success()
    local rsp = '49816898446'
    drive_collection.get_instance().nvme_list[1] = {
        nvme_mi_mctp_obj = {
            queue = function (func)
                func()
            end,
            nvme_mi_obj = {
                IdentifyNS = function()
                    return {value = function ()
                        return rsp
                    end}
                end
            }
        },
        Slot = 13
    }
    local ok, ret = pcall(function ()
        return rpc_service_nvme_drive:get_identify_data('Drive_14_010102', 0)
    end)
    print(ret)
    lu.assertIsTrue(ok)
    for i = #rsp, 1, -1 do
        lu.assertEquals(rsp:byte(i), ret[#rsp - i + 1])
    end
    drive_collection.get_instance().nvme_list[1] = nil
end

--[[测试用例描述:GetIdentifyData方法调用测试
    预制条件:支持mctp的nvme mi硬盘对象不支持mctp
    操作步骤：
    调用获取GetIdentifyData的rpc方法
    预期结果：
    1.返回失败
    2.错误码符合预期]]
function TEST_nvme_method:test_get_identify_data_fail()
    drive_collection.get_instance().nvme_list[1] = {
        nvme_mi_mctp_obj = false,
        Slot = 13
    }
    local ok, err = pcall(function ()
        rpc_service_nvme_drive:get_identify_data('Drive_14_010102', 0)
    end)
    lu.assertIsFalse(ok)
    lu.assertEquals(err.name, 'ActionNotSupported')
    drive_collection.get_instance().nvme_list[1] = nil
end

--[[测试用例描述:GetIdentifyData方法调用测试
    预制条件:支持mctp的nvme mi硬盘对象加载但IdentifyNS返回nil
    操作步骤：
    调用获取GetIdentifyData的rpc方法
    预期结果：
    1.返回失败
    2.错误码符合预期]]
function TEST_nvme_method:test_get_identify_data_nil_response()
    drive_collection.get_instance().nvme_list[1] = {
        nvme_mi_mctp_obj = {
            nvme_mi_obj = {
                IdentifyNS = function()
                    return {value = function ()
                        return nil
                    end}
                end
            }
        },
        Slot = 13
    }
    local ok = pcall(function ()
        return rpc_service_nvme_drive:get_identify_data('Drive_14_010102', 0)
    end)
    lu.assertIsFalse(ok)
    drive_collection.get_instance().nvme_list[1] = nil
end

--[[测试用例描述:GetTelemetryData方法调用测试
    预制条件:支持mctp的nvme mi硬盘对象加载
    操作步骤：
    调用获取GetTelemetryData的rpc方法
    预期结果：
    1.返回成功
    2.taskid符合预期]]
function TEST_nvme_method:test_get_telemetry_data_success()
    local rsp = '8541446'
    drive_collection.get_instance().nvme_list[1] = {
        nvme_mi_mctp_obj = {
            queue = function (func)
                func()
            end,
            nvme_mi_obj = {
                RawRequest = function()
                    return {value = function ()
                        return rsp
                    end}
                end
            }
        },
        Slot = 13
    }
    local create_code = task_mgmt.create_code
    task_mgmt.create_task = function()
        return create_code.TASK_CREATE_SUCCESSFUL, 123, 4566
    end
    local ok, ret = pcall(function()
        return rpc_service_nvme_drive:get_telemetry_data('Drive_14_010102', _, 'Host')
    end)
    lu.assertIsTrue(ok)
    lu.assertEquals(ret, 4566)
    drive_collection.get_instance().nvme_list[1] = nil
end

--[[测试用例描述:GetTelemetryData方法调用测试
    预制条件:支持mctp的nvme mi硬盘对象不支持mctp
    操作步骤：
    调用获取GetTelemetryData的rpc方法
    预期结果：
    1.返回失败
    2.错误码符合预期]]
function TEST_nvme_method:test_get_telemetry_data_fail()
    drive_collection.get_instance().nvme_list[1] = {
        nvme_mi_mctp_obj = false,
        Slot = 13
    }
    local ok, err = pcall(function()
        return rpc_service_nvme_drive:get_telemetry_data('Drive_14_010102', _, 'Host')
    end)
    lu.assertIsFalse(ok)
    lu.assertEquals(err.name, 'ActionNotSupported')
    drive_collection.get_instance().nvme_list[1] = nil
end

--[[测试用例描述:GetTelemetryData方法调用测试
    预制条件:支持mctp的nvme mi硬盘对象加载但task创建失败
    操作步骤：
    调用获取GetTelemetryData的rpc方法
    预期结果：
    1.返回失败
    2.错误码符合预期]]
function TEST_nvme_method:test_get_telemetry_data_task_create_fail()
    drive_collection.get_instance().nvme_list[1] = {
        nvme_mi_mctp_obj = {
            nvme_mi_obj = {
                RawRequest = function()
                    return {value = function ()
                    end}
                end
            }
        },
        Slot = 13
    }
    local create_code = task_mgmt.create_code
    local orig_create_task = task_mgmt.create_task
    task_mgmt.create_task = function()
        return create_code.TASK_CREATE_FAILED, { name = 'DuplicateExportingErr' }, nil
    end
    local ok, err = pcall(function()
        return rpc_service_nvme_drive:get_telemetry_data('Drive_14_010102', _, 'Host')
    end)
    task_mgmt.create_task = orig_create_task
    drive_collection.get_instance().nvme_list[1] = nil
    lu.assertIsFalse(ok)
    lu.assertNotNil(err)
    if type(err) == 'table' and err.name then
        lu.assertEquals(err.name, 'DuplicateExportingErr')
    end
end

function TEST_nvme_method:test_get_telemetry_data_progreass()
    local nvme_utils = require 'nvme.utils'
    local file_sec = require 'utils.file'
    local stub_parse_rsp_status = nvme_utils.parse_rsp_status
    local stub_log_response = NVME_MI_OPTIONS.log_response
    local stub_open_s = file_sec.open_s
    nvme_utils.parse_rsp_status = function (ret)
        return ret
    end
    NVME_MI_OPTIONS.telemetry_log_page_rsp = {unpack = function ()
        return {dalb3 = 563}
    end}
    NVME_MI_OPTIONS.log_response = {unpack = function ()
        return {data = '222'}
    end}
    file_sec.open_s = function ()
        return {close = function () end}
    end
    local ret = pcall(function ()
        return nvme_admin_command.get_telemetry_log({
            nvme_mi_mctp_obj = {
                queue = function (func)
                    func()
                end,
                nvme_mi_obj = {
                    RawRequest = function()
                        return {value = function ()
                            return '1'
                        end}
                    end
                }
            },
            Slot = 13
        })
    end)
    nvme_utils.parse_rsp_status = stub_parse_rsp_status
    NVME_MI_OPTIONS.log_response = stub_log_response
    file_sec.open_s = stub_open_s
    lu.assertIsTrue(ret)
end

return TEST_nvme_method