-- 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 bdf_service = require 'service.bdf_service'
local bios_service = require 'service.bios_service'
local bios_factory = require 'factory.bios_factory'
local prop_def = require 'macros.property_def'
local ipmi = require 'ipmi'
local comp_code = ipmi.types.Cc

local open_db = require 'bios.db'
local test_common = require 'test_common.utils'
local bus = test_common.dbus_launch('../.dbus', nil, true)

TestBiosWriteBdf = {}

local function construct_db()
    local ok, datas = pcall(require, 'bios.datas')
    if not ok then
        -- 如果没有datas配置，证明当前组件不需要datas，仅打开数据库
        datas = nil
    end
    local db = open_db(':memory:', datas)
    return db
end

local function register_bean()
    local bdf_ser = bdf_service.get_instance()
    local bios_ser = bios_service.get_instance(bus, construct_db())
    bios_ser:add_object({
        get_system_id = function()
            return 1
        end,
        register_mdb_objects = function (obj)
        end,
        unregister_mdb_objects = function (obj)
        end,
        PcieCardBDF = '',
        PcieDiskBDF = '',
        OCPCardBDF = '',
        Slot = 1
    })

    bios_factory.register_bean('bios_service', bios_ser)
    bios_factory.register_bean('bdf_service', bdf_ser)
end

function TestBiosWriteBdf:test_validate()
    register_bean()
    local bdf_ser = bdf_service.get_instance()
    local err_code, maun_id = bdf_ser:bios_write_bdf_to_bmc(nil, nil)
    assert(err_code == comp_code.InvalidFieldRequest)
    assert(maun_id == 0x0007DB)

    local ctx = {}
    local req = {}

    ctx.ChanType = 3
    req.MaxFrame = 1
    req.CurrentFrame = 1
    err_code, maun_id = bdf_ser:bios_write_bdf_to_bmc(nil, nil)
    assert(err_code == comp_code.InvalidFieldRequest)
    assert(maun_id == 0x0007DB)
end

function TestBiosWriteBdf:test_validate2()
    local bdf_ser = bdf_service.get_instance()
    local bios_ser = bios_service.get_instance(bus)
    local ctx = {}
    ctx.ChanType = 3
    ctx.chan_num = 15

    local req = {}
    req.ParameterSelector = prop_def.BIOS_IPMI_CMD_PCIEDISK
    req.MaxFrame = 0x1F
    req.CurrentFrame = 0x00
    req.PCIeSlotNumber = 0x01

    local err_code, maun_id = bdf_ser:bios_write_bdf_to_bmc(req, ctx)
    assert(err_code == comp_code.CommandNotAvailable)
    assert(maun_id == 0x0007DB)

    req.ParameterSelector = prop_def.BIOS_IPMI_CMD_PCIECARD
    req.MaxFrame = 0x00
    req.CurrentFrame = 0x00
    err_code, maun_id = bdf_ser:bios_write_bdf_to_bmc(req, ctx)
    local stage = bios_ser:get_bios_prop(prop_def.PROPERTY_BIOS_BOOT_STAGE)
    assert(err_code == comp_code.CommandNotAvailable)
    assert(maun_id == 0x0007DB)
    assert(stage == prop_def.BIOS_BOOT_STAGE_PCIE_INFO_REPORTED)
end

function TestBiosWriteBdf:test_write_one_frame()
    local bdf_ser = bdf_service.get_instance()
    local bios_ser = bios_service.get_instance(bus)
    local ctx = {}
    ctx.ChanType = 3
    ctx.chan_num = 15

    local req = {}
    req.ParameterSelector = prop_def.BIOS_IPMI_CMD_PCIECARD
    req.MaxFrame = 0x01
    req.CurrentFrame = 0x01
    req.PCIeSlotNumber = 0x01

    local err_code, maun_id = bdf_ser:bios_write_bdf_to_bmc(req, ctx)
    assert(err_code == comp_code.CommandNotAvailable)
    assert(maun_id == 0x0007DB)

    req.BdfData = '123456'
    req.ParameterSelector = 0xFF
    err_code, maun_id = bdf_ser:bios_write_bdf_to_bmc(req, ctx)
    assert(err_code == comp_code.CommandNotAvailable)
    assert(maun_id == 0x0007DB)

    req.ParameterSelector = prop_def.BIOS_IPMI_CMD_PCIECARD
    err_code, maun_id = bdf_ser:bios_write_bdf_to_bmc(req, ctx)
    local bdf_data = bios_ser:get_bios_prop(prop_def.PROPERTY_BIOS_PCIECARD_BDF)
    assert(err_code == comp_code.Success)
    assert(maun_id == 0x0007DB)
    assert(bdf_data == '123456')
end

