-- Copyright (c) 2025 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 defs = require 'independent_vrd.ind_vrd_defs'

TestPmbusVrdUpgrade = {}

function TestPmbusVrdUpgrade:setUp()
    local test_self = self
    self.mock_bus = { test = 'bus' }
    self.fw_mgmt_calls = {}
    self.fructl_calls = {}
    self.file_operations = {}
    self.skynet_sleeps = {}
    self.saved_cfgs = {}
    self.power_state = 'OFF'
    self.power_state_sequence = {}
    self.cache_dir_listing = { 'HOST_1_Independent_Vrd_PMBus.hpm' }
    self.package_dir_listing = { 'firmware_entry.bin' }
    self.accessible_paths = {
        ['/test/hpm/test.hpm'] = true,
        ['/test/hpm/process.hpm'] = true,
        ['/test/cache/'] = true,
        ['/test/cache/HOST_1_Independent_Vrd_PMBus.hpm'] = true,
        ['/test/unzip/'] = true
    }

    local function build_condition(name)
        return { eq = function(_, value)
            return { field = name, value = value }
        end }
    end

    local cfg_table = {
        Id = build_condition('Id'),
        ComponentId = build_condition('ComponentId'),
        ComponentIdex = build_condition('ComponentIdex')
    }

    self.mock_db = {
        FwUpdateCfgTable = cfg_table
    }
    function self.mock_db:select(table_ref)
        return {
            where = function(...)
                return {
                    all = function()
                        return { { Id = 'HOST_1_Independent_Vrd_PMBus.hpm' } }
                    end
                }
            end
        }
    end
    self.mock_vrd_manager_collection = {}

    package.loaded['mc.logging'] = {
        notice = function() end,
        info = function() end,
        debug = function() end,
        error = function() end
    }
    package.loaded['mc.context'] = {
        new = function()
            return {}
        end
    }
    package.loaded['mc.utils'] = {
        copy_file = function(src, dst)
            table.insert(test_self.file_operations, { op = 'copy', src = src, dst = dst })
        end,
        remove_file = function(path)
            table.insert(test_self.file_operations, { op = 'remove', path = path })
        end,
        secure_tar_unzip = function(file_path, dir, max_size, buffer_size)
            table.insert(test_self.file_operations, { op = 'unzip', file = file_path, dir = dir })
        end
    }
    package.loaded['utils.core'] = {
        dir = function(path)
            if path == defs.FW_VALID_FILE_DIR[defs.FIRMWARE_TYPE.UPGRADE] then
                return test_self.cache_dir_listing
            elseif path == '/test/unzip/' then
                return test_self.package_dir_listing
            elseif path == '/test/cache/' then
                return test_self.cache_dir_listing
            end
            return {}
        end
    }
    package.loaded['utils.vos'] = {
        get_file_accessible = function(path)
            return test_self.accessible_paths[path] or false
        end
    }
    package.loaded['general_hardware.client'] = {
        UpdateServiceUpdateServicePrepareReply = function(self, ctx, system_id, firmware_type, version_str, ret_code,
                                                          parameters)
            table.insert(test_self.fw_mgmt_calls, {
                func = 'PrepareReply',
                system_id = system_id,
                firmware_type = firmware_type,
                version = version_str,
                ret = ret_code
            })
        end,
        UpdateServiceUpdateServiceProcessReply = function(self, ctx, system_id, firmware_type, ret_code, parameters)
            table.insert(test_self.fw_mgmt_calls, {
                func = 'ProcessReply',
                system_id = system_id,
                firmware_type = firmware_type,
                ret = ret_code
            })
        end,
        UpdateServiceUpdateServiceFinishReply = function(self, ctx, system_id, firmware_type, ret_code, parameters)
            table.insert(test_self.fw_mgmt_calls, {
                func = 'FinishReply',
                system_id = system_id,
                firmware_type = firmware_type,
                ret = ret_code
            })
        end,
        UpdateServiceUpdateServiceUpdateUpgradeStatus = function(self, ctx, system_id, firmware_type, ret_code, progress,
                                                                 status, parameters)
            table.insert(test_self.fw_mgmt_calls, {
                func = 'UpdateStatus',
                system_id = system_id,
                firmware_type = firmware_type,
                progress = progress,
                status = status
            })
        end,
        FirmwareActiveFirmwareActiveRegisterActiveAction = function(self, ctx, list)
            table.insert(test_self.fw_mgmt_calls, {
                func = 'RegisterActive',
                list = list
            })
        end,
        FirmwareActiveFirmwareActiveUpdateActiveStatus = function(self, ctx, param)
            table.insert(test_self.fw_mgmt_calls, {
                func = 'UpdateActiveStatus',
                param = param
            })
        end,
        FirmwareActiveFirmwareActiveActiveProcessReply = function(self, ctx, system_id, firmware_type, ret_code)
            table.insert(test_self.fw_mgmt_calls, {
                func = 'ActiveProcessReply',
                system_id = system_id,
                firmware_type = firmware_type,
                ret = ret_code
            })
        end
    }
    package.loaded['mcu.upgrade.fructl_handler'] = {
        get_power_status = function(bus, system_id)
            if #test_self.power_state_sequence > 0 then
                test_self.power_state = table.remove(test_self.power_state_sequence, 1)
            end
            table.insert(test_self.fructl_calls, { func = 'get_power_status', system_id = system_id })
            return test_self.power_state
        end,
        set_poweron_lock_until_success = function(bus, system_id, locked, timeout, source)
            table.insert(test_self.fructl_calls, {
                func = 'set_poweron_lock',
                system_id = system_id,
                locked = locked
            })
        end
    }
    package.loaded['mcu.upgrade.parser_cfg'] = {
        parse_dir = function(file_path)
            return '/test/unzip/', 'firmware_entry.bin'
        end,
        get_cfgs = function(cfg_path)
            return nil, {
                {
                    uid_list = { 'test-uid-001' },
                    component_id = defs.CONVERT_COMPONENT[defs.FIRMWARE_TYPE.UPGRADE].id,
                    component_idex = defs.CONVERT_COMPONENT[defs.FIRMWARE_TYPE.UPGRADE].idex
                }
            }
        end,
        save_cfg = function(_, cfg)
            table.insert(test_self.saved_cfgs, cfg)
        end
    }
    self.config_data = {
        Firmware1 = { Uid = 'test-uid-001' }
    }
    package.loaded['mc.v2_persistence'] = {
        load_file = function(path)
            return test_self.config_data
        end
    }
    package.loaded['progress_statistics'] = {
        new = function(start_progress, end_progress, sub_task_count)
            return {
                set_sub_task_progress = function(self, index, progress)
                    self.last_index = index
                    self.last_progress = progress
                end,
                get_current_progress = function(self)
                    return start_progress + (end_progress - start_progress) / 2
                end
            }
        end
    }
    package.loaded['common'] = {
        skynet = {
            fork = function(fn)
                fn()
            end,
            fork_once = function(fn)
                fn()
            end,
            sleep = function(ms)
                table.insert(test_self.skynet_sleeps, ms)
            end
        },
        get_package_info = function(path)
            return { FirmwareDirectory = '/test/unzip/' }
        end
    }

    self.mock_vrd_manager = {
        UID = 'test-uid-001',
        objects_complete = true,
        set_objects_complete = function(self, complete)
            self.objects_complete = complete
        end,
        is_objects_complete = function(self)
            return self.objects_complete
        end,
        get_version = function(self)
            return '1.0.0'
        end,
        get_all_version = function(self)
            return '0.0.1'
        end,
        get_chip_count = function(self)
            return 2
        end,
        vrd_upgrade = function(self, dir, progress_callback)
            if progress_callback then
                progress_callback(1, 50)
                progress_callback(2, 100)
            end
            return defs.RET.OK
        end,
        upgrade = function(self, dir, hpm_path, progress_callback)
            return 0
        end,
        update_firmware_version = function(self, bus) end
    }

    self.mock_vrd_manager_collection[1] = self.mock_vrd_manager

    local pmbus_vrd_upgrade = require 'independent_vrd.upgrade.pmbus_vrd_upgrade'
    self.pmbus_vrd_upgrade_class = pmbus_vrd_upgrade
    self.obj = pmbus_vrd_upgrade.new(self.mock_bus, self.mock_db, self.mock_vrd_manager_collection)
