-- 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 dft_test = {}
local skynet = require 'skynet'
local mdb = require 'mc.mdb'
local ctx = require 'mc.context'
local utils = require 'mc.utils'

local ctx_new = ctx.new()
require 'frudata.json_types.Fru'
require 'frudata.json_types.Component'
require 'frudata.json_types.Components'
require 'frudata.json_types.FruDatas'

function dft_test:dft_eeprom(bus)
    -- 测试写保护
    local accessor = mdb.get_object(bus,
        '/bmc/kepler/Accessor/Accessor_2_0105', 'bmc.kepler.Accessor')
    accessor.Value = 1
    assert(accessor.Value == 1, 'actual: ' .. accessor.Value)
    accessor.Value = 0
    assert(accessor.Value == 0, 'actual: ' .. accessor.Value)

    -- 测试eeprom读写
    local eeprom_1_obj = mdb.get_object(bus, '/bmc/kepler/Chip/Eeprom/Eeprom_1_0105',
        'bmc.kepler.Chip.BlockIO')
    eeprom_1_obj:Write(ctx_new, 0x4000 - 8, { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 })
    local buffer = eeprom_1_obj:Read(ctx_new, 0x4000 - 8, 8)
    assert(utils.to_hex(buffer) == '55 55 55 55 55 55 55 55 ', 'actual: ' .. utils.to_hex(buffer))
    eeprom_1_obj:Write(ctx_new, 0, { 90, 139, 121, 54, 138, 66, 72, 209, 81, 220 })
    buffer = eeprom_1_obj:Read(ctx_new, 0, 10)
    assert(utils.to_hex(buffer) == '5A 8B 79 36 8A 42 48 D1 51 DC ', 'actual: ' .. utils.to_hex(buffer))
end

function dft_test:dft_test(bus)
    local dft = mdb.get_object(bus, '/bmc/kepler/Manufacture/SelfTest/DftEeprom/DftEeprom_12_0105',
        'bmc.kepler.Manufacture')

    local eeprom_2_obj = mdb.get_object(bus, '/bmc/kepler/Chip/Eeprom/Eeprom_2_0105',
        'bmc.kepler.Chip.BlockIO')
        
    eeprom_2_obj:Write(ctx_new, 0x4000 - 8, { 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 })

    dft:Start_PACKED(ctx_new)
    local result = dft:GetResult_PACKED(ctx_new)
    assert(result.Status == 'Succeed', 'actual: ' .. result.Status)

    local buffer = eeprom_2_obj:Read(ctx_new, 0x4000 - 8, 8)
    assert(utils.to_hex(buffer) == '50 55 55 55 55 55 55 55 ', 'actual: ' .. utils.to_hex(buffer))

    dft = mdb.get_object(bus, '/bmc/kepler/Manufacture/SelfTest/DftEeprom/DftEeprom_12_1_0105',
        'bmc.kepler.Manufacture')
    dft:Start_PACKED(ctx_new)
    result = dft:GetResult_PACKED(ctx_new)
    assert(result.Status == 'Succeed', 'actual: ' .. result.Status)
end

function dft_test:update(bus)
    local frudata = mdb.get_object(bus, '/bmc/kepler/Systems/1/FruDatas/FruData_3_0105',
        'bmc.kepler.FrudataService.Frudata')
    frudata:Update_PACKED(ctx_new, { 'ChassisSerialNumber', 'BoardSerialNumber', 'xxxx', 'MfgDate', 'BoardCustomInfo' },
        { 'aa', 'bb', 'ccc', '202ddf', 'Description=Manufactured Board,TS300-2280' })
    frudata = mdb.get_object(bus, '/bmc/kepler/Systems/1/FruDatas/FruData_3_0105',
        'bmc.kepler.Systems.FruData.Chassis')
    assert(frudata['ChassisSerialNumber'] == 'aa', 'actual: ' .. frudata['ChassisSerialNumber'])
    frudata = mdb.get_object(bus, '/bmc/kepler/Systems/1/FruDatas/FruData_3_0105',
        'bmc.kepler.Systems.FruData.Board')
    assert(frudata['BoardSerialNumber'] == 'bb', 'actual: ' .. frudata['BoardSerialNumber'])
    assert(frudata['MfgDate'] == '2023/10/23 Mon 00:00:00', 'actual: ' .. frudata['MfgDate'])
    assert(frudata['BoardCustomInfo'] == 'Description=Manufactured Board,TS300-2280',
        'actual: ' .. frudata['BoardCustomInfo'])

    -- 异常场景：特殊字符拦截
    frudata = mdb.get_object(bus, '/bmc/kepler/Systems/1/FruDatas/FruData_3_0105',
        'bmc.kepler.FrudataService.Frudata')
    frudata:Update_PACKED(ctx_new, { 'BoardSerialNumber' }, { 'aa\xff' })
    frudata = mdb.get_object(bus, '/bmc/kepler/Systems/1/FruDatas/FruData_3_0105',
        'bmc.kepler.Systems.FruData.Board')
    assert(frudata['BoardSerialNumber'] == 'bb', 'actual: ' .. frudata['BoardSerialNumber'])
