-- 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 mcu_upg_service = require 'mcu.upgrade.mcu_upg_service'
local fw_mgmt = require 'general_hardware.client'
local context = require 'mc.context'
local MCU_ENUMS = require 'mcu.enum.mcu_enums'
local smc_interface = require 'mcu.upgrade.smc_interface'
local smbus_interface = require 'mcu.upgrade.smbus_interface'
local upgrade_obj = require 'mcu.upgrade.upgrade_object'
local fructl = require 'mcu.upgrade.fructl_handler'

TestMcuUpgService = {}

local RET_OK <const> = 0
local RET_ERR <const> = -1

local upgrade_ret = RET_OK

local active_mode = 'None'
local active_status = 'None'
local mcu_obj = {}
mcu_obj.get_board_type = function ()
    return ''
end
mcu_obj.interface = smc_interface
upgrade_obj.ref_mcu = mcu_obj

local function stub_mcu_upg_instances(ret, is_need_active_vrd, process_ret, finish_ret)
    mcu_upg_service.mcu_upg_instances = {
        Vrd = {
            cfgs = {
                Firmware1 = {
                    name = 'Firmware1',
                    component_id = 23,
                    component_idex = 127
                }
            },
            upgrade_task = function ()
                return ret, is_need_active_vrd
            end,
            is_all_cfgs_processed = function ()
                return true
            end,
            poweron_unlock = function ()
            end
        }
    }

    fw_mgmt.UpdateServiceUpdateServiceProcessReply = function ()
        upgrade_ret = process_ret
    end

    fw_mgmt.UpdateServiceUpdateServiceFinishReply = function ()
        upgrade_ret = finish_ret
    end
end

local function stub_mcu_upg_active_instances()
    mcu_upg_service.mcu_upg_instances = {
        Mcu = {
            cfgs = {
                Firmware1 = {
                    name = 'Firmware1',
                    component_id = 29,
                    component_idex = 0
                }
            },
            upgrade_list = {upgrade_obj},
            poweron_unlock = function ()
            end,
            upgrade_finish = function ()
            end
        }
    }

    fw_mgmt.FirmwareActiveFirmwareActiveRegisterActiveAction = function (fw_mgmt, ctx, mcu_active_register_list)
        active_mode = mcu_active_register_list[4].Value
        active_status= mcu_active_register_list[5].Value
    end
end

-- 测试升级VRD部分失败，部分成功且需要生效场景
function TestMcuUpgService:test_on_upgrade_process1()
    stub_mcu_upg_instances(RET_ERR, true, RET_OK, RET_ERR)

    mcu_upg_service:on_upgrade_process(context.new(), 1, 'Vrd', '')
    lu.assertEquals(upgrade_ret, RET_OK)

    mcu_upg_service:on_upgrade_finish(context.new(), 1, 'Vrd')
    lu.assertEquals(upgrade_ret, RET_ERR)
end

-- 测试升级VRD部分失败，部分成功且不需要生效场景
function TestMcuUpgService:test_on_upgrade_process2()
    stub_mcu_upg_instances(RET_ERR, false, RET_ERR, RET_ERR)

    mcu_upg_service:on_upgrade_process(context.new(), 1, 'Vrd', '')
    lu.assertEquals(upgrade_ret, RET_ERR)
end

local function stub_cfg_nil()
    mcu_upg_service.mcu_upg_instances.Vrd.cfgs = {}
end

-- 测试cfg为空场景
function TestMcuUpgService:test_on_upgrade_process3()
    stub_mcu_upg_instances(RET_ERR, false, RET_ERR, RET_ERR)
    stub_cfg_nil()

    mcu_upg_service:on_upgrade_process(context.new(), 1, 'Vrd', '')
    lu.assertEquals(upgrade_ret, RET_ERR)
end

-- MCU查询生效模式和执行生效动作测试
function TestMcuUpgService:test_on_active_mode1()
    stub_mcu_upg_active_instances()
    upgrade_obj.ref_mcu.interface.blkwrite = function ()
        return true
    end

    local ret = pcall(function ()
        upgrade_obj.ref_mcu.interface:exec_valid_action()
    end)
    lu.assertEquals(ret, true)

    ret = pcall(function ()
        upgrade_obj:exec_valid_action()
    end)
    lu.assertEquals(ret, true)

    upgrade_obj.ref_mcu.interface.blkread = function ()
        return true, string.char(0)
    end
    lu.assertEquals(upgrade_obj:query_active_mode(), MCU_ENUMS.ACTIVE_IMMEDIATELY)

    upgrade_obj.ref_mcu.interface.blkread = function ()
        return false, string.char(1)
    end
    lu.assertEquals(upgrade_obj:query_active_mode(), MCU_ENUMS.ACTIVE_IMMEDIATELY)

    upgrade_obj.ref_mcu.interface.blkread = function ()
        return true, string.char(1)
    end
    lu.assertEquals(upgrade_obj:query_active_mode(), MCU_ENUMS.RESETAC)

    mcu_obj.get_board_type = function ()
        return 'ACU'
    end
    lu.assertEquals(upgrade_obj:query_active_mode(), MCU_ENUMS.ACTIVE_IMMEDIATELY)
