-- 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.


require 'skynet.manager'
local skynet = require 'skynet'
local log = require 'mc.logging'
local bs = require 'mc.bitstring'
local json = require 'cjson'
local enums = require 'ipmi.enums'
local lu = require 'luaunit'
local channel_type = enums.ChannelType

local props = require 'basic_cooling.define.cooling_properties'
local ipmi_obj = require 'basic_cooling.cooling_intf.cooling_ipmi'

local MANUFACTURE_ID<const> = 0x0007db
local SMART_MODE<const> = {
    ['EnergySaving'] = 0x10, -- 节能模式
    ['LowNoise'] = 0x11, -- 低噪声模式
    ['HighPerformance'] = 0x12, -- 高性能模式
    ['Custom'] = 0x13, -- 用户自定义模式
    ['LiquidCooling'] = 0x14 -- 液冷模式
}
local test_ipmi = {}

local function ipmi_test_tool(bus, ipmi_req, chan_type)
    local ipmi_package = bs.new('<<_,_:2,DestNetFn:6,_:3/unit:8,Cmd,Payload/string>>')
    local req = ipmi_package:pack(ipmi_req)
    if not chan_type then
        chan_type = channel_type.CT_ME:value()
    end
    local ctx = json.encode({ChanType = chan_type, Instance = 0})
    local ok, rsp = pcall(bus.call, bus, 'bmc.kepler.ipmi_core', '/bmc/kepler/IpmiCore',
        'bmc.kepler.IpmiCore', 'Route', 'a{ss}ayay', require'mc.context'.new(), req, ctx)
    return ok, rsp
end

local function test_get_total_fan_power(bus)
    local GET_FANS_POWER_RSP = '<<CompletionCode:1/unit:8, ManufactureId:3/unit:8, FanPower:4/unit:8, Unit:1/unit:8>>'
    local ok, rsp, data
    local get_total_fan_power_req = {
        DestNetFn = 0x30,
        Cmd = 0x93,
        Payload = '\xdb\x07\x00\x31\x08\x03\xff\00'
    }
    ok, rsp = ipmi_test_tool(bus, get_total_fan_power_req)
    assert(ok, 'Call ipmi msg get total fan power failed')
    data = bs.new(GET_FANS_POWER_RSP):unpack(rsp)
    lu.assertEquals(data.CompletionCode, 0)
end

local function test_fan_level_ctrl(bus)
    local GET_FAN_LEVEL_RSP = '<<CompletionCode, PicmgIdentifier:1/unit:8, LocalCtlFanLevel:1/unit:8>>'
    local SET_FAN_LEVEL_RSP = '<<CompletionCode, PicmgIdentifier:1/unit:8>>'
    local ok, rsp, data
    -- 获取手动模式风扇转速级别
    local get_fan_level_req = {
        DestNetFn = 0x2c,
        Cmd = 0x16,
        Payload = '\x00\x00\x00'
    }
    ok, rsp = ipmi_test_tool(bus, get_fan_level_req)
    assert(ok, 'Call ipmi msg get fan level failed')
    data = bs.new(GET_FAN_LEVEL_RSP):unpack(rsp)
    assert(data.PicmgIdentifier == 0 and data.LocalCtlFanLevel == 20)
    -- 设置手动模式风扇转速级别为60
    local set_fan_level_req = {
        DestNetFn = 0x2c,
        Cmd = 0x15,
        Payload = '\x00\x00\x3c\x00'
    }
    ok, rsp = ipmi_test_tool(bus, set_fan_level_req)
    assert(ok, 'Call ipmi msg set fan level failed')
    data = bs.new(SET_FAN_LEVEL_RSP):unpack(rsp)
    assert(data.PicmgIdentifier == 0)
    -- 校验手动模式风扇转速级别
    ok, rsp = ipmi_test_tool(bus, get_fan_level_req)
    assert(ok, 'Call ipmi msg get fan level failed')
    data = bs.new(GET_FAN_LEVEL_RSP):unpack(rsp)
    assert(data.PicmgIdentifier == 0 and data.LocalCtlFanLevel == 60)

    -- 恢复风扇转速级别为20
    set_fan_level_req = {
        DestNetFn = 0x2c,
        Cmd = 0x15,
        Payload = '\x00\x00\x14\x00'
    }
    ok, rsp = ipmi_test_tool(bus, set_fan_level_req)
    assert(ok, 'Call ipmi msg set fan level failed')
    data = bs.new(SET_FAN_LEVEL_RSP):unpack(rsp)
    assert(data.PicmgIdentifier == 0)
    -- 校验手动模式风扇转速级别
    ok, rsp = ipmi_test_tool(bus, get_fan_level_req)
    assert(ok, 'Call ipmi msg get fan level failed')
    data = bs.new(GET_FAN_LEVEL_RSP):unpack(rsp)
    assert(data.PicmgIdentifier == 0 and data.LocalCtlFanLevel == 20)
end

