-- 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 nvme_admin_command_process = require 'nvme.nvme_mi_protocol.nvme_admin_command_process'
local nvme_admin_command = require 'nvme.nvme_mi_protocol.nvme_mi_admin_command'
local nvme_mi_command = require 'nvme.nvme_mi_protocol.nvme_mi_command'
local NVME_MI_OPTIONS = require 'nvme.nvme_mi_protocol.nvme_mi_def'

TESTNvmeMiAdminProcess = {}

local function pack(obj)
    local result = ''
    for _, v in ipairs(obj) do
        result = result .. v
    end
    return result
end

-- 测试是否支持uuid
function TESTNvmeMiAdminProcess:test_check_support_uuid_by_identify_ctrl()
    local origin_func = nvme_admin_command.identify_ctrl
    nvme_admin_command.identify_ctrl = function ()
    end
    local ret = nvme_admin_command_process.check_support_uuid_by_identify_ctrl()
    lu.assertEquals(ret, false)

    nvme_admin_command.identify_ctrl = function ()
        return ''
    end
    ret = nvme_admin_command_process.check_support_uuid_by_identify_ctrl()
    lu.assertEquals(ret, false)
    nvme_admin_command.identify_ctrl = origin_func
    local nvme_obj = {
        queue = function (func)
            func()
        end,
        ctrl_id = 1,
        nvme = {
            Slot = 1
        },
        nvme_mi_obj = {
            Identify = function ()
                return {
                    value = function ()
                        return pack({
                            '\x00\x00\x00',                 -- rsvd
                            '\x00\x00\x00\x00',             -- cdw0
                            '\x00\x00\x00\x00',             -- cdw1
                            '\x00\x00\x00\x00',             -- cdw3
                            '\x00\x00',                     -- vid
                            '\x00\x00',                     -- ssvid
                            '\x48\x53\x35\x45\x32\x33\x41\x32\x34\x31\x30\x30\x50\x51\x30\x4D\x20\x20\x20\x20', -- sn
                            '\x48\x53\x35\x45\x32\x33\x41\x32\x34\x31\x30\x30\x50\x51\x30\x4D\x20\x20\x20\x20', -- mn
                            '\x48\x53\x35\x45\x32\x33\x41\x32\x34\x31\x30\x30\x50\x51\x30\x4D\x20\x20\x20\x20', -- sn
                            '\x00\x00\x00\x00\x00\x00\x00\x00',                     -- fr
                            '\x00\x00\x00\x00\x00\x00\x01\x00',
                            '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
                            '\x11\x82\x08\x00'               -- ctratt
                        })
                    end
                }
            end
        }
    }
    ret = nvme_admin_command_process.check_support_uuid_by_identify_ctrl(nvme_obj)
    lu.assertEquals(ret, true)
end

-- 测试指定opcode是否支持uuid
function TESTNvmeMiAdminProcess:test_check_specified_opcode_support_uuid()
    local origin_func = nvme_admin_command.get_support_effects_log
    nvme_admin_command.get_support_effects_log = function ()
    end
    local ret = nvme_admin_command_process.check_specified_opcode_support_uuid()
    lu.assertEquals(ret, false)

    nvme_admin_command.get_support_effects_log = function ()
        return 'test'
    end
    ret = nvme_admin_command_process.check_specified_opcode_support_uuid()
    lu.assertEquals(ret, false)

    nvme_admin_command.get_support_effects_log = origin_func
    local nvme_obj = {
        queue = function (func)
            func()
        end,
        ctrl_id = 1,
        nvme = {
            Slot = 1
        },
        nvme_mi_obj = {
            GetLogPage = function ()
                return {
                    value = function ()
                        return pack({
                            '\x00\x00\x00',                 -- rsvd
                            '\x00\x00\x00\x00',             -- cdw0
                            '\x00\x00\x00\x00',             -- cdw1
                            '\x00\x00\x00\x00',             -- cdw3
                            '\x00\x00\x00\x00\x32\x33\x41\x32\x34\x31\x30\x30\x50\x51\x30\x4D\x20\x20\x20\x20',
                            '\x01\x00\x08\x00'               -- opcode0x05
                        })
                    end
                }
            end
        }
    }
    ret = nvme_admin_command_process.check_specified_opcode_support_uuid(nvme_obj, 0x05)
    lu.assertEquals(ret, true)
