-- 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 bs = require 'mc.bitstring'
local log = require 'mc.logging'
require 'skynet.manager'
require 'ipmi'
local bios_enum = require 'bios.types.enums'
local test_bios_common = require 'test_bios_common'
local test_smbios = {}

local function get_bios_all_properties(bus, name, system_id)
    return bus:call('bmc.kepler.bios', '/bmc/kepler/Systems/' .. system_id .. '/' .. name,
        'org.freedesktop.DBus.Properties', 'GetAll', 's', 'bmc.kepler.Systems.' .. name)
end

local function send_ipmi(data)
    return test_bios_common.send_ipmi(data)
end

local WRITE_SMBIOS_DATA_RSP = '<<ManufactureId:3/unit:8, RequiredOffset/string>>'
function test_smbios.test_smbios_ipmi(bus)
    log:info('================ test_smbios_ipmi start================')
    local ok, rsp = send_ipmi('0x30 0x92 0xdb 0x07 0x00 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00')
    assert(ok == true)
    if ok then
        local data = bs.new(WRITE_SMBIOS_DATA_RSP):unpack(rsp)
        assert(data.ManufactureId == 0x0007DB)
        assert(data.RequiredOffset == '')
    end

    local properties_bios = get_bios_all_properties(bus, 'Bios', 1)
    assert(properties_bios['SystemStartupState']:value() ==
               bios_enum.BiosStartupState.BIOS_STARTUP_SMBIOS_WRITE_PREPARE:value())
    local properties_smbios = get_bios_all_properties(bus, 'SmBios', 1)
    assert(properties_smbios['SmBiosStatus']:value() ==
               bios_enum.SmbiosWriteStage.SMBIOS_WRITE_PREPARE:value())

    ok, rsp = send_ipmi('0x30 0x92 0xdb 0x07 0x00 0x04 0x00 0x01 ' ..
        '0x0A 0x00 0x00 0x00 0x00 0x01 0x02 0x03 0x04')
    assert(ok == true)
    if ok then
        local data = bs.new(WRITE_SMBIOS_DATA_RSP):unpack(rsp)
        assert(data.ManufactureId == 0x0007DB)
        assert(data.RequiredOffset == '')
    end

    properties_bios = get_bios_all_properties(bus, 'Bios', 1)
    assert(properties_bios['SystemStartupState']:value() ==
               bios_enum.BiosStartupState.BIOS_STARTUP_SMBIOS_WRITE_DATA:value())
    properties_smbios = get_bios_all_properties(bus, 'SmBios', 1)
    assert(properties_smbios['SmBiosStatus']:value() ==
               bios_enum.SmbiosWriteStage.SMBIOS_WRITE_DATA:value())

    ok, rsp = send_ipmi('0x30 0x92 0xdb 0x07 0x00 0x04 0x00 0x03 0x0A')
    assert(ok == true)
    if ok then
        local data = bs.new(WRITE_SMBIOS_DATA_RSP):unpack(rsp)
        assert(data.ManufactureId == 0x0007DB)
        assert(data.RequiredOffset == '')
    end

    properties_bios = get_bios_all_properties(bus, 'Bios', 1)
    assert(properties_bios['SystemStartupState']:value() ==
               bios_enum.BiosStartupState.BIOS_STARTUP_SMBIOS_WRITE_FINISH:value())
    properties_smbios = get_bios_all_properties(bus, 'SmBios', 1)
    assert(properties_smbios['SmBiosStatus']:value() ==
               bios_enum.SmbiosWriteStage.SMBIOS_WRITE_FINISH:value())

    log:info('================ test_smbios_ipmi finish================')
end

function test_smbios.test_smbios_ipmi_fail(bus)
    log:info('================ test_smbios_ipmi_fail start================')
    local ok = send_ipmi('0x30 0x92 0x00 0x07 0xdb 0x04 0x00 0x06 0x00 0x00 0x00 0x00 0x00')
    assert(ok == false)

    ok = send_ipmi('0x30 0x92 0xd6 0x07 0x00 0x04 0x00 0x03 0x00 0x00 0x00 0x00 0x00')
    assert(ok == false)

    ok = send_ipmi('0x30 0x92 0xdb 0x07 0x00 0x04 0x01 0x00 0x00 0x00 0x00 0x00 0x00')
    assert(ok == false)

    ok = send_ipmi('0x30 0x92 0xdb 0x07 0x00 0x04 0x00 0x01 0x00 0x01 0x00 0x00 0x00')
    assert(ok == false)

    log:info('================ test_smbios_ipmi_fail finish================')
end

