-- 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 upgrade_service_handle = require 'mcu.upgrade.upgrade_service.upgrade_service_handle'
local fw_mgmt = require 'general_hardware.client'
local context = require 'mc.context'
local ini_parser = require 'mc.v2_persistence'
local upgrade_service_vrd = require 'mcu.upgrade.upgrade_service.upgrade_service_vrd'
local upgrade_service_mcu = require 'mcu.upgrade.upgrade_service.upgrade_service_mcu'
local upgrade_service_comm = require 'mcu.upgrade.upgrade_service.upgrade_service_comm'
local upgrade_service_object = require 'mcu.upgrade.upgrade_service.upgrade_service_object'
local upgrade_object = require 'mcu.upgrade.upgrade_object'

local fructl = require 'mcu.upgrade.fructl_handler'
local parse_cfg = require 'mcu.upgrade.parser_cfg'
local mdb = require 'mc.mdb'
local utils = require 'mc.utils'
local vos = require 'utils.vos'
local utils_core = require 'utils.core'

TestVrdUpgService = {}

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

local upgrade_ret
local active_ret

local old_function ={}
local upgrade_object_new = upgrade_object.new
local vrd_instance = nil

local cfg = {}

local function stub_functions_2()
    upgrade_service_handle.is_activing =false
    upgrade_service_vrd.is_vrd_upgrading = false
    upgrade_service_mcu.get_instance().is_mcu_upgrading = false

    -- Initialize the upgrade service object with VRD service
    upgrade_service_object.get_instance():init_upgrade_service_obj(nil, nil, mcu_collection)

    -- Stub the upgrade service object to return a controllable VRD instance
    old_function.get_upgrade_service_obj = upgrade_service_object.get_instance().get_upgrade_service_obj
    vrd_instance = upgrade_service_object.get_instance().vrd_upgrade_service
    upgrade_service_object.get_instance().get_upgrade_service_obj = function(self, firmware_type)
        if firmware_type == 'Vrd' or firmware_type == 'Vdm' then
            return vrd_instance
        end
        return old_function.get_upgrade_service_obj(self, firmware_type)
    end

    old_function.get_cfgs = parse_cfg.get_cfgs
    parse_cfg.get_cfgs = function ()
        return 'Firmware1', cfg
    end

    old_function.save_cfg = parse_cfg.save_cfg
    parse_cfg.save_cfg = function ()
    end

    old_function.load_file = ini_parser.load_file
    local data = {
        Firmware1 = {
            Uid = true
        }
    }
    ini_parser.load_file = function()
        return data
    end

    old_function.PFileFileChown = fw_mgmt.PFileFileChown
    fw_mgmt.PFileFileChown = function()
        return true
    end

    upgrade_service_vrd.is_vrd_upgrading = false

    old_function.get_power_status = fructl.get_power_status
    fructl.get_power_status = function ()
        return 'ON'
    end

    old_function.get_sub_objects = mdb.get_sub_objects
    mdb.get_sub_objects = function()
        local obj_list = {
            [1] = {
                pcall= {
                    SetPowerOnLock = function()
                    end
                }
            }
        }
        return obj_list
    end

    old_function.secure_tar_unzips = utils.secure_tar_unzip
    utils.secure_tar_unzip = function()
    end

    old_function.get_file_accessible = vos.get_file_accessible
    vos.get_file_accessible = function()
        return true
    end
end

local function stub_functions()
    stub_functions_2()
    old_function.dir = utils_core.dir
    utils_core.dir = function()
        return {
            'BCU_1_vrd.hpm'
        }
    end

    old_function.new = upgrade_object.new
    upgrade_object.new = function(mcu_obj, system_id, power_state)
        local obj = upgrade_object_new(mcu_obj, system_id, power_state)
        obj.upgrade_process = function()
            return 0
        end
        return obj
    end

    old_function.is_upgrade_obj_proc_finis = upgrade_service_comm.is_upgrade_obj_proc_finish
    upgrade_service_comm.is_upgrade_obj_proc_finish = function()
        return true
    end

    old_function.UpdateServiceUpdateServicePrepareReply = fw_mgmt.UpdateServiceUpdateServicePrepareReply
    fw_mgmt.UpdateServiceUpdateServicePrepareReply = function (_, _, _, _, _, prepare_ret, parameters)
        upgrade_ret = prepare_ret
    end

    old_function.UpdateServiceUpdateServiceProcessReply = fw_mgmt.UpdateServiceUpdateServiceProcessReply
    fw_mgmt.UpdateServiceUpdateServiceProcessReply = function (_, _, _, _, process_ret, parameters)
        upgrade_ret = process_ret
    end

    old_function.UpdateServiceUpdateServiceFinishReply = fw_mgmt.UpdateServiceUpdateServiceFinishReply
    fw_mgmt.UpdateServiceUpdateServiceFinishReply = function (_, _, _, _, finish_ret, parameters)
        upgrade_ret = finish_ret
    end

    old_function.FirmwareActiveFirmwareActiveActiveProcessReply = fw_mgmt.FirmwareActiveFirmwareActiveActiveProcessReply
    fw_mgmt.FirmwareActiveFirmwareActiveActiveProcessReply = function (_, _, _, _, active1_ret)
        active_ret = active1_ret
    end

    old_function.FirmwareActiveFirmwareActiveRegisterActiveAction =
        fw_mgmt.FirmwareActiveFirmwareActiveRegisterActiveAction
    fw_mgmt.FirmwareActiveFirmwareActiveRegisterActiveAction = function()
    end
