-- 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 log = require 'mc.logging'
local class = require 'mc.class'
local bs = require 'mc.bitstring'
local json = require 'cjson'
local ctx = require 'mc.context'
local ipmi = require 'ipmi'
local enums = require 'ipmi.enums'

local channel_type = enums.ChannelType

local cc = ipmi.types.Cc
local PKG_IPMI = bs.new('<<_,_:2,DestNetFn:6,_:3/unit:8,Cmd,Payload/string>>')
-- 封装ipmi发送函数
local function ipmi_send_msg(bus, netfn, cmd, str)
    local ipmi_req = {
        DestNetFn = netfn,
        Cmd = cmd,
        Payload = str .. "\x00" -- 必须添加最后一位校验
    }
    local req = PKG_IPMI:pack(ipmi_req)
    local ctx_ipmi = json.encode({ChanType = channel_type.CT_LAN:value(), Instance = 1})
    local ok, rsp = pcall(bus.call, bus, 'bmc.kepler.ipmi_core', '/bmc/kepler/IpmiCore',
        'bmc.kepler.IpmiCore', 'Route', 'a{ss}ayay', ctx.get_context_or_default(), req, ctx_ipmi)
    return ok, rsp
end

local TestIpmi = class()

function TestIpmi:ctor(bus)
    self.bus = bus
end

local function test_SetIPMCConfiguration_length_invalid(bus, netfn, cmd, data)
    log:notice('====================== test_SetIPMCConfiguration_length_invalid ===========')
    data = data .. '\x05\x00\x00\x00\x00\x00'
    local ok, rsp = ipmi_send_msg(bus, netfn, cmd, data)
    lu.assertTrue(ok, rsp)
    lu.assertEquals(rsp:byte(1), cc.InvalidFieldRequest)
end

local function test_SetIPMCConfiguration_flag_offset(bus, netfn, cmd, data)
    log:notice('====================== test_SetIPMCConfiguration_flag_offset ===========')
    
    local data1 = data:sub(1, -3) .. '\x01\x00' .. '\x04\x00\x00\x00\x00'
    local ok, rsp = ipmi_send_msg(bus, netfn, cmd, data1)
    lu.assertTrue(ok, rsp)
    lu.assertEquals(rsp:byte(1), cc.InvalidFieldRequest)

    local data2 = data:sub(1, -3) .. '\x00\x01' .. '\x04\x00\x00\x00\x00'
    ok, rsp = ipmi_send_msg(bus, netfn, cmd, data2)
    lu.assertTrue(ok, rsp)
    lu.assertEquals(rsp:byte(1), cc.InvalidFieldRequest)
end

local function test_SetIPMCConfiguration_invalid_port(bus, netfn, cmd, data)
    log:notice('====================== test_SetIPMCConfiguration_invalid_port ===========')
    data = data .. '\x04\x01\x01\xdf\xfd'
    local ok, rsp = ipmi_send_msg(bus, netfn, cmd, data)
    lu.assertTrue(ok, rsp)
    lu.assertEquals(rsp:byte(1), cc.InvalidFieldRequest)
end

local function test_SetIPMCConfiguration_valid_port(bus, netfn, cmd, data)
    log:notice('====================== test_SetIPMCConfiguration_valid_port ===========')
    data = data .. '\x04\x01\x01\x00\x01'
    local ok, rsp = ipmi_send_msg(bus, netfn, cmd, data)
    lu.assertTrue(ok, rsp)
    lu.assertEquals(rsp:byte(1), cc.InvalidFieldRequest)
end

function TestIpmi:test_SetIPMCConfiguration()
    log:notice('====================== test_SetIPMCConfiguration ===========')
    local netfn = 0x30
    local cmd = 0x93
    local data = "\xdb\x07\x00\x05\x19\x00\x00"
    test_SetIPMCConfiguration_length_invalid(self.bus, netfn, cmd, data)
    test_SetIPMCConfiguration_flag_offset(self.bus, netfn, cmd, data)
    test_SetIPMCConfiguration_invalid_port(self.bus, netfn, cmd, data)
    test_SetIPMCConfiguration_valid_port(self.bus, netfn, cmd, data)