local function test_fan_manual_ctrl(bus)
    local SET_FAN_CTRL_MODE_RSP = '<<CompletionCode, ManufactureId:3/unit:8>>'
    local GET_FAN_CTRL_MODE_RSP = '<<CompletionCode, ManufactureId:3/unit:8, Mode:1/unit:8, Timeout/string>>'
    local ok, rsp
    -- 获取当前风扇控制模式
    local get_fan_ctrl_mode_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x02\x00'
    }
    ok, rsp = ipmi_test_tool(bus, get_fan_ctrl_mode_req)
    assert(ok, 'Call ipmi msg get fan ctrl mode failed')
    local data = bs.new(GET_FAN_CTRL_MODE_RSP):unpack(rsp)
    assert(data.ManufactureId == MANUFACTURE_ID and data.Mode == 2)

    -- 设置为手动模式，Timeout = 100s
    local set_fan_ctrl_mode_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x01\x01\x64\x00'
    }
    ok, rsp = ipmi_test_tool(bus, set_fan_ctrl_mode_req)
    assert(ok, 'Call ipmi msg set fan ctrl mode failed')

    data = bs.new(SET_FAN_CTRL_MODE_RSP):unpack(rsp)
    assert(data.ManufactureId == MANUFACTURE_ID)

    -- 获取当前风扇控制模式
    ok, rsp = ipmi_test_tool(bus, get_fan_ctrl_mode_req)
    assert(ok, 'Call ipmi msg get fan ctrl mode failed')
    data = bs.new(GET_FAN_CTRL_MODE_RSP):unpack(rsp)
    assert(data.ManufactureId == MANUFACTURE_ID and data.Mode == 1)
    assert(string.unpack('I', data.Timeout) <= 100)

    test_fan_level_ctrl(bus)
    skynet.sleep(1000)
    ok, rsp = ipmi_test_tool(bus, get_fan_ctrl_mode_req)
    assert(ok, 'Call ipmi msg get fan ctrl mode failed')

    data = bs.new(GET_FAN_CTRL_MODE_RSP):unpack(rsp)
    log:notice('%s %s', data.Mode, data.Timeout)
    assert(data.Mode == 1)
    local cur_timeout = string.unpack('I', data.Timeout)
    assert(cur_timeout <= 100, 'Cur: ' .. cur_timeout)

    -- 恢复风扇控制模式为自动模式
    set_fan_ctrl_mode_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x01\x00\x00'
    }
    ok, rsp = ipmi_test_tool(bus, set_fan_ctrl_mode_req)
    assert(ok, 'Call ipmi msg set fan ctrl mode failed')
    data = bs.new(SET_FAN_CTRL_MODE_RSP):unpack(rsp)
    assert(data.ManufactureId == MANUFACTURE_ID)

    -- 获取风扇模式应当为自动
    ok, rsp = ipmi_test_tool(bus, get_fan_ctrl_mode_req)
    assert(ok, 'Call ipmi msg get fan ctrl mode failed')
    data = bs.new(GET_FAN_CTRL_MODE_RSP):unpack(rsp)
    assert(data.ManufactureId == MANUFACTURE_ID and data.Mode == 0)
end

local function test_set_cooling_device_mixed_mode(bus)
    local SET_COOLING_DEVICE_CTRL_MODE_RSP = '<<CompletionCode, ManufactureId:3/unit:8>>'
    local GET_COOLING_DEVICE_CTRL_MODE_RSP = '<<CompletionCode, ManufactureId:3/unit:8, Mode:1/unit:8, Timeout/string>>'
    local ok, rsp
    -- 获取当前散热器件调速模式
    local get_cooling_device_ctrl_mode_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x24\x00\x00'
    }
    ok, rsp = ipmi_test_tool(bus, get_cooling_device_ctrl_mode_req)
    assert(ok, 'Call ipmi msg get cooling device ctrl mode failed')
    local data = bs.new(GET_COOLING_DEVICE_CTRL_MODE_RSP):unpack(rsp)
    assert(data.ManufactureId == MANUFACTURE_ID and data.Mode == 0)

    -- 设置散热器件调速模式为混合模式
    local set_cooling_device_ctrl_mode_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x23\x00\x02\x00'
    }
    ok, rsp = ipmi_test_tool(bus, set_cooling_device_ctrl_mode_req)
    assert(ok, 'Call ipmi msg set cooling device ctrl mode failed')
    data = bs.new(SET_COOLING_DEVICE_CTRL_MODE_RSP):unpack(rsp)
    assert(data.ManufactureId == MANUFACTURE_ID)

    -- 获取当前散热器件调速速模式仍为自动模式
    ok, rsp = ipmi_test_tool(bus, get_cooling_device_ctrl_mode_req)
    assert(ok, 'Call ipmi msg get cooling device ctrl mode failed')
    data = bs.new(GET_COOLING_DEVICE_CTRL_MODE_RSP):unpack(rsp)
    assert(data.ManufactureId == MANUFACTURE_ID and data.Mode == 2)
end

local function test_set_cooling_device_exp_mode(bus)
    local SET_COOLING_DEVICE_CTRL_MODE_RSP = '<<CompletionCode, ManufactureId:3/unit:8>>'
    local GET_COOLING_DEVICE_CTRL_MODE_RSP = '<<CompletionCode, ManufactureId:3/unit:8, Mode:1/unit:8, Timeout/string>>'
    local ok, rsp
    -- 获取当前散热器件调速模式
    local get_cooling_device_ctrl_mode_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x24\x00\x00'
    }
    ok, rsp = ipmi_test_tool(bus, get_cooling_device_ctrl_mode_req)
    assert(ok, 'Call ipmi msg get cooling device ctrl mode failed')
    local data = bs.new(GET_COOLING_DEVICE_CTRL_MODE_RSP):unpack(rsp)
    assert(data.ManufactureId == MANUFACTURE_ID and data.Mode == 2)

    -- 设置散热器件调速模式为异常模式
    local set_cooling_device_ctrl_mode_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x23\x00\x03\x00'
    }
    ok, rsp = ipmi_test_tool(bus, set_cooling_device_ctrl_mode_req)
    assert(ok, 'Call ipmi msg set cooling device ctrl mode failed')
    assert(rsp, '')

    -- 恢复散热器件调速模式为自动模式
    set_cooling_device_ctrl_mode_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x23\x00\x00\x00'
    }
    ok, rsp = ipmi_test_tool(bus, set_cooling_device_ctrl_mode_req)
    assert(ok, 'Call ipmi msg set cooling device ctrl mode failed')
    data = bs.new(SET_COOLING_DEVICE_CTRL_MODE_RSP):unpack(rsp)
    assert(data.ManufactureId == MANUFACTURE_ID)

    -- 获取散热器件调速模式应当为自动
    ok, rsp = ipmi_test_tool(bus, get_cooling_device_ctrl_mode_req)
    assert(ok, 'Call ipmi msg get cooling device ctrl mode failed')
    data = bs.new(GET_COOLING_DEVICE_CTRL_MODE_RSP):unpack(rsp)
    assert(data.ManufactureId == MANUFACTURE_ID and data.Mode == 0)