end

local function recover_functions()
    parse_cfg.get_cfgs = old_function.get_cfgs
    parse_cfg.save_cfg = old_function.save_cfg
    ini_parser.load_file = old_function.load_file
    fw_mgmt.PFileFileChown = old_function.PFileFileChown
    upgrade_service_vrd.is_vrd_upgrading = false
    fructl.get_power_status = old_function.get_power_status
    mdb.get_sub_objects = old_function.get_sub_objects
    utils.secure_tar_unzip = old_function.secure_tar_unzips
    vos.get_file_accessible = old_function.get_file_accessible
    utils_core.dir = old_function.dir
    upgrade_object.new = old_function.new
    upgrade_service_comm.is_upgrade_obj_proc_finish = old_function.is_upgrade_obj_proc_finis
    fw_mgmt.UpdateServiceUpdateServicePrepareReply = old_function.UpdateServiceUpdateServicePrepareReply
    fw_mgmt.UpdateServiceUpdateServiceProcessReply = old_function.UpdateServiceUpdateServiceProcessReply
    fw_mgmt.UpdateServiceUpdateServiceFinishReply = old_function.UpdateServiceUpdateServiceFinishReply
    fw_mgmt.FirmwareActiveFirmwareActiveActiveProcessReply = old_function.FirmwareActiveFirmwareActiveActiveProcessReply
    fw_mgmt.FirmwareActiveFirmwareActiveRegisterActiveAction =
        old_function.FirmwareActiveFirmwareActiveRegisterActiveAction
    if old_function.get_upgrade_service_obj then
        upgrade_service_object.get_instance().get_upgrade_service_obj = old_function.get_upgrade_service_obj
    end
end

local mcu_collection = {
    [1] =
    {
        get_system_id = function ()
            return 1
        end,
        get_uid = function ()
            return '111'
        end,
        mcu = {
            uid = '111',
            SubCompList = {
                {
                Type = 2,
                get_mdb_vrd_firmware_version = function()
                    return '0.01'
                end,
                set_major_version = function()
                end,
                set_minor_version = function()
                end,
                set_revision = function()
                end,
                ge_component_major_version = function()
                   return '6'
                end
            }
            },
            LockChip = {
                SetLockStatus = function()
                    return 0
                end,
                LockStatus = 0
            },
        },
        chip_lock_supported = function()
            return true
        end,
        chip_lock = function()
            return true, 0
        end,
        chip_unlock = function()
            return true
        end,
        get_position = function()
        end,
        update_sub_component_info_list = function()
        end,
        vrd_info_changed = {
            emit = function()
            end
        },
        set_major_version = function()
        end,
        set_minor_version = function()
        end,
        set_revision = function()
        end
    }
}

local function stub_vrd_upg_instances()
    upgrade_service_vrd.mcu_collection = mcu_collection
    cfg = {
        Firmware1 =
        {
            name = 'Firmware1',
            component_id = 0x17,
            component_idex = 0x7D,
            uid_list = {'111'}
        }
    }
end

local function stub_low_version_vrd_upg_instances(ver)
    upgrade_service_vrd.mcu_collection = mcu_collection
    cfg = {
        Firmware1 =
        {
            name = 'Firmware1',
            component_id = 0x17,
            component_idex = 0x7D,
            uid_list = {'111'},
            version = ver
        }
    }
end

function TestVrdUpgService:test_upgrade_vrd()
    stub_vrd_upg_instances()
    stub_functions()
    upgrade_service_handle:on_upgrade_prepare(context.new(), 1, 'Vrd', '', '', {})
    lu.assertEquals(upgrade_ret, RET_OK)
    upgrade_service_handle:on_upgrade_process(context.new(), 1, 'Vrd', '/dev/shm/upgrad/valid/123456/Firmware1')
    lu.assertEquals(upgrade_ret, RET_OK)
    upgrade_service_handle:on_upgrade_finish(context.new(), 1, 'Vrd')
    lu.assertEquals(upgrade_ret, RET_OK)
    recover_functions()
end