local GET_SMBIOS_INFO_RSP = '<<ManufactureId:3/unit:8, InformationLength, Information/string>>'
function test_smbios.test_smbios_get_info_ipmi(bus)
    log:info('================ test_smbios_get_info_ipmi start ================')

    --获取默认Version成功测试
    local ok, rsp = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5A 0x00 0x01')
    assert(ok == true)
    if ok then
        local data = bs.new(GET_SMBIOS_INFO_RSP):unpack(rsp)
        assert(data.ManufactureId == 0x0007DB)
    end

    --获取默认SKUNumber成功测试
    local ok, rsp = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5A 0x00 0x02')
    assert(ok == true)
    if ok then
        local data = bs.new(GET_SMBIOS_INFO_RSP):unpack(rsp)
        assert(data.ManufactureId == 0x0007DB)
    end

    --获取默认Family成功测试
    local ok, rsp = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5A 0x00 0x03')
    assert(ok == true)
    if ok then
        local data = bs.new(GET_SMBIOS_INFO_RSP):unpack(rsp)
        assert(data.ManufactureId == 0x0007DB)
    end

    --Type过大测试
    local ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5A 0x00 0x05')
    assert(not ok)

    --Type过小测试
    local ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5A 0x00 0x00')
    assert(not ok)

    --BiosId过大测试
    local ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5A 0x03 0x01')
    assert(not ok)

    log:info('================ test_smbios_get_info_ipmi finish ================')
end

local SET_SMBIOS_INFO_RSP = '<<ManufactureId:3/unit:8>>'
function test_smbios.test_smbios_set_info_ipmi(bus)
    log:info('================ test_smbios_set_info_ipmi start ================')

    --设置Version成功测试
    local ok, rsp = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5B 0x00 0x01 0x03 0x31 0x32 0x33')
    assert(ok == true)
    if ok then
        local data = bs.new(SET_SMBIOS_INFO_RSP):unpack(rsp)
        assert(data.ManufactureId == 0x0007DB)
    end

    --获取Version成功测试
    local ok, rsp = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5A 0x00 0x01')
    assert(ok == true)
    if ok then
        local data = bs.new(GET_SMBIOS_INFO_RSP):unpack(rsp)
        assert(data.ManufactureId == 0x0007DB)
        assert(data.InformationLength == 3)
        assert(data.Information == '123')
    end

    --设置SKUNumber成功测试
    local ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5B 0x00 0x02 0x03 0x71 0x72 0x75')
    assert(ok == true)

    --获取SKUNumber成功测试
    local ok, rsp = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5A 0x00 0x02')
    assert(ok == true)
    if ok then
        local data = bs.new(GET_SMBIOS_INFO_RSP):unpack(rsp)
        assert(data.ManufactureId == 0x0007DB)
        assert(data.InformationLength == 3)
        assert(data.Information == 'qru')
    end

    --设置Family成功测试
    local ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5B 0x00 0x03 0x05 0x23 0x24 0x25 0x5e 0x26')
    assert(ok == true)

    --获取Family成功测试
    local ok, rsp = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5A 0x00 0x03')
    assert(ok == true)
    if ok then
        local data = bs.new(GET_SMBIOS_INFO_RSP):unpack(rsp)
        assert(data.ManufactureId == 0x0007DB)
        assert(data.InformationLength == 5)
        assert(data.Information == '#$%^&')
    end

    log:info('================ test_smbios_set_info_ipmi finish ================')
end

function test_smbios.test_smbios_set_info_ipmi_fail(bus)
    log:info('================ test_smbios_set_info_ipmi_fail start ================')

    --非法InformationType设置测试（大于上限）
    local ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5B 0x00 0x04 0x5 0x31 0x32 0x33 0x34 0x35')
    assert(not ok)

    --非法InformationType设置测试（小于下限）
    local ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5B 0x00 0x00 0x1 0x31')
    assert(not ok)

    --长度与实际不一致（实际小于期望）
    local ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5B 0x00 0x01 0x26 0x31 0x32 0x33')
    assert(not ok)

    --长度与实际不一致（实际大于期望）
    local ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5B 0x00 0x02 0x02 0x31 0x32 0x33')
    assert(not ok)

    --设置的长度超上限
    local ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5B 0x00 0x02 0x4C 0x31 0x32 0x33')
    assert(not ok)

    --设置的长度为0
    local ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5B 0x00 0x02 0x00')
    assert(ok == true)

    --BiosId过大测试
    local ok = send_ipmi('0x30 0x92 0xDB 0x07 0x00 0x5B 0x05 0x02 0x03 0x31 0x32 0x33')
    assert(not ok)

    log:info('================ test_smbios_set_info_ipmi_fail finish ================')
end

function test_smbios.test_smbios_all(bus)
    log:info('================ test smbios start ================')
    test_smbios.test_smbios_get_info_ipmi(bus)
    test_smbios.test_smbios_set_info_ipmi(bus)
    test_smbios.test_smbios_set_info_ipmi_fail(bus)
    test_smbios.test_smbios_ipmi(bus)
    test_smbios.test_smbios_ipmi_fail(bus)
    log:info('================ test smbios complete ================')
end

return test_smbios