end

local function test_fan_mixed_ctrl(bus)
    local SET_FAN_CTRL_MODE_RSP = '<<CompletionCode, ManufactureId:3/unit:8>>'
    local GET_FAN_CTRL_MODE_RSP = '<<CompletionCode, ManufactureId:3/unit:8, Mode:1/unit:8, Timeout/string>>'
    local ok, rsp
    -- 获取当前风扇控制模式
    local get_fan_ctrl_mode_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x02\x00'
    }
    ok, rsp = ipmi_test_tool(bus, get_fan_ctrl_mode_req)
    assert(ok, 'Call ipmi msg get fan ctrl mode failed')
    local data = bs.new(GET_FAN_CTRL_MODE_RSP):unpack(rsp)
    assert(data.ManufactureId == MANUFACTURE_ID and data.Mode == 0)

    -- 设置风扇转速模式为混合模式失败
    local set_fan_ctrl_mode_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x01\x02\x00'
    }
    ok, rsp = ipmi_test_tool(bus, set_fan_ctrl_mode_req)
    assert(ok, 'Call ipmi msg set fan ctrl mode failed')
    data = bs.new(SET_FAN_CTRL_MODE_RSP):unpack(rsp)
    assert(data.ManufactureId == MANUFACTURE_ID)

    -- 获取当前风扇转速模式仍为自动模式
    ok, rsp = ipmi_test_tool(bus, get_fan_ctrl_mode_req)
    assert(ok, 'Call ipmi msg get fan ctrl mode failed')
    data = bs.new(GET_FAN_CTRL_MODE_RSP):unpack(rsp)
    assert(data.ManufactureId == MANUFACTURE_ID and data.Mode == 2)

    -- 恢复风扇调速模式为自动模式
    set_fan_ctrl_mode_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x01\x00\x00'
    }
    ok, rsp = ipmi_test_tool(bus, set_fan_ctrl_mode_req)
    assert(ok, 'Call ipmi msg set fan ctrl mode failed')
    data = bs.new(SET_FAN_CTRL_MODE_RSP):unpack(rsp)
    assert(data.ManufactureId == MANUFACTURE_ID)

    -- 获取风扇模式应当为自动
    ok, rsp = ipmi_test_tool(bus, get_fan_ctrl_mode_req)
    assert(ok, 'Call ipmi msg get fan ctrl mode failed')
    data = bs.new(GET_FAN_CTRL_MODE_RSP):unpack(rsp)
    assert(data.ManufactureId == MANUFACTURE_ID and data.Mode == 0)
end

local function test_fan_exp_ctrl(bus)
    local SET_FAN_CTRL_MODE_RSP = '<<CompletionCode, ManufactureId:3/unit:8>>'
    local GET_FAN_CTRL_MODE_RSP = '<<CompletionCode, ManufactureId:3/unit:8, Mode:1/unit:8, Timeout/string>>'
    local ok, rsp
    -- 获取当前风扇控制模式
    local get_fan_ctrl_mode_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x02\x00'
    }
    ok, rsp = ipmi_test_tool(bus, get_fan_ctrl_mode_req)
    assert(ok, 'Call ipmi msg get fan ctrl mode failed')
    local data = bs.new(GET_FAN_CTRL_MODE_RSP):unpack(rsp)
    assert(data.ManufactureId == MANUFACTURE_ID and data.Mode == 0)

    -- 设置风扇转速模式为异常模式
    local set_fan_ctrl_mode_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x01\x03\x00'
    }
    ok, rsp = ipmi_test_tool(bus, set_fan_ctrl_mode_req)
    assert(ok, 'Call ipmi msg set fan ctrl mode failed')
    assert(rsp, '')

    -- 恢复风扇调速模式为自动模式
    set_fan_ctrl_mode_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x01\x00\x00'
    }
    ok, rsp = ipmi_test_tool(bus, set_fan_ctrl_mode_req)
    assert(ok, 'Call ipmi msg set fan ctrl mode failed')
    data = bs.new(SET_FAN_CTRL_MODE_RSP):unpack(rsp)
    assert(data.ManufactureId == MANUFACTURE_ID)

    -- 获取风扇模式应当为自动
    ok, rsp = ipmi_test_tool(bus, get_fan_ctrl_mode_req)
    assert(ok, 'Call ipmi msg get fan ctrl mode failed')
    data = bs.new(GET_FAN_CTRL_MODE_RSP):unpack(rsp)
    assert(data.ManufactureId == MANUFACTURE_ID and data.Mode == 0)
end