end

-- Helper function to find call by function name
function TestPmbusVrdUpgrade:findCall(func_name)
    for _, call in ipairs(self.fw_mgmt_calls) do
        if call.func == func_name then
            return call
        end
    end
    return nil
end

-- Test: new creates object
function TestPmbusVrdUpgrade:test_new_creates_object()
    lu.assertNotNil(self.obj)
    lu.assertEquals(self.mock_bus, self.obj.bus)
    lu.assertEquals(self.mock_db, self.obj.db)
    lu.assertEquals(false, self.obj.is_activing)
    lu.assertEquals(false, self.obj.is_upgrading)
end

-- Test: new initializes fields
function TestPmbusVrdUpgrade:test_new_initializes_fields()
    lu.assertEquals('', self.obj.cfg_path)
    lu.assertEquals('', self.obj.hpm_path)
    lu.assertEquals('', self.obj.power_state)
    lu.assertEquals(false, self.obj.poweron_locked)
    lu.assertEquals(false, self.obj.vrd_cached)
end

-- Test: on_upgrade_prepare already upgrading
function TestPmbusVrdUpgrade:test_on_upgrade_prepare_already_upgrading()
    self.obj.is_upgrading = true

    self.obj:on_upgrade_prepare(nil, 1, 'Independent_Vrd_PMBus', '/test/cfg.ini', '/test/hpm/test.hpm', {})

    local call = self:findCall('PrepareReply')
    lu.assertNotNil(call)
    lu.assertEquals(248, call.ret)
    lu.assertEquals('', call.version)