function TestBiosWriteBdf:test_write_first_bdf_frame()
    local bdf_ser = bdf_service.get_instance()
    local ctx = {}
    ctx.ChanType = 3
    ctx.chan_num = 15

    local req = {}
    req.ParameterSelector = prop_def.BIOS_IPMI_CMD_PCIECARD
    req.MaxFrame = 0x01
    req.CurrentFrame = 0x02
    req.PCIeSlotNumber = 0x01
    req.BdfData = '12345'

    local err_code, maun_id = bdf_ser:bios_write_bdf_to_bmc(req, ctx)
    assert(err_code == comp_code.CommandNotAvailable)
    assert(maun_id == 0x0007DB)

    req.MaxFrame = 0x0F
    req.CurrentFrame = 0x01
    req.BdfData = '1234'
    err_code, maun_id = bdf_ser:bios_write_bdf_to_bmc(req, ctx)
    assert(err_code == comp_code.CommandNotAvailable)
    assert(maun_id == 0x0007DB)

    req.BdfData = '12345'
    err_code, maun_id = bdf_ser:bios_write_bdf_to_bmc(req, ctx)
    assert(err_code == comp_code.Success)
    assert(maun_id == 0x0007DB)
    assert(bdf_ser.data_opts[1].data_buf == '12345')
    assert(bdf_ser.data_opts[1].data_offset == 5)
    assert(bdf_ser.data_opts[1].data_len == 1)
end

local function send_first_frame()
    local bdf_ser = bdf_service.get_instance()
    local ctx = {}
    ctx.ChanType = 3
    ctx.chan_num = 15

    local req = {}
    req.ParameterSelector = prop_def.BIOS_IPMI_CMD_PCIECARD
    req.MaxFrame = 0x0F
    req.CurrentFrame = 0x01
    req.PCIeSlotNumber = 0x01
    req.BdfData = '12345'
    bdf_ser:bios_write_bdf_to_bmc(req, ctx)
end

function TestBiosWriteBdf:test_write_data_bdf_frame()
    local bdf_ser = bdf_service.get_instance()
    local ctx = {}
    ctx.ChanType = 3
    ctx.chan_num = 15

    local req = {}
    req.ParameterSelector = prop_def.BIOS_IPMI_CMD_PCIECARD
    req.MaxFrame = 0x0F
    req.CurrentFrame = 0x03
    req.PCIeSlotNumber = 0x01
    req.BdfData = '12345'

    local err_code, maun_id = bdf_ser:bios_write_bdf_to_bmc(req, ctx)
    assert(err_code == comp_code.CommandNotAvailable)
    assert(maun_id == 0x0007DB)

    send_first_frame()
    err_code, maun_id = bdf_ser:bios_write_bdf_to_bmc(req, ctx)
    assert(err_code == prop_def.BIOS_ERR_WRONG_OFFSET)
    assert(maun_id == 0x0007DB)

    req.CurrentFrame = 0x02
    req.BdfData = '1234'
    err_code, maun_id = bdf_ser:bios_write_bdf_to_bmc(req, ctx)
    assert(err_code == comp_code.CommandNotAvailable)
    assert(maun_id == 0x0007DB)

    req.BdfData = '12345'
    err_code, maun_id = bdf_ser:bios_write_bdf_to_bmc(req, ctx)
    assert(err_code == comp_code.Success)
    assert(maun_id == 0x0007DB)
    assert(bdf_ser.data_opts[1].data_buf == '1234512345')
    assert(bdf_ser.data_opts[1].data_offset == 10)
    assert(bdf_ser.data_opts[1].data_len == 2)
end

local function send_second_frame()
    local bdf_ser = bdf_service.get_instance()
    local ctx = {}
    ctx.ChanType = 3
    ctx.chan_num = 15

    local req = {}
    req.ParameterSelector = prop_def.BIOS_IPMI_CMD_PCIECARD
    req.MaxFrame = 0x0F
    req.CurrentFrame = 0x02
    req.PCIeSlotNumber = 0x01
    req.BdfData = '12345'

    send_first_frame()
    bdf_ser:bios_write_bdf_to_bmc(req, ctx)
end

function TestBiosWriteBdf:test_write_finish_bdf_frame()
    local bdf_ser = bdf_service.get_instance()
    local bios_ser = bios_service.get_instance(bus)
    local ctx = {}
    ctx.ChanType = 3
    ctx.chan_num = 15

    local req = {}
    req.ParameterSelector = prop_def.BIOS_IPMI_CMD_PCIECARD
    req.MaxFrame = 0x03
    req.CurrentFrame = 0x03
    req.PCIeSlotNumber = 0x01
    req.BdfData = '12345'

    send_second_frame()
    req.ParameterSelector = 0xFF
    local err_code, maun_id = bdf_ser:bios_write_bdf_to_bmc(req, ctx)
    assert(err_code == comp_code.CommandNotAvailable)
    assert(maun_id == 0x0007DB)

    send_second_frame()
    req.ParameterSelector = prop_def.BIOS_IPMI_CMD_PCIECARD
    err_code, maun_id = bdf_ser:bios_write_bdf_to_bmc(req, ctx)
    local bdf_data = bios_ser:get_bios_prop(prop_def.PROPERTY_BIOS_PCIECARD_BDF)
    assert(err_code == comp_code.Success)
    assert(maun_id == 0x0007DB)
    assert(bdf_data == '123451234512345')
end