-- Ipmi设置和查询扇热模式 
local function smart_cooling_mode_test(bus, c_config_obj)
    local ok, rsp
    local SET_SMART_COOLING_MODE_RSP = '<<CompletionCode, ManufactureId:3/unit:8>>'
    local GET_SMART_COOLING_MODE_RSP =
        '<<CompletionCode, ManufactureId:3/unit:8, PolicyOption:1/unit:8, PolicyValue:1/unit:8>>'

    local smart_cooling_mode = c_config_obj.SmartCoolingMode
    -- 设置散热模式为LowNoise
    local set_smart_cooling_mode_lownoise_req = {
        DestNetFn = 0x30,
        Cmd = 0x92,
        Payload = '\xdb\x07\x00\x13\x01\x11\x00'
    }
    ok, rsp = ipmi_test_tool(bus, set_smart_cooling_mode_lownoise_req)
    assert(ok, 'Call ipmi msg set smart cooling mode failed')
    local data = bs.new(SET_SMART_COOLING_MODE_RSP):unpack(rsp)
    assert(data.ManufactureId == MANUFACTURE_ID)
    -- 获取散热模式
    local get_smart_cooling_mode_req = {
        DestNetFn = 0x30,
        Cmd = 0x92,
        Payload = '\xdb\x07\x00\x14\x00'
    }

    ok, rsp = ipmi_test_tool(bus, get_smart_cooling_mode_req)
    assert(ok, 'Call ipmi msg get smart cooling mode failed')
    data = bs.new(GET_SMART_COOLING_MODE_RSP):unpack(rsp)
    assert(data.PolicyValue == 0x11)

    -- 恢复散热模式为初始值
    set_smart_cooling_mode_lownoise_req = {
        DestNetFn = 0x30,
        Cmd = 0x92,
        Payload = '\xdb\x07\x00\x13\x01' .. string.char(ipmi_obj.get_idx_by_mode(smart_cooling_mode)) .. '\x00'
    }
    ok, rsp = ipmi_test_tool(bus, set_smart_cooling_mode_lownoise_req)
    assert(ok, 'Call ipmi msg set smart cooling mode failed')
    data = bs.new(SET_SMART_COOLING_MODE_RSP):unpack(rsp)
    assert(data.ManufactureId == MANUFACTURE_ID)

    -- 获取散热模式
    ok, rsp = ipmi_test_tool(bus, get_smart_cooling_mode_req)
    assert(ok, 'Call ipmi msg get smart cooling mode failed')
    data = bs.new(GET_SMART_COOLING_MODE_RSP):unpack(rsp)
    assert(data.PolicyValue == SMART_MODE[smart_cooling_mode])
end

local function test_get_fan_props(bus, c_config_obj)
    local GET_FAN_PROPS_RSP = '<<CompletionCode:1/unit:8, PicmgIdentifier:1/unit:8, MinimalSpd:1/unit:8,' ..
        'MaximumSpd:1/unit:8, DefaultSpd:1/unit:8, DefaultData:1/unit:8>>'

    local ok, rsp, data
    -- 获取手动模式风扇转速级别
    local get_fan_props_req = {
        DestNetFn = 0x2c,
        Cmd = 0x14,
        Payload = '\x00\x00\x00'
    }
    ok, rsp = ipmi_test_tool(bus, get_fan_props_req)
    assert(ok, 'Call ipmi msg get fan props failed')
    data = bs.new(GET_FAN_PROPS_RSP):unpack(rsp)
    assert(data.MinimalSpd == string.byte(c_config_obj[props.LEVEL_RANGE], 1) and data.MaximumSpd == 100)
end