--测试解析包内容失败
function TestVrdUpgService:test_upgrade_vrd_invalid()
    stub_vrd_upg_instances()
    stub_functions()
    fw_mgmt.PFileFileChown = function()
        return false
    end
    upgrade_service_handle:on_upgrade_prepare(context.new(), 1, 'Vrd', '', '', {})
    lu.assertEquals(upgrade_ret, RET_ERR)
    recover_functions()
end

--测试有其他vrd正在升级
function TestVrdUpgService:test_is_upgrading_vrd()
    stub_vrd_upg_instances()
    stub_functions()
    vrd_instance.is_vrd_upgrading = true
    upgrade_service_handle:on_upgrade_prepare(context.new(), 1, 'Vrd', '', '', {})
    lu.assertEquals(upgrade_ret, OTHERS_UPGRADING)
    vrd_instance.is_vrd_upgrading = false
    recover_functions()
end

--测试下电升级
function TestVrdUpgService:test_poweroff_upgrade_vrd()
    stub_vrd_upg_instances()
    stub_functions()
    fructl.get_power_status = function ()
        return 'OFF'
    end
    upgrade_service_handle:on_upgrade_prepare(context.new(), 1, 'Vrd', '', '', {})
    lu.assertEquals(upgrade_ret, RET_OK)
    upgrade_service_handle:on_upgrade_process(context.new(), 1, 'Vrd', '/dev/shm/upgrad/valid/123456/Firmware1')
    lu.assertEquals(upgrade_ret, RET_OK)
    recover_functions()
end

--测试串行升级
function TestVrdUpgService:test_serial_upgrade_vrd()
    stub_vrd_upg_instances()
    stub_functions()
    old_function.SetLockStatus = upgrade_service_mcu.get_instance().mcu_collection[1].mcu.LockChip.SetLockStatus
    upgrade_service_vrd.mcu_collection[1].mcu.LockChip.SetLockStatus = nil
    upgrade_service_handle:on_upgrade_prepare(context.new(), 1, 'Vrd', '', '', {})
    lu.assertEquals(upgrade_ret, RET_OK)
    upgrade_service_handle:on_upgrade_process(context.new(), 1, 'Vrd', '/dev/shm/upgrad/valid/123456/Firmware1')
    lu.assertEquals(upgrade_ret, RET_OK)
    recover_functions()
    upgrade_service_mcu.get_instance().mcu_collection[1].mcu.LockChip.SetLockStatus = old_function.SetLockStatus
end


function TestVrdUpgService:test_upgrade_all_vrd()
    stub_vrd_upg_instances()
    stub_functions()
    upgrade_service_handle:on_upgrade_prepare(context.new(), 255, 'Vrd', '', '', {})
    lu.assertEquals(upgrade_ret, RET_OK)
    recover_functions()
end

function TestVrdUpgService:test_active_vrd()
    stub_vrd_upg_instances()
    stub_functions()
    upgrade_service_handle:on_active_process(context.new(), 1, 'VRD')
    lu.assertEquals(active_ret, RET_OK)
    recover_functions()
end

-- 多host并行生效VRD测试
function TestVrdUpgService:test_on_active_process_parallel_valid()
    os.execute('mkdir -p /data/backup/vrd/up_cfg/')
    os.execute('echo test_valid_vrd1 > /data/backup/vrd/up_cfg/HOST_1_vrd.hpm')
    os.execute('echo test_valid_vrd2 > /data/backup/vrd/up_cfg/HOST_2_vrd.hpm')
    upgrade_service_handle:on_active_process(context.new(), 1, 'VRD')
    local valid_obj = require 'mcu.upgrade.valid'
    lu.assertEquals(next(valid_obj.valid_list), nil)

    os.execute('rm -rf /data/backup/vrd/up_cfg/')
end

-- 降级升级失败
function TestVrdUpgService:test_upgrade_vrd_low_version_fail()
    local LOW_VERSION = 33
    stub_low_version_vrd_upg_instances(5)
    stub_functions()
    upgrade_service_handle:on_upgrade_prepare(context.new(), 1, 'Vrd', '', '', {})
    lu.assertEquals(upgrade_ret, LOW_VERSION)
    recover_functions()
end

-- 高版本升级成功
function TestVrdUpgService:test_upgrade_vrd_low_version_succ()
    stub_low_version_vrd_upg_instances(7)
    stub_functions()
    upgrade_service_handle:on_upgrade_prepare(context.new(), 1, 'Vrd', '', '', {})
    lu.assertEquals(upgrade_ret, RET_OK)
    upgrade_service_handle:on_upgrade_process(context.new(), 1, 'Vrd', '/dev/shm/upgrad/valid/123456/Firmware1')
    lu.assertEquals(upgrade_ret, RET_OK)
    upgrade_service_handle:on_upgrade_finish(context.new(), 1, 'Vrd')
    lu.assertEquals(upgrade_ret, RET_OK)
    recover_functions()
end