end

-- 测试获取制定的uuid index
function TESTNvmeMiAdminProcess:test_get_specified_uuid_index()
    local origin_func = nvme_admin_command.identify_uuid_list
    nvme_admin_command.identify_uuid_list = function ()
    end
    local ret = nvme_admin_command_process.get_specified_uuid_index()
    lu.assertEquals(ret, false)

    nvme_admin_command.identify_uuid_list = function ()
        return ''
    end
    ret = nvme_admin_command_process.get_specified_uuid_index()
    lu.assertEquals(ret, false)

    nvme_admin_command.identify_uuid_list = function ()
        return pack({'\x00\x00\x00',                 -- rsvd
            '\x00\x00\x00\x00',             -- cdw0
            '\x00\x00\x00\x00',             -- cdw1
            '\x00\x00\x00\x00',             -- cdw3
            '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
            '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'   -- rsvd1
            })
    end
    ret = nvme_admin_command_process.get_specified_uuid_index()
    lu.assertEquals(ret, false)

    -- 预期uuid index = 2时为对应的uuid
    nvme_admin_command.identify_uuid_list = origin_func
    local nvme_obj = {
        queue = function (func)
            func()
        end,
        ctrl_id = 1,
        nvme = {
            Slot = 1
        },
        nvme_mi_obj = {
            Identify = function ()
                return {
                    value = function ()
                        return pack({
                            '\x00\x00\x00',                 -- rsvd
                            '\x00\x00\x00\x00',             -- cdw0
                            '\x00\x00\x00\x00',             -- cdw1
                            '\x00\x00\x00\x00',             -- cdw3
                            '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
                            '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',   -- rsvd1
                            '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',   -- uuidl1
                            '\x2e\x77\xb6\x9c\x75\x34\x11\xed\xae\x2c\xa8\xbd\xd2\x80\x59\xc0',   -- uuidh1
                            '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',   -- uuidl2
                            '\x2e\x77\xb6\x9c\x75\x34\x11\xed\xae\x2c\xa8\xbd\xd2\x80\x59\xc1',   -- uuidh2
                        })
                    end
                }
            end
        }
    }

    ret = nvme_admin_command_process.get_specified_uuid_index(nvme_obj,
    NVME_MI_OPTIONS.HW_DEFINED_UUID_LL, NVME_MI_OPTIONS.HW_DEFINED_UUID_LH,
    NVME_MI_OPTIONS.HW_DEFINED_UUID_HL, NVME_MI_OPTIONS.HW_DEFINED_UUID_HH)
    lu.assertEquals(ret, 2)
end

