-- Copyright (c) 2024 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 c_object_manage = require 'mc.orm.object_manage'
local npu_imu_cmd = require 'npu.hdk_cmd'
local fructl = require 'infrastructure.fructl'
local ipmi = require 'ipmi'
skynet = require 'skynet'
local comp_code = ipmi.types.Cc
local bs = require 'mc.bitstring'
local c_object_manage = require 'mc.orm.object_manage'

TEST_hdk_cmd = {}

local function mock_get_power_status(...)
    return 'ON'
end

local function mock_get_instance(...)
    return {
        bus = 'test'
    }
end

local function  mock_ipmi_request(...)
    return 0x01, ''
end

-- 对于日志收集等长命令需要根据偏移返回
local function update_mock_resp(mock_resp, offset)
    if offset == 0 then
        return mock_resp
    end

    -- 根据返回体格式可能需要增加ifelse分支
    if mock_resp.tail then
        mock_resp.tail = string.sub(mock_resp.tail, 1 + offset, #mock_resp.tail)
    elseif mock_resp.data then
        mock_resp.data = string.sub(mock_resp.data, 1 + offset, #mock_resp.data)
    end

    return mock_resp
end

local function mock_ipmi(mock_data)
    local mocak_comp_code, mock_resp, req_format, resp_format = mock_data.comp_code, mock_data.mock_resp,
        mock_data.req_format, mock_data.resp_format
    ipmi.request = function (...)
        local _, _, req = ...
        local payload = req_format:unpack(req.Payload)
        local offset, _ = payload.offset, payload.data_length
        mock_resp = update_mock_resp(mock_resp, offset)
        mock_resp = resp_format:pack(mock_resp)
        return mocak_comp_code, mock_resp
    end
end

local get_power_status = fructl.get_power_status
local ipmi_request = ipmi.request
local get_instance = c_object_manage.get_instance

function TEST_hdk_cmd:setUp()
    fructl.get_power_status = mock_get_power_status
    c_object_manage.get_instance = mock_get_instance
    ipmi.request = mock_ipmi_request
end


function TEST_hdk_cmd:tearDown()
    fructl.get_power_status = get_power_status
    c_object_manage.get_instance = get_instance
    ipmi.request = ipmi_request
end

function TEST_hdk_cmd:test_get_info_from_imu()
    local obj = npu_imu_cmd.get_info_from_imu(1, 1)
    lu.assertEquals(obj.ip_addr, 'N/A')
end

local test_get_op_runtime_info<const> = {
    comp_code = comp_code.Success,
    req_format = bs.new([[<<
        0xDB0700:3/unit:8,
        cmd:1/unit:8,
        lun:1/unit:8,
        request_parameter:1/unit:8,
        op_cmd:1/unit:8,
        op_fun:1/unit:8,
        offset:4/unit:8,
        data_length:4/unit:8,
        request_type:1/unit:8,
        op_logical_id:1/unit:8
        >>]]),
    resp_format = bs.new([[<<
        error_code:1/unit:8,
        opcode:2/little-unit:8,
        total_length:4/little-unit:8,
        length:4/little-unit:8,
        cmd_version:1/unit:8,

        # support_info 有7个字节,每个bit代表接下来结构体中对应顺序的属性是否支持
        runtime_supported:1,
        poweron_time_supported:1,
        poweron_count_supported:1,
        power_status_supported:1,
        odsp_temp_supported:1,
        odsp_high_heat_time_supported:1,
        laser_run_time_supported:1,
        laser_temp_supported:1,
        laser_core_temp_supported:1,
        reserved:47,

        runtime:4/little-unit:8,
        poweron_time:4/little-unit:8,
        poweron_count:2/little-unit:8,
        power_status:2/little-unit:8,
        odsp_temp:2/little-unit:8,
        odsp_high_heat_time:4/little-unit:8,
        laser_run_time:4/little-unit:8,
        laser_temp:2/little-unit:8,
        laser_core_temp:2/little-unit:8,
        tail/string
        >>]]),
    mock_resp = {
        error_code = 0,
        opcode = 0,
        total_length = 0,
        length = 0,
        cmd_version = 0,
        runtime_supported = 1,
        poweron_time_supported = 1,
        poweron_count_supported = 1,
        power_status_supported = 1,
        odsp_temp_supported = 1,
        odsp_high_heat_time_supported = 1,
        laser_run_time_supported = 1,
        laser_temp_supported = 1,
        laser_core_temp_supported = 1,
        reserved = 1,
        runtime = 4,
        poweron_time = 4,
        poweron_count = 2,
        power_status = 2,
        odsp_temp = 2,
        odsp_high_heat_time = 4,
        laser_run_time = 4,
        laser_temp = 2,
        laser_core_temp = 0,
        tail =""
    }
}

function TEST_hdk_cmd:test_get_op_runtime_info()
    mock_ipmi(test_get_op_runtime_info)
    local ok, err = pcall(function()
        return npu_imu_cmd.get_op_runtime_info(1)
    end)
    print(err)
    lu.assertEquals(ok, true)
end

local test_get_op_base_info_new<const> = {
    comp_code = comp_code.Success,
    req_format = bs.new([[<<
        0xDB0700:3/unit:8,
        cmd:1/unit:8,
        lun:1/unit:8,
        para:1/unit:8,
        op_cmd:1/unit:8,
        op_fun:1/unit:8,
        offset:4/unit:8,
        data_length:4/unit:8,
        op_logical_id:1/unit:8
    >>]]),
    resp_format = bs.new([[<<
        head:3/unit:8,
        total_length:4/little-unit:8,
        length:4/little-unit:8,
        vendor_name:32/string,
        serial_number:32/string,
        part_number:32/string,
        manufacture_date:32/string,
        transceiver_type:1/little-unit:8,
        optical_type:1/little-unit:8,
        channel_num:1/little-unit:8,
        tail/binary
    >>]]),
    mock_resp = {
        head = 0,
        total_length = 131,
        length = 1,
        vendor_name = 'HUAWEI',
        serial_number = 'QW1258ERR',
        part_number = '539677419',
        manufacture_date = 'manufacture',
        transceiver_type = 16,
        optical_type = 2,
        channel_num = 4,
        tail = ''
    }
}

local test_get_op_base_info_new1<const> = {
    comp_code = comp_code.Success,
    req_format = bs.new([[<<
        0xDB0700:3/unit:8,
        cmd:1/unit:8,
        lun:1/unit:8,
        para:1/unit:8,
        op_cmd:1/unit:8,
        op_fun:1/unit:8,
        offset:4/unit:8,
        data_length:4/unit:8,
        op_logical_id:1/unit:8
    >>]]),
    resp_format = bs.new([[<<
        head:3/unit:8,
        total_length:4/little-unit:8,
        length:4/little-unit:8,
        vendor_name:32/string,
        serial_number:32/string,
        part_number:32/string,
        manufacture_date:32/string,
        transceiver_type:1/little-unit:8,
        optical_type:1/little-unit:8,
        channel_num:1/little-unit:8,
        tail/binary
    >>]]),
    mock_resp = {
        head = 0,
        total_length = 131,
        length = 1,
        vendor_name = 'HUAWEI',
        serial_number = 'QW1258ERR1',
        part_number = '539677419',
        manufacture_date = 'manufacture',
        transceiver_type = 16,
        optical_type = 2,
        channel_num = 4,
        tail = ''
    }
}

local test_get_op_base_info_old<const> = {
    comp_code = comp_code.Success,
    req_format = bs.new([[<<
        0xDB0700:3/unit:8,
        cmd:1/unit:8,
        lun:1/unit:8,
        para:1/unit:8,
        op_cmd:1/unit:8,
        op_fun:1/unit:8,
        offset:4/unit:8,
        data_length:4/unit:8,
        op_logical_id:1/unit:8
    >>]]),
    resp_format = bs.new([[<<
        head:3/unit:8,
        total_length:4/little-unit:8,
        length:4/little-unit:8,
        vendor_name:32/string,
        serial_number:32/string,
        part_number:32/string,
        manufacture_date:32/string,
        transceiver_type:1/little-unit:8,
        tail/binary
    >>]]),
    mock_resp = {
        head = 0,
        total_length = 130,
        length = 1,
        vendor_name = '11111111111111111111111111111111',
        serial_number = '11111111111111111111111111111111',
        part_number = '11111111111111111111111111111111',
        manufacture_date = '11111111111111111111111111111111',
        transceiver_type = 16,
        tail = '\02\01'
    }
}

local test_get_op_base_info_channer_num_err<const> = {
    comp_code = comp_code.Success,
    req_format = bs.new([[<<
        0xDB0700:3/unit:8,
        cmd:1/unit:8,
        lun:1/unit:8,
        para:1/unit:8,
        op_cmd:1/unit:8,
        op_fun:1/unit:8,
        offset:4/unit:8,
        data_length:4/unit:8,
        op_logical_id:1/unit:8
    >>]]),
    resp_format = bs.new([[<<
        head:3/unit:8,
        total_length:4/little-unit:8,
        length:4/little-unit:8,
        vendor_name:32/string,
        serial_number:32/string,
        part_number:32/string,
        manufacture_date:32/string,
        transceiver_type:1/little-unit:8,
        tail/binary
    >>]]),
    mock_resp = {
        head = 0,
        total_length = 131,
        length = 1,
        vendor_name = '11111111111111111111111111111111',
        serial_number = '11111111111111111111111111111111',
        part_number = '11111111111111111111111111111111',
        manufacture_date = '11111111111111111111111111111111',
        transceiver_type = 0,
        tail = ''
    }
}

local test_get_op_speed_info<const> = {
    comp_code = comp_code.Success,
    req_format = bs.new([[<<
        0xDB0700:3/unit:8,
        cmd:1/unit:8,
        lun:1/unit:8,
        para:1/unit:8,
        op_cmd:1/unit:8,
        op_fun:1/unit:8,
        offset:4/unit:8,
        data_length:4/unit:8,
        op_logical_id:1/unit:8
    >>]]),
    resp_format = bs.new([[<<
        head:3/unit:8,
        total_length:4/little-unit:8,
        length:4/little-unit:8,
        vendor_name:32/string,
        serial_number:32/string,
        part_number:32/string,
        manufacture_date:32/string,
        transceiver_type:1/little-unit:8,
        tail/binary
    >>]]),
    mock_resp = {
        head = 0,
        total_length = 135,
        length = 135,
        vendor_name = '11111111111111111111111111111111',
        serial_number = '11111111111111111111111111111111',
        part_number = '11111111111111111111111111111111',
        manufacture_date = '11111111111111111111111111111111',
        transceiver_type = 16,
        tail = '\03\04\03\xa0\x86\x01\00\x00'
    }
}

-- LPO光模块测试数据: transceiver_type = 0xC4, optical_type = 5 (LPO模式)
local test_get_op_base_info_lpo<const> = {
    comp_code = comp_code.Success,
    req_format = bs.new([[<<
        0xDB0700:3/unit:8,
        cmd:1/unit:8,
        lun:1/unit:8,
        para:1/unit:8,
        op_cmd:1/unit:8,
        op_fun:1/unit:8,
        offset:4/unit:8,
        data_length:4/unit:8,
        op_logical_id:1/unit:8
    >>]]),
    resp_format = bs.new([[<<
        head:3/unit:8,
        total_length:4/little-unit:8,
        length:4/little-unit:8,
        vendor_name:32/string,
        serial_number:32/string,
        part_number:32/string,
        manufacture_date:32/string,
        transceiver_type:1/little-unit:8,
        optical_type:1/little-unit:8,
        channel_num:1/little-unit:8,
        tail/binary
    >>]]),
    mock_resp = {
        head = 0,
        total_length = 131,
        length = 1,
        vendor_name = 'HUAWEI',
        serial_number = 'LPO12345678',
        part_number = 'LPO-Module-01',
        manufacture_date = '20240101',
        transceiver_type = 0xC4,
        optical_type = 5,
        channel_num = 8,
        tail = ''
    }
}

function TEST_hdk_cmd:test_get_op_base_info()
    local bus = c_object_manage.get_instance().bus
    -- 模拟ipmi返回
    local tmp = ipmi.request
    mock_ipmi(test_get_op_base_info_new)
    local cc, table = npu_imu_cmd.mock_get_op_base_info(bus, 1)
    lu.assertEquals(cc, 0)
    lu.assertEquals(table.transceiver_type, "400G BASE-SR8")

    print(table.vendor_name, table.sn, table.transceiver_type, table.manufacture_date, table.part_number)
    lu.assertEquals(table.channel_num, 4)

    mock_ipmi(test_get_op_base_info_old)
    local cc1, table1 = npu_imu_cmd.mock_get_op_base_info(bus, 1)
    lu.assertEquals(cc1, 0)
    print(table1.vendor_name, table1.sn, table1.transceiver_type, table1.manufacture_date, table1.part_number)
    lu.assertEquals(table1.channel_num, 8)
    lu.assertEquals(table1.transceiver_type, "400G BASE-SR8")

    mock_ipmi(test_get_op_base_info_channer_num_err)
    local cc2, table2 = npu_imu_cmd.mock_get_op_base_info(bus, 1)
    lu.assertEquals(cc2, 0)
    lu.assertEquals(table2.channel_num, 8)
    print(table2.vendor_name, table2.sn, table2.transceiver_type, table2.manufacture_date, table2.part_number)

    mock_ipmi(test_get_op_speed_info)
    local cc3, table3 = npu_imu_cmd.mock_get_op_base_info(bus, 1)
    lu.assertEquals(cc3, 0)
    lu.assertEquals(table3.channel_num, 4)
    lu.assertEquals(table3.transceiver_type, "100G AOC")
    print(table3.vendor_name, table3.sn, table3.transceiver_type, table3.manufacture_date, table3.part_number)

    mock_ipmi(test_get_op_base_info_new)
    local cc4, table4 = npu_imu_cmd.mock_get_op_base_info(bus, 1)
    skynet.sleep(300)
    mock_ipmi(test_get_op_base_info_new1)
    local cc5, table5 = npu_imu_cmd.mock_get_op_base_info(bus, 1)
    lu.assertEquals(cc4, 0)
    lu.assertEquals(table4.sn, 'QW1258ERR')
    lu.assertEquals(cc5, 0)
    lu.assertEquals(table5.sn, 'QW1258ERR1')

    -- 测试LPO光模块 transceiver_type = 0xC4 显示为 "LPO 800GBASE-VR8"
    mock_ipmi(test_get_op_base_info_lpo)
    local cc6, table6 = npu_imu_cmd.mock_get_op_base_info(bus, 1)
    lu.assertEquals(cc6, 0)
    lu.assertEquals(table6.transceiver_type, "LPO 800GBASE-VR8")
    print(table6.vendor_name, table6.sn, table6.transceiver_type, table6.manufacture_date, table6.part_number)

    ipmi.request = tmp
end

local test_get_op_status_info<const> = {
    comp_code = comp_code.Success,
    req_format = bs.new([[<<
        0xDB0700:3/unit:8,
        cmd:1/unit:8,
        lun:1/unit:8,
        para:1/unit:8,
        op_cmd:1/unit:8,
        op_fun:1/unit:8,
        offset:4/unit:8,
        data_length:4/unit:8,
        op_logical_id:1/unit:8
        >>]]),
    resp_format = bs.new([[<<
        head:3/unit:8,
        total_length:4/little-unit:8,
        length:4/little-unit:8,
        voltage:4/little-unit:8,
        tx_power1:2/big-unit:8,
        tx_power2:2/big-unit:8,
        tx_power3:2/big-unit:8,
        tx_power4:2/big-unit:8,
        tx_power5:2/big-unit:8,
        tx_power6:2/big-unit:8,
        tx_power7:2/big-unit:8,
        tx_power8:2/big-unit:8,
        rx_power1:2/big-unit:8,
        rx_power2:2/big-unit:8,
        rx_power3:2/big-unit:8,
        rx_power4:2/big-unit:8,
        rx_power5:2/big-unit:8,
        rx_power6:2/big-unit:8,
        rx_power7:2/big-unit:8,
        rx_power8:2/big-unit:8,
        tx_bias1:2/big-unit:8,
        tx_bias2:2/big-unit:8,
        tx_bias3:2/big-unit:8,
        tx_bias4:2/big-unit:8,
        tx_bias5:2/big-unit:8,
        tx_bias6:2/big-unit:8,
        tx_bias7:2/big-unit:8,
        tx_bias8:2/big-unit:8,
        tx_los:4/little-unit:8,
        rx_los:4/little-unit:8,
        tx_lol:4/little-unit:8,
        rx_lol:4/little-unit:8,
        temperature:4/little-unit:8,
        tx_fault:4/little-unit:8,
        host_snr1:32/little-float,
        host_snr2:32/little-float,
        host_snr3:32/little-float,
        host_snr4:32/little-float,
        host_snr5:32/little-float,
        host_snr6:32/little-float,
        host_snr7:32/little-float,
        host_snr8:32/little-float,
        media_snr1:32/little-float,
        media_snr2:32/little-float,
        media_snr3:32/little-float,
        media_snr4:32/little-float,
        media_snr5:32/little-float,
        media_snr6:32/little-float,
        media_snr7:32/little-float,
        media_snr8:32/little-float,
        access_failed:1/little-unit:8,
        tail/string
        >>]]),
    mock_resp = {
        head = 0,
        total_length = 1,
        length = 1,
        voltage = 0,
        tx_power1 = 0,
        tx_power2 = 0,
        tx_power3 = 0,
        tx_power4 = 0,
        tx_power5 = 0,
        tx_power6 = 0,
        tx_power7 = 0,
        tx_power8 = 0,
        rx_power1 = 0,
        rx_power2 = 0,
        rx_power3 = 0,
        rx_power4 = 0,
        rx_power5 = 0,
        rx_power6 = 0,
        rx_power7 = 0,
        rx_power8 = 0,
        tx_bias1 = 0,
        tx_bias2 = 0,
        tx_bias3 = 0,
        tx_bias4 = 0,
        tx_bias5 = 0,
        tx_bias6 = 0,
        tx_bias7 = 0,
        tx_bias8 = 0,
        tx_los = 0,
        rx_los = 0,
        tx_lol = 0,
        rx_lol = 0,
        temperature = 0,
        tx_fault = 0,
        host_snr1 = 1,
        host_snr2 = 2,
        host_snr3 = 3,
        host_snr4 = 4,
        host_snr5 = 5,
        host_snr6 = 6,
        host_snr7 = 7,
        host_snr8 = 8,
        media_snr1 = 11,
        media_snr2 = 22,
        media_snr3 = 33,
        media_snr4 = 44,
        media_snr5 = 55,
        media_snr6 = 66,
        media_snr7 = 77,
        media_snr8 = 88,
        access_failed = 0,
        tail =""
    }
}

function TEST_hdk_cmd:test_get_op_status_info()
    local bus = c_object_manage.get_instance().bus
    -- 模拟ipmi返回
    local tmp = ipmi.request
    mock_ipmi(test_get_op_status_info)
    local cc, voltage, tx_power, rx_power, tx_bias, tx_los, rx_los, tx_lol, rx_lol,
        temperature, tx_fault, host_snr, media_snr, access_failed =
        npu_imu_cmd.mock_get_op_status_info(bus, 1, 4)
    print(voltage, tx_los, rx_los, tx_lol, rx_lol, temperature, tx_fault, access_failed)
    lu.assertEquals(cc, 0)
    lu.assertEquals(#tx_power, 4)
    lu.assertEquals(#rx_power, 4)
    lu.assertEquals(#tx_bias, 4)
    lu.assertEquals(#host_snr, 4)
    lu.assertEquals(#media_snr, 4)

    mock_ipmi(test_get_op_status_info)
    local cc1, voltage1, tx_power1, rx_power1, tx_bias1, tx_los1, rx_los1, tx_lol1, rx_lol1,
        temperature1, tx_fault1, host_snr1, media_snr1, access_failed1 =
        npu_imu_cmd.mock_get_op_status_info(bus, 1, 8)
    print(voltage1, tx_los1, rx_los1, tx_lol1, rx_lol1, temperature1, tx_fault1, access_failed1)
    lu.assertEquals(cc1, 0)
    lu.assertEquals(#tx_power1, 8)
    lu.assertEquals(#rx_power1, 8)
    lu.assertEquals(#tx_bias1, 8)
    lu.assertEquals(#host_snr1, 8)
    lu.assertEquals(#media_snr1, 8)
    ipmi.request = tmp
end

-- 测试 get_op_status_info NPU_UB 模型分支 (覆盖行1116, 1124)
function TEST_hdk_cmd:test_get_op_status_info_ub_model()
    local temp = ipmi.request
    local bus = c_object_manage.get_instance().bus

    -- 捕获请求参数以验证 data_length 和 op_logical_id
    local captured_req
    ipmi.request = function(bus_info, cmd_info, req)
        local req_data = test_get_op_status_info.req_format:unpack(req.Payload)
        captured_req = req_data
        local mock_resp = test_get_op_status_info.mock_resp
        local resp_packed = test_get_op_status_info.resp_format:pack(mock_resp)
        return 0, resp_packed
    end

    -- 测试 NPU_UB model - 应该使用 data_length=1 和 op_logical_id
    pcall(function()
        npu_imu_cmd.mock_get_op_status_info(bus, 1, 4, 1, 'NPU_UB', 8)
    end)

    -- 验证 data_length=1 (is_support_ub返回true时的分支)
    lu.assertNotNil(captured_req)
    if captured_req then
        lu.assertEquals(captured_req.data_length, 1)
    end

    -- 测试非 NPU_UB model - 应该使用 data_length=0 和 op_logical_id=0
    captured_req = nil
    pcall(function()
        npu_imu_cmd.mock_get_op_status_info(bus, 1, 4, 1, 'NPU', 8)
    end)

    lu.assertNotNil(captured_req)
    if captured_req then
        lu.assertEquals(captured_req.data_length, 0)
    end

    ipmi.request = temp
end

function TEST_hdk_cmd:test_get_npu_cdr_temp_from_imu()    
    ipmi.request = function(bus, cmd, subcmd)
        return 0, "test"
    end
    local ret = {cdr_temp = 1}
    local rspNpuCdrTemp = {}
    rspNpuCdrTemp.unpack = function()
        return ret
    end
    npu_imu_cmd.get_npu_cdr_temp_from_imu(1, true)
    lu.assertEquals(ret.cdr_temp, 1)
end

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

function TEST_hdk_cmd:test_get_mac_from_imu()
    local mock_response = pack({
        '\x00\x00\x00',
        '\x00\x00\x00\x00',
        '\x00\x00\x00\x00',
        '\x3a',
        '\x3b',
        '\x3c',
        '\x3d',
        '\x3e',
        '\x3f'
    })
    ipmi.request = function(bus, cmd, subcmd)
        return 0, mock_response
    end

    local ret = npu_imu_cmd.get_info_from_imu(1, 1)
    lu.assertEquals(ret.mac_addr, '3A:3B:3C:3D:3E:3F')
end

local get_linkdown_optical_info<const> = {
    comp_code = comp_code.Success,
    req_format = bs.new([[<<
        0xDB0700:3/unit:8,
        cmd:1/unit:8,
        lun:1/unit:8,
        request_parameter:1/unit:8,
        op_cmd:1/unit:8,
        op_fun:1/unit:8,
        offset:4/unit:8,
        data_length:4/unit:8,
        op_logical_id:1/unit:8
    >>]]),
    resp_format = bs.new([[<<
        error_code:1/unit:8,
        opcode:2/little-unit:8,
        total_length:4/little-unit:8,
        length:4/little-unit:8,
        packet_type:1/little-unit:8,
        packet_all:1/little-unit:8,
        packet_num:1/little-unit:8,
        packet_len:1/little-unit:8,
        timestamp:4/little-unit:8,
        reserve:4/little-unit:8,
        voltage:4/little-unit:8,
        tx_power1:4/little-unit:8,
        tx_power2:4/little-unit:8,
        tx_power3:4/little-unit:8,
        tx_power4:4/little-unit:8,
        tx_power5:4/little-unit:8,
        tx_power6:4/little-unit:8,
        tx_power7:4/little-unit:8,
        tx_power8:4/little-unit:8,
        rx_power1:4/little-unit:8,
        rx_power2:4/little-unit:8,
        rx_power3:4/little-unit:8,
        rx_power4:4/little-unit:8,
        rx_power5:4/little-unit:8,
        rx_power6:4/little-unit:8,
        rx_power7:4/little-unit:8,
        rx_power8:4/little-unit:8,
        tx_bias1:4/little-unit:8,
        tx_bias2:4/little-unit:8,
        tx_bias3:4/little-unit:8,
        tx_bias4:4/little-unit:8,
        tx_bias5:4/little-unit:8,
        tx_bias6:4/little-unit:8,
        tx_bias7:4/little-unit:8,
        tx_bias8:4/little-unit:8,
        tx_los:4/little-unit:8,
        rx_los:4/little-unit:8,
        tx_lol:4/little-unit:8,
        rx_lol:4/little-unit:8,
        temperature:4/little-unit:8,
        tx_fault:4/little-unit:8,
        host_snr1:32/little-float,
        host_snr2:32/little-float,
        host_snr3:32/little-float,
        host_snr4:32/little-float,
        host_snr5:32/little-float,
        host_snr6:32/little-float,
        host_snr7:32/little-float,
        host_snr8:32/little-float,
        media_snr1:32/little-float,
        media_snr2:32/little-float,
        media_snr3:32/little-float,
        media_snr4:32/little-float,
        media_snr5:32/little-float,
        media_snr6:32/little-float,
        media_snr7:32/little-float,
        media_snr8:32/little-float,
        tail/binary
    >>]]),
    mock_resp = {
        error_code = 0,
        opcode = 0x06a0,
        total_length = 1,
        length = 1,
        packet_type = 0,
        packet_all = 0,
        packet_num = 1,
        packet_type = 0,
        packet_len = 0,
        timestamp = 0,
        reserve = 0,
        voltage = 0,
        tx_power1 = 0,
        tx_power2 = 0,
        tx_power3 = 0,
        tx_power4 = 0,
        tx_power5 = 0,
        tx_power6 = 0,
        tx_power7 = 0,
        tx_power8 = 0,
        rx_power1 = 0,
        rx_power2 = 0,
        rx_power3 = 0,
        rx_power4 = 0,
        rx_power5 = 0,
        rx_power6 = 0,
        rx_power7 = 0,
        rx_power8 = 0,
        tx_bias1 = 0,
        tx_bias2 = 0,
        tx_bias3 = 0,
        tx_bias4 = 0,
        tx_bias5 = 0,
        tx_bias6 = 0,
        tx_bias7 = 0,
        tx_bias8 = 0,
        tx_los = 0,
        rx_los = 0,
        tx_lol = 0,
        rx_lol = 0,
        temperature = 0,
        tx_fault = 0,
        host_snr1 = 1,
        host_snr2 = 2,
        host_snr3 = 3,
        host_snr4 = 4,
        host_snr5 = 5,
        host_snr6 = 6,
        host_snr7 = 7,
        host_snr8 = 8,
        media_snr1 = 11,
        media_snr2 = 22,
        media_snr3 = 33,
        media_snr4 = 44,
        media_snr5 = 55,
        media_snr6 = 66,
        media_snr7 = 77,
        media_snr8 = 88,
        device_id = 0,
        tail = '\02\01'
    }
}

function TEST_hdk_cmd:test_get_linkdown_optical_info()
    -- 模拟ipmi返回
    local tmp = ipmi.request
    mock_ipmi(get_linkdown_optical_info)
    local packet_all = npu_imu_cmd.mock_get_linkdown_optical_info_cmd(1)
    lu.assertEquals(packet_all, 0)
    ipmi.request = tmp
end

local get_linkdown_electric_info<const> = {
    comp_code = comp_code.Success,
    req_format = bs.new([[<<
        0xDB0700:3/unit:8,
        cmd:1/unit:8,
        lun:1/unit:8,
        request_parameter:1/unit:8,
        op_cmd:1/unit:8,
        op_fun:1/unit:8,
        offset:4/unit:8,
        data_length:4/unit:8
    >>]]),
    resp_format = bs.new([[<<
        error_code:1/unit:8,
        opcode:2/little-unit:8,
        total_length:4/little-unit:8,
        length:4/little-unit:8,
        cmd_version:1/little-unit:8,
        support_info:7/little-unit:8,
        packet_type:1/little-unit:8,
        packet_all:1/little-unit:8,
        packet_num:1/little-unit:8,
        packet_len:1/little-unit:8,
        timestamp:4/little-unit:8,
        npu_rx_snr1:32/little-float,
        npu_rx_snr2:32/little-float,
        npu_rx_snr3:32/little-float,
        npu_rx_snr4:32/little-float,
        npu_rx_snr5:32/little-float,
        npu_rx_snr6:32/little-float,
        npu_rx_snr7:32/little-float,
        npu_rx_snr8:32/little-float,
        pcs_err_cnt:8/little-unit:8,
        cw_before_correct_cnt:8/little-unit:8,
        cw_correct_cnt:8/little-unit:8,
        cw_uncorrect_cnt:8/little-unit:8,
        cdr_host_snr1:32/little-float,
        cdr_host_snr2:32/little-float,
        cdr_host_snr3:32/little-float,
        cdr_host_snr4:32/little-float,
        cdr_host_snr5:32/little-float,
        cdr_host_snr6:32/little-float,
        cdr_host_snr7:32/little-float,
        cdr_host_snr8:32/little-float,
        cdr_media_snr1:32/little-float,
        cdr_media_snr2:32/little-float,
        cdr_media_snr3:32/little-float,
        cdr_media_snr4:32/little-float,
        cdr_media_snr5:32/little-float,
        cdr_media_snr6:32/little-float,
        cdr_media_snr7:32/little-float,
        cdr_media_snr8:32/little-float,
        device_id:4/little-unit:8,
        tail/string
        >>]]),
    mock_resp = {
        error_code = 0,
        opcode = 0x06a5,
        total_length = 1,
        length = 1,
        cmd_version = 1,
        support_info = 286331153,
        packet_type = 0,
        packet_all = 0,
        packet_num = 1,
        packet_type = 0,
        packet_len = 0,
        timestamp = 0,
        npu_rx_snr1 = 1,
        npu_rx_snr2 = 2,
        npu_rx_snr3 = 3,
        npu_rx_snr4 = 4,
        npu_rx_snr5 = 5,
        npu_rx_snr6 = 6,
        npu_rx_snr7 = 7,
        npu_rx_snr8 = 8,
        pcs_err_cnt = 1,
        cw_before_correct_cnt = 2,
        cw_correct_cnt = 3,
        cw_uncorrect_cnt = 4,
        cdr_host_snr1 = 1,
        cdr_host_snr2 = 2,
        cdr_host_snr3 = 3,
        cdr_host_snr4 = 4,
        cdr_host_snr5 = 5,
        cdr_host_snr6 = 6,
        cdr_host_snr7 = 7,
        cdr_host_snr8 = 8,
        cdr_media_snr1 = 1,
        cdr_media_snr2 = 2,
        cdr_media_snr3 = 3,
        cdr_media_snr4 = 4,
        cdr_media_snr5 = 5,
        cdr_media_snr6 = 6,
        cdr_media_snr7 = 7,
        cdr_media_snr8 = 8,
        device_id = 0,
        tail = '\02\01'
    }
}

function TEST_hdk_cmd:test_get_linkdown_electric_info()
    -- 模拟ipmi返回
    local tmp = ipmi.request
    mock_ipmi(get_linkdown_electric_info)
    local packet_all = npu_imu_cmd.mock_get_linkdown_electric_info_cmd(1)
    lu.assertEquals(packet_all, 0)
    ipmi.request = tmp
end

local get_npu_hccs<const> = {
    comp_code = comp_code.Success,
    req_format = bs.new([[<<
        0xDB0700:3/unit:8,
        cmd:1/unit:8,
        lun:1/unit:8,
        para:1/unit:8,
        op_cmd:1/unit:8,
        op_fun:1/unit:8,
        offset:4/unit:8,
        data_length:4/unit:8,
        macro_id:1/unit:8,
        udie_id:1/unit:8,
        port_id:1/unit:8,
        pf_id:1/unit:8
    >>]]),
    resp_format = bs.new([[<<
        error_code:1/unit:8,
        opcode:2/little-unit:8,
        total_length:4/little-unit:8,
        length:4/little-unit:8,
        cmd_version:1/unit:8,

        # support_info 有7个字节,每个bit代表接下来结构体中对应顺序的属性是否支持,小端字节序
        reserved:43,
        half_height_support:1,
        snr_support:1,
        first_error_lane_support:1,
        error_count_support:1,
        retry_count_support:1,
        rx_bytes_support:1,
        rx_packets_support:1,
        tx_bytes_support:1,
        tx_packets_support:1,
        link_speed_support:1,
        link_lane_list_support:1,
        lane_mode_support:1,
        health_status_support:1,

        health_status:4/little-unit:8,
        lane_mode:4/little-unit:8,
        link_lane_list:4/little-unit:8,
        link_speed:4/little-unit:8,
        tx_packets:8/little-unit:8,
        tx_bytes:8/little-unit:8,
        rx_packets:8/little-unit:8,
        rx_bytes:8/little-unit:8,
        retry_count:8/little-unit:8,
        error_count:8/little-unit:8,
        first_error_lane:4/little-unit:8,
        snr1:4/little-unit:8,
        snr2:4/little-unit:8,
        snr3:4/little-unit:8,
        snr4:4/little-unit:8,
        half_height1:4/little-unit:8,
        half_height2:4/little-unit:8,
        half_height3:4/little-unit:8,
        half_height4:4/little-unit:8,
        tail/string
    >>]]),
    mock_resp = {
        error_code = 0,
        opcode = 0x06b5,
        total_length = 1,
        length = 1,
        cmd_version = 1,
        reserved = 43,
        half_height_support = 1,
        snr_support = 1,
        first_error_lane_support = 1,
        error_count_support = 1,
        retry_count_support = 1,
        rx_bytes_support = 1,
        rx_packets_support = 1,
        tx_bytes_support = 1,
        tx_packets_support = 1,
        link_speed_support = 1,
        link_lane_list_support = 1,
        lane_mode_support = 1,
        health_status_support = 1,
        health_status = 0,
        lane_mode = 0,
        link_lane_list = 1,
        link_speed = 0,
        tx_packets = 0,
        tx_bytes = 0,
        rx_packets = 1,
        rx_bytes = 2,
        retry_count = 3,
        error_count = 4,
        first_error_lane = 5,
        snr1 = 6,
        snr2 = 7,
        snr3 = 8,
        snr4 = 8,
        half_height1 = 6,
        half_height2 = 7,
        half_height3 = 8,
        half_height4 = 8,
        tail = ''
    }
}

function TEST_hdk_cmd:test_get_hccs_info_from_imu()
    local get_power_status = fructl.get_power_status
    fructl.get_power_status = function()
        return 'ON'
    end
    -- 模拟ipmi返回
    local tmp = ipmi.request
    mock_ipmi(get_npu_hccs)

    local hccs_info = npu_imu_cmd.get_hccs_info_from_imu(1, 0)
    lu.assertEquals(#hccs_info, 0)

    ipmi.request = tmp
    fructl.get_power_status = get_power_status
end

function TEST_hdk_cmd:test_get_npu_hccs()
    -- 模拟ipmi返回
    local tmp = ipmi.request
    mock_ipmi(get_npu_hccs)
    local ok, _ = npu_imu_cmd.mock_get_npu_hccs(1, 1)
    lu.assertEquals(ok, true)
    ipmi.request = tmp
end

local get_period_electric_info<const> = {
    comp_code = comp_code.Success,
    req_format = bs.new([[<<
        0xDB0700:3/unit:8,
        cmd:1/unit:8,
        lun:1/unit:8,
        request_parameter:1/unit:8,
        op_cmd:1/unit:8,
        op_fun:1/unit:8,
        offset:4/unit:8,
        data_length:4/unit:8
    >>]]),
    resp_format = bs.new([[<<
        error_code:1/unit:8,
        opcode:2/little-unit:8,
        total_length:4/little-unit:8,
        length:4/little-unit:8,
        cmd_version:1/unit:8,
        support_info:7/little-unit:8,
        rx_total_pkt_num:8/little-unit:8,
        rx_fec_err_pkt_num:8/little-unit:8,
        rx_bad_pkt_num:8/little-unit:8,
        tx_bad_pkt_num:8/little-unit:8,
        pcs_err_cnt:8/little-unit:8,
        fec_pre:8/little-unit:8,
        fec_success:8/little-unit:8,
        fec_fail:8/little-unit:8,
        npu_rx_snr1:4/little-unit:8,
        npu_rx_snr2:4/little-unit:8,
        npu_rx_snr3:4/little-unit:8,
        npu_rx_snr4:4/little-unit:8,
        npu_rx_snr5:4/little-unit:8,
        npu_rx_snr6:4/little-unit:8,
        npu_rx_snr7:4/little-unit:8,
        npu_rx_snr8:4/little-unit:8,
        cdr_host_snr1:4/little-unit:8,
        cdr_host_snr2:4/little-unit:8,
        cdr_host_snr3:4/little-unit:8,
        cdr_host_snr4:4/little-unit:8,
        cdr_host_snr5:4/little-unit:8,
        cdr_host_snr6:4/little-unit:8,
        cdr_host_snr7:4/little-unit:8,
        cdr_host_snr8:4/little-unit:8,
        cdr_media_snr1:4/little-unit:8,
        cdr_media_snr2:4/little-unit:8,
        cdr_media_snr3:4/little-unit:8,
        cdr_media_snr4:4/little-unit:8,
        cdr_media_snr5:4/little-unit:8,
        cdr_media_snr6:4/little-unit:8,
        cdr_media_snr7:4/little-unit:8,
        cdr_media_snr8:4/little-unit:8,
        tail/string
    >>]]),
    mock_resp = {
        error_code = 0,
        opcode = 0x06b5,
        total_length = 1,
        length = 1,
        cmd_version = 1,
        support_info = 1,
        rx_total_pkt_num = 1,
        rx_fec_err_pkt_num = 1,
        rx_bad_pkt_num = 1,
        tx_bad_pkt_num = 1,
        pcs_err_cnt = 5,
        fec_pre = 1,
        fec_success = 1,
        fec_fail = 1,
        npu_rx_snr1 = 1,
        npu_rx_snr2 = 1,
        npu_rx_snr3 = 1,
        npu_rx_snr4 = 1,
        npu_rx_snr5 = 1,
        npu_rx_snr6 = 1,
        npu_rx_snr7 = 1,
        npu_rx_snr8 = 1,
        cdr_host_snr1 = 1,
        cdr_host_snr2 = 1,
        cdr_host_snr3 = 1,
        cdr_host_snr4 = 1,
        cdr_host_snr5 = 1,
        cdr_host_snr6 = 1,
        cdr_host_snr7 = 1,
        cdr_host_snr8 = 1,
        cdr_media_snr1 = 1,
        cdr_media_snr2 = 1,
        cdr_media_snr3 = 1,
        cdr_media_snr4 = 1,
        cdr_media_snr5 = 1,
        cdr_media_snr6 = 1,
        cdr_media_snr7 = 1,
        cdr_media_snr8 = 1,
        tail = ''
    }
}

function TEST_hdk_cmd:test_get_period_electric_info()
    local get_power_status = fructl.get_power_status
    fructl.get_power_status = function()
        return 'ON'
    end
    -- 模拟ipmi返回
    local tmp = ipmi.request
    mock_ipmi(get_period_electric_info)

    local _, info = npu_imu_cmd.get_period_electric_info(1)
    lu.assertEquals(info.pcs_err_cnt, 5)

    ipmi.request = tmp
    fructl.get_power_status = get_power_status
end

function TEST_hdk_cmd:test_heartbeat_check()
    -- 模拟ipmi返回
    local tmp = ipmi.request
    ipmi.request = function() return 195 end
    local _, ret1 = npu_imu_cmd.heartbeat_check(1)
    lu.assertEquals(ret1, 195)

    ipmi.request = function() return 3 end
    local _, ret = npu_imu_cmd.heartbeat_check(1)
    lu.assertEquals(ret, 3)
    ipmi.request = tmp
end
local test_get_op_alarm_info<const> = {
    comp_code = comp_code.Success,
    req_format = bs.new([[<<
                0xDB0700:3/unit:8,
                cmd:1/unit:8,
                lun:1/unit:8,
                request_parameter:1/unit:8,
                op_cmd:1/unit:8,
                op_fun:1/unit:8,
                offset:4/unit:8,
                data_length:4/unit:8,
                request_type:1/unit:8,
                op_logical_id:1/unit:8
            >>]]),

    resp_format = bs.new([[<<
        error_code:1/unit:8,
        opcode:2/little-unit:8,
        total_length:4/little-unit:8,
        length:4/little-unit:8,
        cmd_version:1/unit:8,

        # support_info 有7个字节,每个bit代表接下来结构体中对应顺序的属性是否支持,小端字节序
        reserved:51,
        # 光链路严重告警是否支持，用于BMC告警
        optical_link_major_fault_supported:1,
        #光链路检测
        optical_link_fault_supported:1,
        #电链路检测
        electrical_link_fault_supported:1,
        #光模块诊断一般隐患,bmc不用于告警
        optical_module_minor_fault_supported:1,
        #光模块诊断严重故障,bmc用于告警
        optical_module_major_fault_supported:1,

        #光模块本体诊断故障
        optical_module_fault:4/little-unit:8,
        #光模块本体诊断预警
        optical_module_pre_fault:4/little-unit:8,
        #电链路检测告警
        electrical_link_fault:1/little-unit:8,
        #电链路检测预警
        electrical_link_pre_fault:1/little-unit:8,
        #光链路中度告警
        optical_link_minor_fault:1/little-unit:8,
        #光链路轻微告警
        optical_link_normal_fault:1/little-unit:8,
        tail/string
    >>]]),

    mock_resp = {
        error_code = 0,
        opcode  = 1,
        total_length = 1,
        length = 1,
        cmd_version = 1,
        reserved = 1,

        optical_link_major_fault_supported = 1,
        optical_link_fault_supported = 1,
        electrical_link_fault_supported = 1,
        optical_module_minor_fault_supported = 1,
        optical_module_major_fault_supported = 1,

        optical_module_fault = 1,
        optical_module_pre_fault = 1,
        electrical_link_fault = 1,
        electrical_link_pre_fault = 1,
        optical_link_minor_fault = 1,
        optical_link_normal_fault = 1,
        tail="1123"}
}

function TEST_hdk_cmd:test_get_op_alarm_info()
    local temp = ipmi.request
     mock_ipmi(test_get_op_alarm_info)
    local ret = npu_imu_cmd.get_op_alarm_info(1, 1, 'NPU_UB')
    lu.assertEquals(ret.HardwareFaultStatus, 1)
    ipmi.request = temp
end

function TEST_hdk_cmd:test_get_op_runtime_info_ub_vs_non_ub()
    local temp = ipmi.request
    ipmi.request = function()
        return 0, ''
    end
    pcall(function()
        return npu_imu_cmd.get_op_runtime_info(1, 1, 'NPU_UB')
    end)
    pcall(function()
        return npu_imu_cmd.get_op_runtime_info(1, 1, 'NPU_UBoE')
    end)
    pcall(function()
        return npu_imu_cmd.get_op_runtime_info(1, 1, 'NPU')
    end)
    lu.assertTrue(true)
    ipmi.request = temp
end

function TEST_hdk_cmd:test_get_op_alarm_info_ub_vs_non_ub()
    local temp = ipmi.request
    ipmi.request = function()
        return 0, ''
    end
    pcall(function()
        return npu_imu_cmd.get_op_alarm_info(1, 1, 'NPU_UB')
    end)
    pcall(function()
        return npu_imu_cmd.get_op_alarm_info(1, 1, 'NPU_UBoE')
    end)
    pcall(function()
        return npu_imu_cmd.get_op_alarm_info(1, 1, 'NPU')
    end)
    lu.assertTrue(true)
    ipmi.request = temp
end

function TEST_hdk_cmd:test_get_op_statistics_info_ub_vs_non_ub()
    local temp = ipmi.request
    ipmi.request = function()
        return 0, ''
    end
    pcall(function()
        return npu_imu_cmd.get_op_statistics_info(1, 1, 'NPU_UB')
    end)
    pcall(function()
        return npu_imu_cmd.get_op_statistics_info(1, 1, 'NPU')
    end)

    lu.assertTrue(true)

    ipmi.request = temp
end

function TEST_hdk_cmd:test_get_op_base_info_ub_vs_non_ub()
    local temp = ipmi.request
    ipmi.request = function()
        return 0, ''
    end
    pcall(function()
        return npu_imu_cmd.get_op_base_info(1, 1, 'NPU_UB')
    end)
    pcall(function()
        return npu_imu_cmd.get_op_base_info(1, 1, 'NPU')
    end)
    lu.assertTrue(true)
    ipmi.request = temp
end

function TEST_hdk_cmd:test_get_op_threshold_ub_vs_non_ub()
    local temp = ipmi.request
    ipmi.request = function()
        return 0, ''
    end
    local bus = c_object_manage.get_instance().bus
    pcall(function()
        return npu_imu_cmd.get_op_threshold and npu_imu_cmd.get_op_threshold(bus, 1, 1, 'NPU_UB')
    end)
    pcall(function()
        return npu_imu_cmd.get_op_threshold and npu_imu_cmd.get_op_threshold(bus, 1, 1, 'NPU')
    end)
    lu.assertTrue(true)
    ipmi.request = temp
end

function TEST_hdk_cmd:test_get_linkdown_optical_info_cmd_ub_vs_non_ub()
    -- 定义请求格式
    local linkdown_req_format = bs.new([[<<
        cmd:1/unit:8,
        lun:1/unit:8,
        request_parameter:1/unit:8,
        op_cmd:1/unit:8,
        op_fun:1/unit:8,
        offset:4/unit:8,
        data_length:4/unit:8,
        op_logical_id:1/unit:8
    >>]])

    -- 捕获请求参数
    local captured_data
    ipmi.request = function(...)
        local _, _, req = ...
        if req and req.Payload then
            local payload = linkdown_req_format:unpack(req.Payload)
            captured_data = payload
        end
        return 0, ''
    end

    -- 测试 NPU_UB model - data_length应该为1
    captured_data = nil
    pcall(function()
        return npu_imu_cmd.mock_get_linkdown_optical_info_cmd(1, 1, 'NPU_UB')
    end)
    if captured_data then
        lu.assertEquals(captured_data.data_length, 1)
    end

    -- 测试非NPU_UB model - data_length应该为0
    captured_data = nil
    pcall(function()
        return npu_imu_cmd.mock_get_linkdown_optical_info_cmd(1, 1, 'NPU')
    end)
    if captured_data then
        lu.assertEquals(captured_data.data_length, 0)
    end
    lu.assertTrue(true)
end