local function test_set_inlet_policy(bus, c_config_obj)
    local GET_INLET_POLICY_RSP = [=[<<CompletionCode:1/unit:8, ManufactureId:3/unit:8,]=] ..
        [=[ EnvArrLen:1/unit:8, EnvSpdArr/string>>]=]
    local SET_INLET_POLICY_RSP = [=[<<CompletionCode:1/unit:8, ManufactureId:3/unit:8>>]=]

    local ok, rsp, data
    -- 设置入风口调速策略
    local set_inlet_policy_req = {
        DestNetFn = 0x30,
        Cmd = 0x93,
        Payload = '\xdb\x07\x00\x45\x04\x14\x1e\x28\x32\x28\x32\x3c\x46\x50\x00'
    }
    ok, rsp = ipmi_test_tool(bus, set_inlet_policy_req)
    assert(ok, 'Call ipmi msg set inlet policy failed')
    data = bs.new(SET_INLET_POLICY_RSP):unpack(rsp)
    assert(data.CompletionCode == 0 and data.ManufactureId == MANUFACTURE_ID)

    -- 获取入风口调速策略
    local get_inlet_policy_req = {
        DestNetFn = 0x30,
        Cmd = 0x93,
        Payload = '\xdb\x07\x00\x46\x00'
    }
    ok, rsp = ipmi_test_tool(bus, get_inlet_policy_req)
    assert(ok, 'Call ipmi msg get inlet policy failed')
    data = bs.new(GET_INLET_POLICY_RSP):unpack(rsp)

    assert(data.EnvArrLen == 4, 'Actual: ' .. data.EnvArrLen)
    assert(#data.EnvSpdArr == data.EnvArrLen * 2 + 1, 'Actual: ' .. #data.EnvSpdArr .. '==' .. data.EnvArrLen * 2 + 1)

    local env_arr_len_bck = data.EnvArrLen
    local env_apd_arr_bck = data.EnvSpdArr

    local temp_arr_s = string.sub(env_apd_arr_bck, 1, env_arr_len_bck - 1)
    local spd_arr_s = string.sub(env_apd_arr_bck, env_arr_len_bck + 1, #env_apd_arr_bck - 1)
    -- 设置入风口调速策略
    set_inlet_policy_req = {
        DestNetFn = 0x30,
        Cmd = 0x93,
        Payload = '\xdb\x07\x00\x45' .. string.char(env_arr_len_bck - 1) .. temp_arr_s .. spd_arr_s .. '\x00'
    }
    ok, rsp = ipmi_test_tool(bus, set_inlet_policy_req)
    assert(ok, 'Call ipmi msg set inlet policy failed')
    data = bs.new(SET_INLET_POLICY_RSP):unpack(rsp)
    assert(data.CompletionCode == 0 and data.ManufactureId == MANUFACTURE_ID)

    -- 设置入风口调速策略
    set_inlet_policy_req = {
        DestNetFn = 0x30,
        Cmd = 0x93,
        Payload = '\xdb\x07\x00\x45' .. string.char(env_arr_len_bck) .. env_apd_arr_bck .. '\x00'
    }
    ok, rsp = ipmi_test_tool(bus, set_inlet_policy_req)
    assert(ok, 'Call ipmi msg set inlet policy failed')
    data = bs.new(SET_INLET_POLICY_RSP):unpack(rsp)
    assert(data.CompletionCode == 0 and data.ManufactureId == MANUFACTURE_ID)
end

local function test_op_init_level_in_start_up(bus)
    local GET_INIT_LEVEL_RSP = [=[<<CompletionCode:1/unit:8, ManufactureId:3/unit:8, Level:1/unit:8>>]=]
    local SET_INIT_LEVEL_RSP = [=[<<CompletionCode:1/unit:8, ManufactureId:3/unit:8>>]=]

    local ok, rsp, data
    -- 获取init level
    local get_init_level_req = {
        DestNetFn = 0x30,
        Cmd = 0x93,
        Payload = '\xdb\x07\x00\x5b\x1f\x00\x00\x00\x00'
    }
    ok, rsp = ipmi_test_tool(bus, get_init_level_req)
    assert(ok, 'Call ipmi msg get init level failed')
    data = bs.new(GET_INIT_LEVEL_RSP):unpack(rsp)
    assert(data.CompletionCode == 0 and data.ManufactureId == MANUFACTURE_ID and data.Level == 100)

    local init_level = data.Level

    -- 设置init level 为 init_level - 1
    local set_init_level_req = {
        DestNetFn = 0x30,
        Cmd = 0x93,
        Payload = '\xdb\x07\x00\x5a\x1f\x00\x01\x00' .. string.char(init_level - 1) .. '\x00'
    }
    ok, rsp = ipmi_test_tool(bus, set_init_level_req)
    assert(ok, 'Call ipmi msg set init level failed')
    data = bs.new(SET_INIT_LEVEL_RSP):unpack(rsp)
    assert(data.CompletionCode == 0 and data.ManufactureId == MANUFACTURE_ID)

    ok, rsp = ipmi_test_tool(bus, get_init_level_req)
    assert(ok, 'Call ipmi msg get init level failed')
    data = bs.new(GET_INIT_LEVEL_RSP):unpack(rsp)
    assert(data.CompletionCode == 0 and data.Level == init_level - 1)

    -- 将init level设置为回原来的值
    set_init_level_req = {
        DestNetFn = 0x30,
        Cmd = 0x93,
        Payload = '\xdb\x07\x00\x5a\x1f\x00\x01\x00' .. string.char(init_level) .. '\x00'
    }
    ok, rsp = ipmi_test_tool(bus, set_init_level_req)
    assert(ok, 'Call ipmi msg set init level failed')
    data = bs.new(SET_INIT_LEVEL_RSP):unpack(rsp)
    assert(data.CompletionCode == 0 and data.ManufactureId == MANUFACTURE_ID)
end

-- 获取当前风扇和泵的控制模式
local function test_get_cooling_device_mode(bus)
    local GET_COOLING_DEVIDE_MODE_RSP = [=[<<CompletionCode:1/unit:8, ManufactureId:3/unit:8, Mode:1/unit:8,]=] ..
        [=[ Timeout/string>>]=]
    local ok, rsp, data

    local get_cooling_fan_mode_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x24\x00\x00'
    }
    local get_cooling_pump_mode_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x24\x01\x00'
    }
    ok, rsp = ipmi_test_tool(bus, get_cooling_fan_mode_req)
    assert(ok, 'Call ipmi get cooling fan mode failed')
    data = bs.new(GET_COOLING_DEVIDE_MODE_RSP):unpack(rsp)
    assert(data.CompletionCode == 0 and data.ManufactureId == MANUFACTURE_ID)
    assert(data.Mode == 0, 'Actual: ' .. data.Mode)

    ok, rsp = ipmi_test_tool(bus, get_cooling_pump_mode_req)
    assert(ok, 'Call ipmi get cooling pump mode failed')
    data = bs.new(GET_COOLING_DEVIDE_MODE_RSP):unpack(rsp)
    assert(data.CompletionCode == 0 and data.ManufactureId == MANUFACTURE_ID)
    assert(data.Mode == 2, 'Actual: ' .. data.Mode)
end