-- 测试是否支持不填充UUID获取0XEF LOG PAGE
function TESTNvmeMiAdminProcess:test_check_support_hw_defined_without_uuid()
    local origin_func = nvme_admin_command.get_log_page
    local nvme_obj = {
        ctrl_id = 0,
        nvme = {
            Slot = 1
        }
    }
    nvme_admin_command.get_log_page = function ()
    end
    local ret = nvme_admin_command_process.check_support_hw_defined_without_uuid(nvme_obj)
    lu.assertEquals(ret, false)

    nvme_admin_command.get_log_page = function ()
        return pack({
            '\x00\x00\x00',                 -- rsvd
            '\x00\x00\x00\x00',             -- cdw0
            '\x00\x00\x00\x00',             -- cdw1
            '\x00\x00\x00\x00',             -- cdw3
            '\x00\x01\x00\x64\x00\x48\x12\xA5\x5A\x21\x84\x00',  -- magic_header
        })
    end
    ret = nvme_admin_command_process.check_support_hw_defined_without_uuid(nvme_obj)
    lu.assertEquals(ret, false)

    nvme_admin_command.get_log_page = function ()
        local str = string.rep('\x00', 1512)
        return pack({
            '\x00\x00\x00',                 -- rsvd
            '\x00\x00\x00\x00',             -- cdw0
            '\x00\x00\x00\x00',             -- cdw1
            '\x00\x00\x00\x00',             -- cdw3
            '\x00\x01\x00\x64\x00\x48\x12\xA5\x5A\x21\x84\x00',  -- magic_header
            str,                            -- attr_list
        })
    end
    ret = nvme_admin_command_process.check_support_hw_defined_without_uuid(nvme_obj)
    lu.assertEquals(ret, true)
    nvme_admin_command.get_log_page = origin_func
end

-- 测试更新admin_command_info
function TESTNvmeMiAdminProcess:test_update_admin_command()
    local origin_func = nvme_admin_command.update_smart_log
    nvme_admin_command.update_smart_log = function ()
    end
    local rsp = {['test'] = 'tttt'}
    local nvme_obj = {
        queue = function(func)
            func()
        end,
        ctrl_id = 0,
        nvme = {
            Slot = 1
        },
        nvme_mi_obj = {
            FwLog = function ()
                return {
                    value = function ()
                        return rsp
                    end
                }
            end,
            FeatureIdentifiers = function ()
                return {
                    value = function ()
                        return rsp
                    end
                }
            end,
            ErrorInformation = function ()
                return {
                    value = function ()
                        return rsp
                    end
                }
            end,
            SupportedLogPages = function ()
                return {
                    value = function ()
                        return rsp
                    end
                }
            end
        }
    }
    nvme_admin_command.update_admin_command_info(nvme_obj)
    for k, v in pairs(rsp) do
        lu.assertEquals(nvme_obj.fw_log[k], v)
    end
    for k, v in pairs(rsp) do
        lu.assertEquals(nvme_obj.feature_identifiers[k], v)
    end
    for k, v in pairs(rsp) do
        lu.assertEquals(nvme_obj.error_log[k], v)
    end
    for k, v in pairs(rsp) do
        lu.assertEquals(nvme_obj.supported_log_pages[k], v)
    end
    nvme_admin_command.update_smart_log = origin_func
end

-- 测试更新mi_command_info
function TESTNvmeMiAdminProcess:test_update_mi_command()
    local rsp = {['test'] = 'tttt'}
    local nvme_obj = {
        queue = function(func)
            func()
        end,
        ctrl_id = 0,
        nvme = {
            Slot = 1
        },
        nvme_mi_obj = {
            ControllerHealthStatus = function ()
                return {
                    value = function ()
                        return rsp
                    end
                }
            end,
            MctpTransSize = function ()
                return {
                    value = function ()
                        return rsp
                    end
                }
            end,
            SubsystemInfo = function ()
                return {
                    value = function ()
                        return rsp
                    end
                }
            end,
            SubsystemHealthStatus = function ()
                return {
                    value = function ()
                        return rsp
                    end
                }
            end
        }
    }
    nvme_mi_command.update_nvme_mi_command_info(nvme_obj)
    for k, v in pairs(rsp) do
        lu.assertEquals(nvme_obj.controller_health_status[k], v)
    end
    for k, v in pairs(rsp) do
        lu.assertEquals(nvme_obj.mctp_trans_unit_size[k], v)
    end
    for k, v in pairs(rsp) do
        lu.assertEquals(nvme_obj.nvm_subsystem_info[k], v)
    end
    for k, v in pairs(rsp) do
        lu.assertEquals(nvme_obj.subsys_health_status[k], v)
    end
end