end

-- Test: on_upgrade_prepare invalid config
function TestPmbusVrdUpgrade:test_on_upgrade_prepare_invalid_config()
    self.config_data = nil

    self.obj:on_upgrade_prepare(nil, 1, 'Independent_Vrd_PMBus', '/test/cfg.ini', '/test/hpm/test.hpm', {})

    local call = self:findCall('PrepareReply')
    lu.assertNotNil(call)
    lu.assertEquals(-1, call.ret)
    lu.assertEquals('', call.version)
    lu.assertEquals(false, self.obj.is_upgrading)
end

-- Test: on_upgrade_prepare VRD manager not found
function TestPmbusVrdUpgrade:test_on_upgrade_prepare_vrd_manager_not_found()
    self.config_data = {
        Firmware1 = {
            Uid = 'non-existent-uid'
        }
    }

    self.obj:on_upgrade_prepare(nil, 1, 'Independent_Vrd_PMBus', '/test/cfg.ini', '/test/hpm/test.hpm', {})

    local call = self:findCall('PrepareReply')
    lu.assertNotNil(call)
    lu.assertEquals(-1, call.ret)
    lu.assertEquals(false, self.obj.is_upgrading)
end

function TestPmbusVrdUpgrade:test_on_upgrade_prepare_unlocks_when_power_returns()
    self.power_state = 'OFF'
    self.power_state_sequence = { 'OFF', 'ON' }

    self.obj:on_upgrade_prepare(nil, 1, 'Independent_Vrd_PMBus', '/test/cfg.ini', '/test/hpm/test.hpm', {})

    lu.assertFalse(self.obj.poweron_locked)
    local unlocked = false
    for _, call in ipairs(self.fructl_calls) do
        if call.func == 'set_poweron_lock' and call.locked == false then
            unlocked = true
            break
        end
    end
    lu.assertTrue(unlocked)
end

-- Test: on_upgrade_process cache when power on
function TestPmbusVrdUpgrade:test_on_upgrade_process_cache_when_power_on()
    self.power_state = 'OFF'
    self.obj:on_upgrade_prepare(nil, 1, 'Independent_Vrd_PMBus', '/test/cfg.ini', '/test/hpm/test.hpm', {})

    self.power_state = 'ON'
    self.fw_mgmt_calls = {}
    self.file_operations = {}
    self.accessible_paths['/test/firmware.tar'] = true

    self.obj:on_upgrade_process(nil, 1, 'Independent_Vrd_PMBus', '/test/firmware.tar', {})

    lu.assertEquals(true, self.obj.vrd_cached)
    local has_copy = false
    for _, op in ipairs(self.file_operations) do
        if op.op == 'copy' then
            has_copy = true
            break
        end
    end
    lu.assertTrue(has_copy)
end

-- Test: on_upgrade_process no manager
function TestPmbusVrdUpgrade:test_on_upgrade_process_no_manager()
    self.obj.upgrade_vrd_manager = nil
    self.accessible_paths['/test/firmware.tar'] = true

    self.obj:on_upgrade_process(nil, 1, 'Independent_Vrd_PMBus', '/test/firmware.tar', {})

    local call = self:findCall('ProcessReply')
    lu.assertNotNil(call)
    lu.assertEquals(-1, call.ret)