end

function dft_test:update_health(bus)
    local frudata = mdb.get_object(bus, '/bmc/kepler/Systems/1/Components/Component_System_0105',
        'bmc.kepler.Systems.Component')
    -- 模拟Minor状态
    frudata:UpdateHealth_PACKED(ctx_new, 1)
    assert(frudata['Health'] == 1, 'actual: ' .. frudata['Health'])
    -- 恢复健康状态
    frudata:UpdateHealth_PACKED(ctx_new, 0)
    assert(frudata['Health'] == 0, 'actual: ' .. frudata['Health'])
    -- 设置异常值
    frudata:UpdateHealth_PACKED(ctx_new, 10)
    assert(frudata['Health'] == 0, 'actual: ' .. frudata['Health'])
end

function dft_test:set_product_assettag(bus)
    local frudata = mdb.get_object(bus, '/bmc/kepler/Systems/1/FruDatas/FruData_0_0105',
        'bmc.kepler.FrudataService.Frudata')
    frudata:SetProductAssetTag_PACKED(ctx_new, 0, "abc")
    local ok, _ = pcall(function()
        frudata:SetProductAssetTag_PACKED(ctx_new, 0, "ab\x11")
    end)
    assert(not ok)
    skynet.sleep(300)
    frudata = mdb.get_object(bus, '/bmc/kepler/Systems/1/FruDatas/FruData_0_0105',
        'bmc.kepler.Systems.FruData.Product')

    assert(frudata['AssetTag'] == 'abc', 'actual: ' .. frudata['AssetTag'])
end

function dft_test:set_sys_product_name(bus)
    local frudata = mdb.get_object(bus, '/bmc/kepler/Systems/1/FruDatas/FruData_0_0105',
        'bmc.kepler.FrudataService.Frudata')
    frudata:SetSysProductName_PACKED(ctx_new, 0, "abc")
    frudata:SetSysProductName_PACKED(ctx_new, 1, "abc")
    frudata:SetSysProductName_PACKED(ctx_new, 0, "ab\x11")

    skynet.sleep(300)
    frudata = mdb.get_object(bus, '/bmc/kepler/Systems/1/FruDatas/FruData_0_0105',
        'bmc.kepler.Systems.FruData.System')

    assert(frudata['SystemProductName'] == 'abc', 'actual: ' .. frudata['SystemProductName'])
end

function dft_test:serial_number(bus)
    local com_obj = mdb.get_object(bus, '/bmc/kepler/Systems/1/Components/Component_Sn_0105',
        'bmc.kepler.Systems.Component')
    assert(com_obj.PreviousSN == com_obj.SerialNumber, 'actual: ' .. com_obj.SerialNumber)
end

function dft_test:component_type(bus)
    local com_obj = mdb.get_object(bus, '/bmc/kepler/Systems/1/Components',
        'bmc.kepler.Systems.Components')
    local types = com_obj:GetComponentTypes_PACKED(ctx_new)
    assert(#types.ComponentTypes == 6, 'actual: ' .. #types.ComponentTypes)
end

function dft_test:update_pcbversion(bus)
    local fru_obj = mdb.get_object(bus, '/bmc/kepler/Systems/1/Frus/Fru_4_0105',
        'bmc.kepler.Systems.Fru')

    assert(fru_obj.PcbVersion == '.z', 'actual: ' .. fru_obj.PcbVersion)
end

function dft_test:recover(bus)
    local frudata = mdb.get_object(bus, '/bmc/kepler/Systems/1/FruDatas/FruData_0_0105',
        'bmc.kepler.FrudataService.Frudata')
    frudata:SetProductAssetTag_PACKED(ctx_new, 0, "abc")

    bus:call('bmc.kepler.frudata', '/bmc/kepler/frudata/MicroComponent', 'bmc.kepler.MicroComponent.ConfigManage',
        'Recover', 'a{ss}a{ss}', ctx_new, {})

    skynet.sleep(300)
    frudata = mdb.get_object(bus, '/bmc/kepler/Systems/1/FruDatas/FruData_0_0105',
        'bmc.kepler.Systems.FruData.Product')
    assert(frudata['AssetTag'] == 'abc', 'actual: ' .. frudata['AssetTag'])
end

function dft_test:get_frudata_list(bus)
    local frudatas = mdb.get_object(bus, '/bmc/kepler/Chassis/1/FruDatas', 'bmc.kepler.Chassis.FruDatas')
    local res = frudatas:GetFruDataList_PACKED(ctx_new):unpack()
    assert(#res == 7, 'actual: ' .. #res)  -- 有7个Frudata
end

function dft_test:dft_rpc_method_test(bus)
    self:component_type(bus)
    self:dft_eeprom(bus)
    self:dft_test(bus)
    self:update(bus)
    self:update_health(bus)
    self:set_product_assettag(bus)
    self:set_sys_product_name(bus)
    self:serial_number(bus)
    self:update_pcbversion(bus)
    self:recover(bus)
    self:get_frudata_list(bus)
end

return dft_test