-- 获取当前风扇和泵的转速
local function test_get_cooling_device_level(bus)
    local GET_COOLING_DEVIDE_LEVEL_RSP = [=[<<CompletionCode:1/unit:8, ManufactureId:3/unit:8, DeviceNum:1/unit:8,]=] ..
        [=[ Level/string>>]=]
    local ok, rsp, data
    -- 所有风扇的手动转速
    local get_all_cooling_fan_manual_level_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x26\x00\xff\x00\x00'
    }
    ok, rsp = ipmi_test_tool(bus, get_all_cooling_fan_manual_level_req)
    assert(ok, 'Call ipmi get all cooling fan manual level failed')
    data = bs.new(GET_COOLING_DEVIDE_LEVEL_RSP):unpack(rsp)
    assert(data.CompletionCode == 0 and data.ManufactureId == MANUFACTURE_ID)

    -- 所有风扇的实际转速
    local get_all_cooling_fan_actual_level_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x26\x00\xff\x01\x00'
    }
    ok, rsp = ipmi_test_tool(bus, get_all_cooling_fan_actual_level_req)
    assert(ok, 'Call ipmi get all cooling fan actual level failed')
    data = bs.new(GET_COOLING_DEVIDE_LEVEL_RSP):unpack(rsp)
    assert(data.CompletionCode == 0 and data.ManufactureId == MANUFACTURE_ID)

    -- 所有泵的手动转速
    local get_all_cooling_pump_manual_level_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x26\x01\xff\x00\x00'
    }
    ok, rsp = ipmi_test_tool(bus, get_all_cooling_pump_manual_level_req)
    assert(ok, 'Call ipmi get all cooling pump manual level failed')
    data = bs.new(GET_COOLING_DEVIDE_LEVEL_RSP):unpack(rsp)
    assert(data.CompletionCode == 0 and data.ManufactureId == MANUFACTURE_ID)

    -- 所有泵的实际转速
    local get_all_cooling_pump_actual_level_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x26\x01\xff\x01\x00'
    }
    ok, rsp = ipmi_test_tool(bus, get_all_cooling_pump_actual_level_req)
    assert(ok, 'Call ipmi get all cooling pump actual level failed')
    data = bs.new(GET_COOLING_DEVIDE_LEVEL_RSP):unpack(rsp)
    assert(data.CompletionCode == 0 and data.ManufactureId == MANUFACTURE_ID)
end

local function test_get_valve_opening_degree(bus)
    local GET_VALVE_OPEN_RSP = '<<CompletionCode:1/unit:8, ManufactureId:3/unit:8, Data:2/unit:8>>'
    local ok, rsp, data
    local get_valve_open_req = {
        DestNetFn = 0x30,
        Cmd = 0x93,
        Payload = '\xdb\x07\x00\x7d\x00\x01\x00'
    }
    ok, rsp = ipmi_test_tool(bus, get_valve_open_req)
    assert(ok, 'Call ipmi msg get total fan power failed')
    data = bs.new(GET_VALVE_OPEN_RSP):unpack(rsp)
    lu.assertEquals(data.Data, 0)
end

local function test_set_cooling_device_fan_mode(bus, c_config_obj)
    local SET_COOLING_DEVICE_MODE_RSP = [=[<<CompletionCode:1/unit:8, ManufactureId:3/unit:8>>]=]
    local ok, rsp, data
    -- 设置风扇手动模式为手动
    local set_fan_mode_manual_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x23\x00\x01\x64\x00'
    }
    ok, rsp = ipmi_test_tool(bus, set_fan_mode_manual_req)
    assert(ok, 'Call ipmi set cooling device(fan) mode to manual failed')
    data = bs.new(SET_COOLING_DEVICE_MODE_RSP):unpack(rsp)
    assert(data.CompletionCode == 0 and data.ManufactureId == MANUFACTURE_ID)
    assert(c_config_obj[props.CTL_MODE] == 'Manual')
    assert(c_config_obj[props.TIME_OUT] <= 0x64)

    -- 设置风扇模式为自动
    local set_fan_mode_auto_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x23\x00\x00\x00\x00'
    }
    ok, rsp = ipmi_test_tool(bus, set_fan_mode_auto_req)
    assert(ok, 'Call ipmi set cooling device(fan) mode to auto failed')
    data = bs.new(SET_COOLING_DEVICE_MODE_RSP):unpack(rsp)
    assert(data.CompletionCode == 0 and data.ManufactureId == MANUFACTURE_ID)
    assert(c_config_obj[props.CTL_MODE] == 'Auto')
end