end

-- Test: on_upgrade_process no chips
function TestPmbusVrdUpgrade:test_on_upgrade_process_no_chips()
    self.obj:on_upgrade_prepare(nil, 1, 'Independent_Vrd_PMBus', '/test/cfg.ini', '/test/hpm/test.hpm', {})

    self.obj.upgrade_vrd_manager.get_chip_count = function(self)
        return 0
    end

    self.fw_mgmt_calls = {}
    self.accessible_paths['/test/firmware.tar'] = true

    self.obj:on_upgrade_process(nil, 1, 'Independent_Vrd_PMBus', '/test/firmware.tar', {})

    local call = self:findCall('ProcessReply')
    lu.assertNotNil(call)
    lu.assertEquals(-1, call.ret)
end

function TestPmbusVrdUpgrade:test_on_upgrade_process_success_power_off()
    self.accessible_paths['/test/firmware.tar'] = true
    self.obj:on_upgrade_prepare(nil, 1, 'Independent_Vrd_PMBus', '/test/cfg.ini', '/test/hpm/test.hpm', {})

    self.fw_mgmt_calls = {}
    self.obj:on_upgrade_process(nil, 1, 'Independent_Vrd_PMBus', '/test/firmware.tar', {})

    local process_call = self:findCall('ProcessReply')
    lu.assertNotNil(process_call)
    lu.assertEquals(0, process_call.ret)

    local status_call = self:findCall('UpdateStatus')
    lu.assertNotNil(status_call)
    lu.assertEquals('Running', status_call.status)
end

-- Test: on_upgrade_finish success
function TestPmbusVrdUpgrade:test_on_upgrade_finish_success()
    self.obj:on_upgrade_prepare(nil, 1, 'Independent_Vrd_PMBus', '/test/cfg.ini', '/test/hpm/test.hpm', {})
    self.obj.system_id = 1

    self.fw_mgmt_calls = {}

    self.obj:on_upgrade_finish(nil, 1, 'Independent_Vrd_PMBus', {})

    local call = self:findCall('FinishReply')
    lu.assertNotNil(call)
    lu.assertEquals(0, call.ret)
    lu.assertEquals(false, self.obj.is_upgrading)
end

-- Test: on_active_process already activing
function TestPmbusVrdUpgrade:test_on_active_process_already_activing()
    self.obj.is_activing = true

    self.obj:on_active_process(nil, 1, 'INDEPENDENT_VRD_PMBUS')

    local call = self:findCall('ActiveProcessReply')
    lu.assertNotNil(call)
    lu.assertEquals(-1, call.ret)
end

-- Test: on_active_process already upgrading
function TestPmbusVrdUpgrade:test_on_active_process_already_upgrading()
    self.obj.is_upgrading = true

    self.obj:on_active_process(nil, 1, 'INDEPENDENT_VRD_PMBUS')

    local call = self:findCall('ActiveProcessReply')
    lu.assertNotNil(call)
    lu.assertEquals(-1, call.ret)
end

-- Test: on_active_process no cached file
function TestPmbusVrdUpgrade:test_on_active_process_no_cached_file()
    self.obj.is_activing = false
    self.obj.is_upgrading = false

    package.loaded['utils.core'].dir = function(path)
        return {}
    end

    self.obj:on_active_process(nil, 1, 'INDEPENDENT_VRD_PMBUS')

    local call = self:findCall('ActiveProcessReply')
    lu.assertNotNil(call)
    lu.assertEquals(-1, call.ret)
end

function TestPmbusVrdUpgrade:test_on_active_process_success()
    local cache_dir = defs.FW_VALID_FILE_DIR[defs.FIRMWARE_TYPE.UPGRADE]
    self.cache_dir_listing = { 'HOST_1_Independent_Vrd_PMBus.hpm' }
    self.accessible_paths[cache_dir] = true
    self.accessible_paths[cache_dir .. 'HOST_1_Independent_Vrd_PMBus.hpm'] = true
    self.package_dir_listing = { 'firmware_entry.bin' }
    self.accessible_paths['/test/unzip/firmware_entry.bin'] = true

    self.obj:on_active_process(nil, 1, 'INDEPENDENT_VRD_PMBUS')

    local reply = self:findCall('ActiveProcessReply')
    lu.assertNotNil(reply)
    lu.assertEquals(0, reply.ret)

    local status_call = self:findCall('UpdateActiveStatus')
    lu.assertNotNil(status_call)
    lu.assertEquals('Apply', status_call.param[3].Value)

    local removed = 0
    for _, op in ipairs(self.file_operations) do
        if op.op == 'remove' then
            removed = removed + 1
        end
    end
    lu.assertTrue(removed >= 1)