end

local function test_GetIPMCConfiguration_offset(bus, netfn, cmd, data)
    log:notice('====================== test_GetIPMCConfiguration_offset ===========')
    data = data .. '\x01\x04'
    local ok, rsp = ipmi_send_msg(bus, netfn, cmd, data)
    lu.assertTrue(ok, rsp)
    lu.assertEquals(rsp:byte(1), cc.InvalidFieldRequest)
end

local function test_GetIPMCConfiguration_2ports(bus, netfn, cmd, data)
    log:notice('====================== test_GetIPMCConfiguration_2ports ===========')
    data = data .. '\x00\x04'
    local ok, rsp = ipmi_send_msg(bus, netfn, cmd, data)
    lu.assertTrue(ok, rsp)
    lu.assertEquals(rsp, '\x00\xdb\x07\x00\x00\x00\xff\xff\xff')
end

local function test_GetIPMCConfiguration_4ports(bus, netfn, cmd, data)
    log:notice('====================== test_GetIPMCConfiguration_4ports ===========')
    data = data .. '\x00\x06'
    local ok, rsp = ipmi_send_msg(bus, netfn, cmd, data)
    lu.assertTrue(ok, rsp)
    lu.assertEquals(rsp, '\x00\xdb\x07\x00\x00\x00\xff\xff\xff\xff\xff')
end

function TestIpmi:test_GetIPMCConfiguration()
    log:notice('====================== test_GetIPMCConfiguration ===========')
    local netfn = 0x30
    local cmd = 0x93
    local data = "\xdb\x07\x00\x06\x19"
    test_GetIPMCConfiguration_offset(self.bus, netfn, cmd, data)
    test_GetIPMCConfiguration_2ports(self.bus, netfn, cmd, data)
    test_GetIPMCConfiguration_4ports(self.bus, netfn, cmd, data)
end

local function test_GetNetworkAdapterChipModel_LOM(bus, netfn, cmd, data)
    log:notice('====================== test_GetNetworkAdapterChipModel_LOM ===========')
    data = data .. '\x4A\x05\x0C\x30\x30\x30\x30\x3a\x31\x36\x3a\x30\x34\x2e\x30'
    local ok, rsp = ipmi_send_msg(bus, netfn, cmd, data)
    lu.assertTrue(ok, rsp)
    lu.assertEquals(rsp:byte(1), cc.Success)
    lu.assertEquals(rsp, "\x00\xdb\x07\x00\x4d\x65\x6c\x6c\x61\x6e\x6f\x78")
end

local function test_GetNetworkAdapterChipModel_OCP(bus, netfn, cmd, data)
    log:notice('====================== test_GetNetworkAdapterChipModel_OCP ===========')
    data = data .. '\x53\x05\x0C\x30\x30\x30\x30\x3a\x31\x36\x3a\x30\x34\x2e\x31'
    local ok, rsp = ipmi_send_msg(bus, netfn, cmd, data)
    lu.assertTrue(ok, rsp)
    lu.assertEquals(rsp:byte(1), cc.Success)
    lu.assertEquals(rsp, "\x00\xdb\x07\x00\x4d\x65\x6c\x6c\x61\x6e\x6f\x78")
end

function TestIpmi:test_GetNetworkAdapterChipModel()
    log:notice('====================== test_GetNetworkAdapterChipModel ===========')
    local netfn = 0x30
    local cmd = 0x93
    local data = "\xdb\x07\x00\x40"
    test_GetNetworkAdapterChipModel_LOM(self.bus, netfn, cmd, data)
    test_GetNetworkAdapterChipModel_OCP(self.bus, netfn, cmd, data)
end

return TestIpmi