-- 测试设置泵的手自切换和超时时间回退
local function test_set_cooling_device_pump_mode(bus, pumps_conf, c_pump_1, c_pump_2)
    local SET_COOLING_DEVICE_MODE_RSP = [=[<<CompletionCode:1/unit:8, ManufactureId:3/unit:8>>]=]
    local GET_COOLING_DEVIDE_MODE_RSP = [=[<<CompletionCode:1/unit:8, ManufactureId:3/unit:8, Mode:1/unit:8,]=] ..
        [=[ Timeout/string>>]=]
    local ok, rsp, data

    local get_cooling_pump_mode_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x24\x01\x00'
    }
    -- 设置泵模式为手动,超时时间为100秒
    local set_pump_mode_manual_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x23\x01\x01\x64\x00'
    }
    ok, rsp = ipmi_test_tool(bus, set_pump_mode_manual_req)
    assert(ok, 'Call ipmi set cooling device(pump) mode to manual failed')

    data = bs.new(SET_COOLING_DEVICE_MODE_RSP):unpack(rsp)
    assert(data.CompletionCode == 0 and data.ManufactureId == MANUFACTURE_ID)
    assert(pumps_conf[props.CTL_MODE] == 'Manual', 'Actual: ' .. pumps_conf[props.CTL_MODE])
    assert(pumps_conf[props.TIME_OUT] <= 0x64)
    assert(c_pump_1.Level == pumps_conf[props.CONF_MANUAL_LEVEL], -- 单个泵初始化手动转速属性应当与整体手动属性一致
        'Expect: ' .. pumps_conf[props.CONF_MANUAL_LEVEL] .. ', Actual: ' .. c_pump_1.Level)
    assert(c_pump_2.Level == pumps_conf[props.CONF_MANUAL_LEVEL],
        'Expect: ' .. pumps_conf[props.CONF_MANUAL_LEVEL] .. ', Actual: ' .. c_pump_2.Level)

    -- 获取当前泵的控制模式
    ok, rsp = ipmi_test_tool(bus, get_cooling_pump_mode_req)
    assert(ok, 'Call ipmi msg get pump ctrl mode failed')
    data = bs.new(GET_COOLING_DEVIDE_MODE_RSP):unpack(rsp)
    assert(data.ManufactureId == MANUFACTURE_ID and data.Mode == 1)

    -- 泵的超时时间应当自动回退
    ok, rsp = ipmi_test_tool(bus, get_cooling_pump_mode_req)
    assert(ok, 'Call ipmi msg get pump ctrl mode failed')

    data = bs.new(GET_COOLING_DEVIDE_MODE_RSP):unpack(rsp)
    local cur_timeout = string.unpack('I', data.Timeout)
    assert(cur_timeout <= 100, 'Cur: ' .. cur_timeout)

    -- 设置泵模式为自动
    local set_pump_mode_auto_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x23\x01\x00\x00\x00'
    }
    ok, rsp = ipmi_test_tool(bus, set_pump_mode_auto_req)
    assert(ok, 'Call ipmi set cooling device(pump) mode to auto failed')
    data = bs.new(SET_COOLING_DEVICE_MODE_RSP):unpack(rsp)
    assert(data.CompletionCode == 0 and data.ManufactureId == MANUFACTURE_ID)
    assert(pumps_conf[props.CTL_MODE] == 'Auto')
end

-- 测试设置风扇的全体和单个手动转速
local function test_set_cooling_device_fan_level(bus, c_fan_1, c_fan_2)
    local SET_COOLING_DEVICE_LEVEL_RSP = [=[<<CompletionCode:1/unit:8, ManufactureId:3/unit:8>>]=]
    local ok, rsp, data

    -- 设置风扇手动模式为手动
    local set_fan_mode_manual_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x23\x00\x01\x64\x00'
    }
    ok = ipmi_test_tool(bus, set_fan_mode_manual_req)
    assert(ok, 'Call ipmi set cooling device(fan) mode to manual failed')

    -- 设置全体风扇的手动转速为50%
    local set_all_fan_manual_level_50_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x25\x00\xff\x32\x00'
    }
    ok, rsp = ipmi_test_tool(bus, set_all_fan_manual_level_50_req)
    assert(ok, 'Call ipmi set cooling device(all fan) level to 50 failed')
    data = bs.new(SET_COOLING_DEVICE_LEVEL_RSP):unpack(rsp)
    assert(data.CompletionCode == 0 and data.ManufactureId == MANUFACTURE_ID)
    assert(c_fan_1.Level == 50, 'expect: 50' .. ', actual: ' .. c_fan_1.Level)
    assert(c_fan_2.Level == 50, 'expect: 50' .. ', actual: ' .. c_fan_2.Level)

    -- 设置风扇1的转速为30%
    local set_fan1_manual_level_30_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x25\x00\x01\x1e\x00'
    }
    ok, rsp = ipmi_test_tool(bus, set_fan1_manual_level_30_req)
    assert(ok, 'Call ipmi set cooling device(fan1) level to 30 failed')
    data = bs.new(SET_COOLING_DEVICE_LEVEL_RSP):unpack(rsp)
    assert(data.CompletionCode == 0 and data.ManufactureId == MANUFACTURE_ID)
    assert(c_fan_1.Level == 0x1e, 'expect: 30' .. ', actual' .. c_fan_1.Level)

    -- 设置风扇2的转速为40%
    local set_fan2_manual_level_40_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x25\x00\x02\x28\x00'
    }
    ok, rsp = ipmi_test_tool(bus, set_fan2_manual_level_40_req)
    assert(ok, 'Call ipmi set cooling device(pump2) level to 40 failed')
    data = bs.new(SET_COOLING_DEVICE_LEVEL_RSP):unpack(rsp)
    assert(data.CompletionCode == 0 and data.ManufactureId == MANUFACTURE_ID)
    assert(c_fan_2.Level == 0x28, 'expect: 40' .. ', actual' .. c_fan_2.Level)
end