end

-- Test: is_upgrading_or_activing
function TestPmbusVrdUpgrade:test_is_upgrading_or_activing_both_false()
    self.obj.is_activing = false
    self.obj.is_upgrading = false
    lu.assertEquals(false, self.obj:is_upgrading_or_activing())
end

function TestPmbusVrdUpgrade:test_is_upgrading_or_activing_upgrading()
    self.obj.is_upgrading = true
    lu.assertEquals(true, self.obj:is_upgrading_or_activing())
end

function TestPmbusVrdUpgrade:test_is_upgrading_or_activing_activing()
    self.obj.is_activing = true
    lu.assertEquals(true, self.obj:is_upgrading_or_activing())
end

-- Test: cache_upgrade_file with inaccessible hpm during cache
function TestPmbusVrdUpgrade:test_cache_upgrade_file_inaccessible_hpm()
    -- First prepare with accessible hpm
    self.power_state = 'OFF'
    self.obj:on_upgrade_prepare(nil, 1, 'Independent_Vrd_PMBus', '/test/cfg.ini', '/test/hpm/test.hpm', {})

    -- Set power ON, make hpm inaccessible but file_path for process still accessible
    -- This tests that cache_upgrade_file will fail when self.hpm_path is not accessible
    self.power_state = 'ON'
    self.accessible_paths['/test/hpm/test.hpm'] = false

    -- Process with file_path that's accessible (different from cached hpm_path)
    self.obj:on_upgrade_process(nil, 1, 'Independent_Vrd_PMBus', '/test/hpm/process.hpm', {})

    -- Even though cache failed, process returns OK because system is powered on
    -- and it won't perform actual upgrade, just cache attempt
    local call = self:findCall('ProcessReply')
    lu.assertNotNil(call)
    lu.assertEquals(0, call.ret, "Process should return OK when caching on powered-on system")
end

-- Test: cache_upgrade_file creates directory during process
function TestPmbusVrdUpgrade:test_cache_upgrade_file_creates_directory()
    -- First prepare
    self.power_state = 'OFF'
    self.obj:on_upgrade_prepare(nil, 1, 'Independent_Vrd_PMBus', '/test/cfg.ini', '/test/hpm/test.hpm', {})

    -- Set power ON and cache dir doesn't exist
    self.power_state = 'ON'
    self.accessible_paths['/test/cache/'] = false

    -- Mock os.execute
    local execute_called = false
    local old_execute = os.execute
    os.execute = function(cmd)
        if cmd:find('mkdir') then
            execute_called = true
            -- Simulate directory creation
            self.accessible_paths['/test/cache/'] = true
        end
        return 0
    end

    -- Now process should create the directory when caching
    self.obj:on_upgrade_process(nil, 1, 'Independent_Vrd_PMBus', '/test/hpm/test.hpm', {})

    os.execute = old_execute
    lu.assertTrue(execute_called, "mkdir should have been called to create cache directory")
end

-- Test: on_upgrade_prepare pcall error handling
function TestPmbusVrdUpgrade:test_on_upgrade_prepare_pcall_error()
    -- Make parse_config_file throw error
    package.loaded['mc.v2_persistence'].load_file = function(path)
        error('Config file error')
    end

    self.obj:on_upgrade_prepare(nil, 1, 'Independent_Vrd_PMBus', '/bad/cfg.ini', '/test/hpm/test.hpm', {})

    local call = self:findCall('PrepareReply')
    lu.assertNotNil(call)
    lu.assertEquals(-1, call.ret)
    lu.assertEquals('', call.version)
end

-- Test: on_upgrade_finish handles errors gracefully
function TestPmbusVrdUpgrade:test_on_upgrade_finish_pcall_error()
    self.obj.is_upgrading = true
    self.obj.system_id = 1
    self.obj.power_lock_acquired = true

    -- Force an error in the finish process (but finish should still return OK)
    package.loaded['mcu.upgrade.fructl_handler'].unlock_power_on = function(...)
        error('Unlock error')
    end

    self.obj:on_upgrade_finish(nil, 1, 'Independent_Vrd_PMBus', {})

    local call = self:findCall('FinishReply')
    lu.assertNotNil(call)
    -- Finish always returns OK even if internal operations fail
    lu.assertEquals(0, call.ret)