end

-- smbus通道查询生效模式和执行生效动作测试
function TestMcuUpgService:test_on_active_mode2()
    stub_mcu_upg_active_instances()
    mcu_obj.smbus_interface = smbus_interface

    local ret = pcall(function ()
        upgrade_obj.ref_mcu.smbus_interface:exec_valid_action()
    end)
    lu.assertEquals(ret, true)

    local smbus_active_mode = upgrade_obj.ref_mcu.smbus_interface:query_active_mode()
    lu.assertEquals(smbus_active_mode, MCU_ENUMS.ACTIVE_IMMEDIATELY)

    mcu_obj.smbus_interface = nil
end

-- 升级结束后立即生效测试
function TestMcuUpgService:test_on_active_mode3()
    local active_ret = RET_ERR
    stub_mcu_upg_active_instances()
    upgrade_obj.exec_valid_action = function()
        active_ret = RET_OK
    end

    upgrade_obj.query_active_mode = function ()
        return MCU_ENUMS.ACTIVE_IMMEDIATELY
    end

    upgrade_obj:exec_valid_action_with_condition()
    lu.assertEquals(active_ret, RET_OK)
end

-- MCU生效测试1，无条件生效时不注册升级流程
function TestMcuUpgService:test_on_upgrade_finish1()
    stub_mcu_upg_active_instances()
    upgrade_obj.query_active_mode = function ()
        return MCU_ENUMS.ACTIVE_IMMEDIATELY
    end
    fructl.get_power_status = function ()
        return 'ON'
    end
    mcu_upg_service:on_upgrade_finish(context.new(), 1, 'Mcu')
    lu.assertEquals(active_mode, 'None')
end

-- MCU生效方式测试2, 上电时AC生效，注册状态为Ready
function TestMcuUpgService:test_on_upgrade_finish2()
    stub_mcu_upg_active_instances()
    upgrade_obj.query_active_mode = function ()
        return MCU_ENUMS.RESETAC
    end
    fructl.get_power_status = function ()
        return 'ON'
    end
    active_mode = 'None'
    mcu_upg_service:on_upgrade_finish(context.new(), 1, 'Mcu')
    lu.assertEquals(active_mode, 'ResetAC')
    lu.assertEquals(active_status, 'Ready')
end

-- MCU生效方式测试3, 下电时AC生效，注册状态为Ready
function TestMcuUpgService:test_on_upgrade_finish3()
    stub_mcu_upg_active_instances()
    upgrade_obj.query_active_mode = function ()
        return MCU_ENUMS.RESETAC
    end
    fructl.get_power_status = function ()
        return 'OFF'
    end
    active_mode = 'None'
    mcu_upg_service:on_upgrade_finish(context.new(), 1, 'Mcu')
    lu.assertEquals(active_mode, 'ResetAC')
    lu.assertEquals(active_status, 'Ready')
end

-- MCU/VRD生效测试
function TestMcuUpgService:test_on_active_process()
    local active_ret = RET_ERR
    fw_mgmt.FirmwareActiveFirmwareActiveActiveProcessReply = function ()
        active_ret = RET_OK
    end

    mcu_upg_service.mcu_upg_instances = {
        Mcu = {
            is_upgrading = false
        }
    }

    mcu_upg_service.mcu_active_list = {upgrade_obj}

    -- 仅支持VRD组件生效，且可以正常响应
    mcu_upg_service:on_active_process(context.new(), 1, 'VRD')
    lu.assertEquals(active_ret, RET_OK)

    -- 当前已存在VRD生效中, VRD不生效
    mcu_upg_service.is_upgrading = true
    mcu_upg_service.mcu_upg_instances = {
        Mcu = {
            is_upgrading = false
        }
    }
    mcu_upg_service:on_active_process(context.new(), 1, 'VRD')
    lu.assertEquals(active_ret, RET_OK)

    -- 当前已存在MCU升级流程,VRD不执行生效
    mcu_upg_service.is_upgrading = false
    mcu_upg_service.mcu_upg_instances = {
        Mcu = {
            is_upgrading = true
        }
    }
    mcu_upg_service:on_active_process(context.new(), 1, 'VRD')
    lu.assertEquals(active_ret, RET_OK)
end