-- 测试ipmi设置泵的全体和单个手动转速
local function test_set_cooling_device_pump_level(bus, pumps_conf, c_pump_1, c_pump_2)
    local SET_COOLING_DEVICE_LEVEL_RSP = [=[<<CompletionCode:1/unit:8, ManufactureId:3/unit:8>>]=]
    local SET_COOLING_DEVICE_MODE_RSP = [=[<<CompletionCode:1/unit:8, ManufactureId:3/unit:8>>]=]
    local ok, rsp, data
    -- 设置全体泵的转速为50%
    local set_all_pump_manual_level_50_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x25\x01\xff\x32\x00'
    }
    ok, rsp = ipmi_test_tool(bus, set_all_pump_manual_level_50_req)
    assert(ok, 'Call ipmi set cooling device(all pump) level to 50 failed')
    data = bs.new(SET_COOLING_DEVICE_LEVEL_RSP):unpack(rsp)
    assert(data.CompletionCode == 0 and data.ManufactureId == MANUFACTURE_ID)
    assert(c_pump_1.Level == 50, 'expect: 50' .. ', actual: ' .. c_pump_1.Level)
    assert(c_pump_2.Level == 50, 'expect: 50' .. ', actual: ' .. c_pump_2.Level)

    -- 设置泵1的转速为30%
    local set_pump1_manual_level_30_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x25\x01\x01\x1e\x00'
    }
    ok, rsp = ipmi_test_tool(bus, set_pump1_manual_level_30_req)
    assert(ok, 'Call ipmi set cooling device(pump1) level to 30 failed')
    data = bs.new(SET_COOLING_DEVICE_LEVEL_RSP):unpack(rsp)
    assert(data.CompletionCode == 0 and data.ManufactureId == MANUFACTURE_ID)
    assert(c_pump_1.Level == 0x1e, 'expect: 30' .. ', actual' .. c_pump_1.Level)

    -- 设置泵2的转速为40%
    local set_pump2_manual_level_40_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x25\x01\x02\x28\x00'
    }
    ok, rsp = ipmi_test_tool(bus, set_pump2_manual_level_40_req)
    assert(ok, 'Call ipmi set cooling device(pump2) level to 40 failed')
    data = bs.new(SET_COOLING_DEVICE_LEVEL_RSP):unpack(rsp)
    assert(data.CompletionCode == 0 and data.ManufactureId == MANUFACTURE_ID)
    assert(c_pump_2.Level == 0x28, 'expect: 40' .. ', actual' .. c_pump_2.Level)

    -- 设置泵模式为手动
    local set_pump_mode_manual_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x23\x01\x01\x64\x00'
    }
    -- 切换模式应当设置每个泵的手动转速为config的整体转速
    ok, rsp = ipmi_test_tool(bus, set_pump_mode_manual_req)
    assert(ok, 'Call ipmi set cooling device(pump) mode to manual failed')
    data = bs.new(SET_COOLING_DEVICE_MODE_RSP):unpack(rsp)
    assert(data.CompletionCode == 0 and data.ManufactureId == MANUFACTURE_ID)
    assert(pumps_conf[props.TIME_OUT] <= 0x64)
    assert(c_pump_1.Level == pumps_conf[props.CONF_MANUAL_LEVEL],
        'Expect: ' .. pumps_conf[props.CONF_MANUAL_LEVEL] .. ', Actual: ' .. c_pump_1.Level)
    assert(c_pump_2.Level == pumps_conf[props.CONF_MANUAL_LEVEL],
        'Expect: ' .. pumps_conf[props.CONF_MANUAL_LEVEL] .. ', Actual: ' .. c_pump_2.Level)
end

-- 统一恢复ipmi设置的风扇和泵模式为自动
local function test_set_manual_mode_exist(bus, fans_conf, pumps_conf)
    local SET_COOLING_DEVICE_MODE_RSP = [=[<<CompletionCode:1/unit:8, ManufactureId:3/unit:8>>]=]
    -- 设置风扇模式为自动
    local set_fan_mode_auto_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x23\x00\x00\x00\x00'
    }
    local ok, rsp = ipmi_test_tool(bus, set_fan_mode_auto_req)
    assert(ok, 'Call ipmi set cooling device(pump) mode to auto failed')
    local data = bs.new(SET_COOLING_DEVICE_MODE_RSP):unpack(rsp)
    assert(data.CompletionCode == 0 and data.ManufactureId == MANUFACTURE_ID)
    assert(fans_conf[props.CTL_MODE] == 'Auto')

    -- 设置泵模式为自动
    local set_pump_mode_auto_req = {
        DestNetFn = 0x30,
        Cmd = 0x91,
        Payload = '\xdb\x07\x00\x23\x01\x00\x00\x00'
    }
    ok, rsp = ipmi_test_tool(bus, set_pump_mode_auto_req)
    assert(ok, 'Call ipmi set cooling device(pump) mode to auto failed')
    data = bs.new(SET_COOLING_DEVICE_MODE_RSP):unpack(rsp)
    assert(data.CompletionCode == 0 and data.ManufactureId == MANUFACTURE_ID)
    assert(pumps_conf[props.CTL_MODE] == 'Auto')
end

function test_ipmi.main(bus, c_config_obj, pumps_conf, c_fan_1, c_fan_2, c_pump_1, c_pump_2)
    log:notice('================ test ipmi start ================')
    test_get_total_fan_power(bus)
    test_get_valve_opening_degree(bus)

    test_fan_manual_ctrl(bus)
    test_fan_mixed_ctrl(bus)
    test_fan_exp_ctrl(bus)
    smart_cooling_mode_test(bus, c_config_obj)
    test_get_fan_props(bus, c_config_obj)
    test_set_inlet_policy(bus, c_config_obj)
    test_op_init_level_in_start_up(bus)
    test_get_cooling_device_mode(bus)
    test_set_cooling_device_mixed_mode(bus)
    test_set_cooling_device_exp_mode(bus)
    test_get_cooling_device_level(bus)

    test_set_cooling_device_fan_mode(bus, c_config_obj)
    test_set_cooling_device_fan_level(bus, c_fan_1, c_fan_2)
    test_set_cooling_device_pump_mode(bus, pumps_conf, c_pump_1, c_pump_2)
    test_set_cooling_device_pump_level(bus, pumps_conf, c_pump_1, c_pump_2)

    test_set_manual_mode_exist(bus, c_config_obj, pumps_conf)
    log:notice('================ test ipmi complete ================')
end

return test_ipmi