end

-- Test: register active with no cache directory
function TestPmbusVrdUpgrade:test_register_active_no_cache_dir()
    self.accessible_paths['/test/cache/'] = false

    -- Test that register active doesn't crash
    local obj = self.pmbus_vrd_upgrade_class.new(self.mock_bus, self.mock_db, self.mock_vrd_manager_collection)
    lu.assertNotNil(obj)
end

-- Test: find_cached_upgrade_file with no directory
function TestPmbusVrdUpgrade:test_find_cached_file_no_directory()
    self.accessible_paths['/test/cache/'] = false

    self.obj:on_active_process(nil, 1, 'INDEPENDENT_VRD_PMBUS')

    local call = self:findCall('ActiveProcessReply')
    lu.assertNotNil(call)
    lu.assertEquals(-1, call.ret)
end

-- Test: unzip_cached_firmware error
function TestPmbusVrdUpgrade:test_unzip_cached_firmware_error()
    -- Mock get_package_info to return nil
    package.loaded['common'].get_package_info = function(path)
        return nil
    end

    self.obj:on_active_process(nil, 1, 'INDEPENDENT_VRD_PMBUS')

    local call = self:findCall('ActiveProcessReply')
    lu.assertNotNil(call)
    lu.assertEquals(-1, call.ret)
end

-- Test: unzip_cached_firmware no FirmwareDirectory
function TestPmbusVrdUpgrade:test_unzip_no_firmware_directory()
    -- Mock get_package_info to return object without FirmwareDirectory
    package.loaded['common'].get_package_info = function(path)
        return { SomeOtherField = 'value' }
    end

    self.obj:on_active_process(nil, 1, 'INDEPENDENT_VRD_PMBUS')

    local call = self:findCall('ActiveProcessReply')
    lu.assertNotNil(call)
    lu.assertEquals(-1, call.ret)
end

-- Test: activate_all_vrd_managers with upgrade failure
function TestPmbusVrdUpgrade:test_activate_vrd_managers_failure()
    local failing_manager = {
        upgrade = function(self, dir, hpm_path, callback)
            return -1
        end,
        get_version = function(self)
            return '1.0.0'
        end,
        update_firmware_version = function(self, bus)
        end,
        UID = 'test-uid-001',
        objects_complete = true,
        set_objects_complete = function(self, complete)
            self.objects_complete = complete
        end,
        is_objects_complete = function(self)
            return self.objects_complete
        end
    }

    self.mock_vrd_manager_collection[1] = failing_manager

    self.obj:on_active_process(nil, 1, 'INDEPENDENT_VRD_PMBUS')

    local call = self:findCall('ActiveProcessReply')
    lu.assertNotNil(call)
    lu.assertEquals(-1, call.ret)
end

-- Test: on_active_process pcall error handling
function TestPmbusVrdUpgrade:test_on_active_process_pcall_error()
    -- Force an error by making secure_tar_unzip fail
    package.loaded['mc.utils'].secure_tar_unzip = function(file_path, dir, max_size, buffer_size)
        error('Unzip failed')
    end

    self.obj:on_active_process(nil, 1, 'INDEPENDENT_VRD_PMBUS')

    local call = self:findCall('ActiveProcessReply')
    lu.assertNotNil(call)
    lu.assertEquals(-1, call.ret)
end

function TestPmbusVrdUpgrade:tearDown()
    package.loaded['independent_vrd.upgrade.pmbus_vrd_upgrade'] = nil
    package.loaded['independent_vrd.ind_vrd_defs'] = nil
    package.loaded['mc.logging'] = nil
    package.loaded['mc.utils'] = nil
    package.loaded['mc.context'] = nil
    package.loaded['utils.core'] = nil
    package.loaded['utils.vos'] = nil
    package.loaded['general_hardware.client'] = nil
    package.loaded['common'] = nil
    package.loaded['mcu.upgrade.fructl_handler'] = nil
    package.loaded['mcu.upgrade.parser_cfg'] = nil
    package.loaded['mc.v2_persistence'] = nil
    package.loaded['progress_statistics'] = nil
end
