-- Copyright (c) 2026 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'

-- 定义 mock 对象（但不设置到 package.loaded，避免文件加载时污染全局环境）
local utils_calls = {}
local mock_utils = {
    remove_file = function(path)
        table.insert(utils_calls, {method = 'remove_file', path = path})
        return true
    end
}

local fructl_calls = {}
local mock_fructl = {
    set_poweron_lock_until_success = function(bus, sys_id, state, time, reason)
        table.insert(fructl_calls, {
            method = 'set_poweron_lock_until_success',
            bus = bus,
            sys_id = sys_id,
            state = state,
            time = time,
            reason = reason
        })
        return true
    end
}

local vos_calls = {}
local mock_vos = {
    get_file_accessible = function(path)
        table.insert(vos_calls, {method = 'get_file_accessible', path = path})
        if path == '/tmp/not_exist' then
            return false
        end
        return true
    end
}

local mock_utils_core = {
    dir = function(path)
        if path == '/tmp/empty_dir/' then
            return {}
        elseif path == '/tmp/no_firmware/' then
            return {'file1.bin', 'file2.txt'}
        elseif path == '/data/backup/nic/up_cfg/' then
            -- 返回包含 nic.hpm 的文件，匹配 UPGRADE_NIC_FILE_NAME
            return {'nic.hpm', 'other_file.txt'}
        elseif path:match('/tmp/release/') then
            -- 解压后的目录，应该返回 Firmware 目录
            return {'Firmware1', 'other_file.txt'}
        end
        return {'Firmware1.tar', 'other_file.txt'}
    end,
    stat = function(path)
        return {st_size = 1024}
    end
}

local client_calls = {}
local mock_client = {
    FirmwareActiveFirmwareActiveUpdateActiveStatus = function(self, ctx, param)
        table.insert(client_calls, {
            method = 'UpdateActiveStatus',
            param = param
        })
        return true
    end,
    UpdateServiceUpdateServiceParseFirmwarePackage = function(self, ctx, file_path)
        table.insert(client_calls, {
            method = 'ParseFirmwarePackage',
            file_path = file_path
        })
        if file_path == '/tmp/invalid.tar' then
            error('parse failed')
        end
        return {
            FirmwareDirectory = '/tmp/release/',
            FirmwareName = 'Firmware1'
        }
    end
}

local parser_cfg_calls = {}
local mock_parser_cfg = {
    get_cfgs = function(path)
        table.insert(parser_cfg_calls, {method = 'get_cfgs', path = path})
        if path == '/tmp/invalid.cfg' then
            return {}
        end
        return {
            Firmware1 = {
                name = 'Firmware1',
                component_id = 1,
                component_idex = 2
            }
        }
    end
}

local mock_network_adapter_firmware = {
    collection = {
        fold = function(self, func, acc)
            -- Mock two network adapter firmware objects
            local mock_obj1 = {
                ComponentID = 1,
                ComponentIDEx = 2,
                FirmwareRoute = 0x01,
                DefaultRoute = 0x00,
                FlashSizeKiB = 2048,
                Protocol = 'SFC'
            }
            func(acc, mock_obj1, 'key1')
            return acc
        end
    }
}

local upgrade_flash_calls = {}
local mock_upgrade_flash = {
    network_adapter_upgrade_flash = function(self, file_path)
        table.insert(upgrade_flash_calls, {
            method = 'network_adapter_upgrade_flash',
            file_path = file_path
        })
        return 0 -- upgrade_defs.RET.OK
    end
}

-- mock_context 不再在文件顶层定义，改为在 setUp 中动态创建

-- 延迟加载被测试模块，在 setUp 中加载
local upgrade_defs
local active_process

TEST_Active_Process = {}

function TEST_Active_Process:setUp()
    -- 设置 package.loaded 中的 mock（只在测试用例执行时设置，避免文件加载时污染全局环境）
    package.loaded['mc.logging'] = {
        notice = function() end,
        error = function() end,
        info = function() end,
        maintenance = function() end,
        running = function() end,
        MLOG_INFO = 0,
        RLOG_INFO = 0,
        RLOG_ERROR = 1,
        FC__PUBLIC_OK = 0
    }
    
    -- 对于 mc.context，先加载真实模块，然后只覆盖需要 mock 的函数，保留其他函数（如 get_context）
    package.loaded['mc.context'] = nil
    local real_context = require 'mc.context'
    local context_mock = {}
    -- 复制真实模块的所有函数
    for k, v in pairs(real_context) do
        context_mock[k] = v
    end
    -- 覆盖需要 mock 的函数
    context_mock.new = function()
        return {}
    end
    package.loaded['mc.context'] = context_mock
    
    package.loaded['mc.utils'] = mock_utils
    package.loaded['infrastructure.fructl'] = mock_fructl
    
    -- 对于 utils.vos，先加载真实模块，然后只覆盖需要 mock 的函数，保留其他函数（如 vos_tick_get）
    package.loaded['utils.vos'] = nil
    local real_vos = require 'utils.vos'
    local vos_mock = {}
    -- 复制真实模块的所有函数
    for k, v in pairs(real_vos) do
        vos_mock[k] = v
    end
    -- 覆盖需要 mock 的函数
    vos_mock.get_file_accessible = function(path)
        table.insert(vos_calls, {method = 'get_file_accessible', path = path})
        if path == '/tmp/not_exist' then
            return false
        end
        return true
    end
    package.loaded['utils.vos'] = vos_mock
    
    package.loaded['utils.core'] = mock_utils_core
    package.loaded['network_adapter.client'] = mock_client
    package.loaded['upgrade.parser_cfg'] = mock_parser_cfg
    package.loaded['upgrade.network_adapter_firmware_object'] = mock_network_adapter_firmware
    package.loaded['upgrade.upgrade_flash'] = mock_upgrade_flash
    
    -- 清除被测试模块的缓存，确保使用最新的 mock
    package.loaded['upgrade.active_process'] = nil
    package.loaded['upgrade.upgrade_defs'] = nil
    
    -- 加载被测试模块（使用最新的 mock）
    upgrade_defs = require 'upgrade.upgrade_defs'
    active_process = require 'upgrade.active_process'
    
    -- Reset call records
    utils_calls = {}
    fructl_calls = {}
    vos_calls = {}
    client_calls = {}
    parser_cfg_calls = {}
    upgrade_flash_calls = {}
    
    -- Reset mock functions
    -- 更新 package.loaded['utils.vos'] 中的 get_file_accessible 函数
    package.loaded['utils.vos'].get_file_accessible = function(path)
        table.insert(vos_calls, {method = 'get_file_accessible', path = path})
        if path == '/tmp/not_exist' then
            return false
        end
        return true
    end
    
    mock_utils_core.dir = function(path)
        if path == '/tmp/empty_dir/' then
            return {}
        elseif path == '/tmp/no_firmware/' then
            return {'file1.bin', 'file2.txt'}
        elseif path == '/data/backup/nic/up_cfg/' then
            return {'nic.hpm', 'other_file.txt'}
        elseif path:match('/tmp/release/') then
            return {'Firmware1', 'other_file.txt'}
        end
        return {'Firmware1.tar', 'other_file.txt'}
    end
    
    mock_client.UpdateServiceUpdateServiceParseFirmwarePackage = function(self, ctx, file_path)
        table.insert(client_calls, {
            method = 'ParseFirmwarePackage',
            file_path = file_path
        })
        if file_path == '/tmp/invalid.tar' then
            error('parse failed')
        end
        return {
            FirmwareDirectory = '/tmp/release/',
            FirmwareName = 'Firmware1'
        }
    end
    
    mock_parser_cfg.get_cfgs = function(path)
        table.insert(parser_cfg_calls, {method = 'get_cfgs', path = path})
        if path == '/tmp/invalid.cfg' then
            return {}
        end
        return {
            Firmware1 = {
                name = 'Firmware1',
                component_id = 1,
                component_idex = 2
            }
        }
    end
    
    mock_upgrade_flash.network_adapter_upgrade_flash = function(self, file_path)
        table.insert(upgrade_flash_calls, {
            method = 'network_adapter_upgrade_flash',
            file_path = file_path
        })
        return 0 -- upgrade_defs.RET.OK
    end
    
    mock_utils.remove_file = function(path)
        table.insert(utils_calls, {method = 'remove_file', path = path})
        return true
    end
    
    -- Reload the module with fresh mocks
    package.loaded['upgrade.active_process'] = nil
    
    -- Create mock self object
    self.mock_self = {
        cfgs = {},
        upgrade_list = {},
        is_network_adapter_activing = false,
        bus = {},
        system_id = 1
    }
end

function TEST_Active_Process:tearDown()
    -- 重置调用记录
    utils_calls = {}
    fructl_calls = {}
    vos_calls = {}
    client_calls = {}
    parser_cfg_calls = {}
    upgrade_flash_calls = {}
    
    -- 只清除 test_upgrade 特有的模块，不清除基础模块（如 mc.logging、mc.context 等）
    -- 基础模块可能被其他测试使用，清除它们会导致其他测试失败
    package.loaded['upgrade.parser_cfg'] = nil
    package.loaded['upgrade.network_adapter_firmware_object'] = nil
    package.loaded['upgrade.upgrade_flash'] = nil
    package.loaded['upgrade.active_process'] = nil
    package.loaded['upgrade.upgrade_defs'] = nil
end

-- 测试模块存在
function TEST_Active_Process:test_module_exists()
    lu.assertNotNil(active_process)
    lu.assertTrue(type(active_process) == 'table')
end

-- 测试network_adapter_active_process函数存在
function TEST_Active_Process:test_active_process_function_exists()
    lu.assertNotNil(active_process.network_adapter_active_process)
    lu.assertTrue(type(active_process.network_adapter_active_process) == 'function')
end

-- 测试network_adapter_active_process - 成功场景
function TEST_Active_Process:test_active_process_success()
    -- 确保清理文件时 vos.get_file_accessible 返回 true
    local original_get_accessible = package.loaded['utils.vos'].get_file_accessible
    local get_accessible_call_count = 0
    package.loaded['utils.vos'].get_file_accessible = function(path)
        table.insert(vos_calls, {method = 'get_file_accessible', path = path})
        get_accessible_call_count = get_accessible_call_count + 1
        -- 前面的调用正常处理，后面的清理调用返回 true
        if get_accessible_call_count > 2 then
            return true  -- 清理文件时返回 true
        end
        return path ~= '/tmp/not_exist'
    end
    
    local ret = active_process.network_adapter_active_process(
        self.mock_self,
        1,
        'Nic'
    )
    
    -- 应该成功
    lu.assertEquals(ret, upgrade_defs.RET.OK)
    
    -- 验证状态设置
    lu.assertFalse(self.mock_self.is_network_adapter_activing)
    
    -- 验证UpdateActiveStatus被调用
    local has_update_status = false
    for _, call in ipairs(client_calls) do
        if call.method == 'UpdateActiveStatus' then
            has_update_status = true
            lu.assertNotNil(call.param)
        end
    end
    lu.assertTrue(has_update_status)
    
    -- 验证ParseFirmwarePackage被调用
    local has_parse = false
    for _, call in ipairs(client_calls) do
        if call.method == 'ParseFirmwarePackage' then
            has_parse = true
        end
    end
    lu.assertTrue(has_parse)
    
    -- 验证get_cfgs被调用
    lu.assertTrue(#parser_cfg_calls >= 1)
    lu.assertEquals(parser_cfg_calls[1].method, 'get_cfgs')
    
    -- 验证upgrade_flash被调用
    lu.assertTrue(#upgrade_flash_calls >= 1)
    lu.assertEquals(upgrade_flash_calls[1].method, 'network_adapter_upgrade_flash')
    
    -- 验证加锁和解锁
    local lock_calls = {}
    for _, call in ipairs(fructl_calls) do
        if call.method == 'set_poweron_lock_until_success' then
            table.insert(lock_calls, call)
        end
    end
    lu.assertEquals(#lock_calls, 2)
    lu.assertEquals(lock_calls[1].state, true)  -- 加锁
    lu.assertEquals(lock_calls[2].state, false) -- 解锁
    
    -- 验证清理文件
    local has_remove = false
    for _, call in ipairs(utils_calls) do
        if call.method == 'remove_file' then
            has_remove = true
        end
    end
    lu.assertTrue(has_remove, 'Expected cleanup to call remove_file, but it did not')
    
    -- 恢复原始函数
    package.loaded['utils.vos'].get_file_accessible = original_get_accessible
end

-- 测试network_adapter_active_process - 缓存目录不存在
function TEST_Active_Process:test_active_process_cache_dir_not_exist()
    -- Mock缓存目录不存在
    local original_get_accessible = package.loaded['utils.vos'].get_file_accessible
    package.loaded['utils.vos'].get_file_accessible = function(path)
        table.insert(vos_calls, {method = 'get_file_accessible', path = path})
        return false
    end
    
    local ret = active_process.network_adapter_active_process(
        self.mock_self,
        1,
        'Nic'
    )
    
    -- 应该返回错误
    lu.assertEquals(ret, upgrade_defs.RET.ERR)
    lu.assertFalse(self.mock_self.is_network_adapter_activing)
    
    -- 恢复原始函数
    package.loaded['utils.vos'].get_file_accessible = original_get_accessible
end

-- 测试network_adapter_active_process - 缓存目录为空
function TEST_Active_Process:test_active_process_cache_dir_empty()
    -- Mock缓存目录为空
    local original_dir = mock_utils_core.dir
    mock_utils_core.dir = function(path)
        return {}
    end
    
    local ret = active_process.network_adapter_active_process(
        self.mock_self,
        1,
        'Nic'
    )
    
    -- 应该返回错误
    lu.assertEquals(ret, upgrade_defs.RET.ERR)
    lu.assertFalse(self.mock_self.is_network_adapter_activing)
    
    -- 恢复原始函数
    mock_utils_core.dir = original_dir
end

-- 测试network_adapter_active_process - 没有找到Firmware文件
function TEST_Active_Process:test_active_process_no_firmware_file()
    -- Mock没有Firmware文件
    local original_dir = mock_utils_core.dir
    mock_utils_core.dir = function(path)
        if path == upgrade_defs.UPGRADE_NIC_DIR then
            return {'nic.hpm', 'other_file.txt'}  -- 找到缓存文件
        elseif path:match('/tmp/release/') then
            return {'file1.bin', 'file2.txt'}  -- 解压后没有Firmware目录
        else
            return {}
        end
    end
    
    local ret = active_process.network_adapter_active_process(
        self.mock_self,
        1,
        'Nic'
    )
    
    -- 应该返回错误
    lu.assertEquals(ret, upgrade_defs.RET.ERR)
    lu.assertFalse(self.mock_self.is_network_adapter_activing)
    
    -- 恢复原始函数
    mock_utils_core.dir = original_dir
end

-- 测试network_adapter_active_process - 解析固件包失败
function TEST_Active_Process:test_active_process_parse_package_failed()
    -- Mock ParseFirmwarePackage失败（重试10次都失败）
    local original_parse = mock_client.UpdateServiceUpdateServiceParseFirmwarePackage
    mock_client.UpdateServiceUpdateServiceParseFirmwarePackage = function(self, ctx, file_path)
        table.insert(client_calls, {method = 'ParseFirmwarePackage'})
        error('parse failed')
    end
    
    local ret = active_process.network_adapter_active_process(
        self.mock_self,
        1,
        'Nic'
    )
    
    -- 应该返回错误
    lu.assertEquals(ret, upgrade_defs.RET.ERR)
    lu.assertFalse(self.mock_self.is_network_adapter_activing)
    
    -- 应该重试了10次
    local parse_count = 0
    for _, call in ipairs(client_calls) do
        if call.method == 'ParseFirmwarePackage' then
            parse_count = parse_count + 1
        end
    end
    lu.assertEquals(parse_count, 10)
    
    -- 恢复原始函数
    mock_client.UpdateServiceUpdateServiceParseFirmwarePackage = original_parse
end

-- 测试network_adapter_active_process - get_cfgs失败
function TEST_Active_Process:test_active_process_get_cfgs_failed()
    -- Mock get_cfgs返回空表
    local original_get_cfgs = mock_parser_cfg.get_cfgs
    mock_parser_cfg.get_cfgs = function(path)
        table.insert(parser_cfg_calls, {method = 'get_cfgs', path = path})
        return {}
    end
    
    -- 确保清理文件时 vos.get_file_accessible 返回 true
    local original_get_accessible = package.loaded['utils.vos'].get_file_accessible
    local get_accessible_call_count = 0
    package.loaded['utils.vos'].get_file_accessible = function(path)
        table.insert(vos_calls, {method = 'get_file_accessible', path = path})
        get_accessible_call_count = get_accessible_call_count + 1
        -- 前面的调用正常处理，后面的清理调用返回 true
        if get_accessible_call_count > 2 then
            return true  -- 清理文件时返回 true
        end
        return path ~= '/tmp/not_exist'
    end
    
    local ret = active_process.network_adapter_active_process(
        self.mock_self,
        1,
        'Nic'
    )
    
    -- 应该返回错误
    lu.assertEquals(ret, upgrade_defs.RET.ERR)
    lu.assertFalse(self.mock_self.is_network_adapter_activing)
    
    -- 应该清理文件
    local has_remove = false
    for _, call in ipairs(utils_calls) do
        if call.method == 'remove_file' then
            has_remove = true
        end
    end
    lu.assertTrue(has_remove, 'Expected cleanup to call remove_file, but it did not')
    
    -- 恢复原始函数
    mock_parser_cfg.get_cfgs = original_get_cfgs
    package.loaded['utils.vos'].get_file_accessible = original_get_accessible
end

-- 测试network_adapter_active_process - upgrade_flash失败
function TEST_Active_Process:test_active_process_upgrade_flash_failed()
    -- Mock upgrade_flash返回错误
    local original_upgrade_flash = mock_upgrade_flash.network_adapter_upgrade_flash
    mock_upgrade_flash.network_adapter_upgrade_flash = function(self, file_path)
        table.insert(upgrade_flash_calls, {method = 'network_adapter_upgrade_flash'})
        return upgrade_defs.RET.ERR
    end
    
    -- 确保清理文件时 vos.get_file_accessible 返回 true
    local original_get_accessible = package.loaded['utils.vos'].get_file_accessible
    local get_accessible_call_count = 0
    package.loaded['utils.vos'].get_file_accessible = function(path)
        table.insert(vos_calls, {method = 'get_file_accessible', path = path})
        get_accessible_call_count = get_accessible_call_count + 1
        -- 前面的调用正常处理，后面的清理调用返回 true
        if get_accessible_call_count > 2 then
            return true  -- 清理文件时返回 true
        end
        return path ~= '/tmp/not_exist'
    end
    
    local ret = active_process.network_adapter_active_process(
        self.mock_self,
        1,
        'Nic'
    )
    
    -- 应该返回错误
    lu.assertEquals(ret, upgrade_defs.RET.ERR)
    lu.assertFalse(self.mock_self.is_network_adapter_activing)
    
    -- 应该解除上电锁
    local unlock_count = 0
    for _, call in ipairs(fructl_calls) do
        if call.method == 'set_poweron_lock_until_success' and call.state == false then
            unlock_count = unlock_count + 1
        end
    end
    lu.assertEquals(unlock_count, 1)
    
    -- 应该清理文件
    local has_remove = false
    for _, call in ipairs(utils_calls) do
        if call.method == 'remove_file' then
            has_remove = true
        end
    end
    lu.assertTrue(has_remove, 'Expected cleanup to call remove_file, but it did not')
    
    -- 恢复原始函数
    mock_upgrade_flash.network_adapter_upgrade_flash = original_upgrade_flash
    package.loaded['utils.vos'].get_file_accessible = original_get_accessible
end

-- 测试network_adapter_active_process - upgrade_flash抛出异常
function TEST_Active_Process:test_active_process_upgrade_flash_exception()
    -- Mock upgrade_flash抛出异常
    local original_upgrade_flash = mock_upgrade_flash.network_adapter_upgrade_flash
    mock_upgrade_flash.network_adapter_upgrade_flash = function(self, file_path)
        error('upgrade flash exception')
    end
    
    local ret = active_process.network_adapter_active_process(
        self.mock_self,
        1,
        'Nic'
    )
    
    -- 应该捕获异常并返回错误
    lu.assertEquals(ret, upgrade_defs.RET.ERR)
    lu.assertFalse(self.mock_self.is_network_adapter_activing)
    
    -- 应该解除上电锁
    local unlock_count = 0
    for _, call in ipairs(fructl_calls) do
        if call.method == 'set_poweron_lock_until_success' and call.state == false then
            unlock_count = unlock_count + 1
        end
    end
    lu.assertEquals(unlock_count, 1)
    
    -- 恢复原始函数
    mock_upgrade_flash.network_adapter_upgrade_flash = original_upgrade_flash
end

-- 测试network_adapter_active_process - UpdateActiveStatus调用
function TEST_Active_Process:test_active_process_update_active_status()
    active_process.network_adapter_active_process(
        self.mock_self,
        1,
        'Nic'
    )
    
    -- 验证UpdateActiveStatus被调用，且参数正确
    local status_calls = {}
    for _, call in ipairs(client_calls) do
        if call.method == 'UpdateActiveStatus' then
            table.insert(status_calls, call)
        end
    end
    
    lu.assertTrue(#status_calls >= 1)
    
    -- 验证参数包含FirmwareId, FirmwareType, ActiveStatus
    local param = status_calls[1].param
    lu.assertNotNil(param)
    
    local has_firmware_id = false
    local has_firmware_type = false
    local has_active_status = false
    for _, item in ipairs(param) do
        if item.Key == 'FirmwareId' then
            has_firmware_id = true
        elseif item.Key == 'FirmwareType' then
            has_firmware_type = true
        elseif item.Key == 'ActiveStatus' then
            has_active_status = true
            lu.assertEquals(item.Value, 'Apply')
        end
    end
    
    lu.assertTrue(has_firmware_id)
    lu.assertTrue(has_firmware_type)
    lu.assertTrue(has_active_status)
end

-- 测试network_adapter_active_process - 状态管理
function TEST_Active_Process:test_active_process_state_management()
    -- 初始状态
    lu.assertFalse(self.mock_self.is_network_adapter_activing)
    
    -- 执行active_process
    active_process.network_adapter_active_process(
        self.mock_self,
        1,
        'Nic'
    )
    
    -- 执行完成后状态应该被清除
    lu.assertFalse(self.mock_self.is_network_adapter_activing)
end

-- 测试network_adapter_active_process - 清理文件逻辑
function TEST_Active_Process:test_active_process_cleanup_files()
    -- 确保 vos.get_file_accessible 对所有路径都返回 true，以便触发清理
    local original_get_accessible = package.loaded['utils.vos'].get_file_accessible
    package.loaded['utils.vos'].get_file_accessible = function(path)
        table.insert(vos_calls, {method = 'get_file_accessible', path = path})
        return true  -- 总是返回 true 以确保清理逻辑被触发
    end
    
    active_process.network_adapter_active_process(
        self.mock_self,
        1,
        'Nic'
    )
    
    -- 应该清理hpm文件和解压目录
    local remove_calls = {}
    for _, call in ipairs(utils_calls) do
        if call.method == 'remove_file' then
            table.insert(remove_calls, call)
        end
    end
    
    -- cleanup_upgrade_files 会删除 hpm_path 和 dir
    -- 在成功流程中应该有2次 remove_file 调用
    lu.assertTrue(#remove_calls >= 2, 
        string.format('Expected at least 2 remove_file calls (hpm_path and dir), got %d. Calls: %s', 
            #remove_calls, 
            table.concat((function()
                local paths = {}
                for _, c in ipairs(remove_calls) do
                    table.insert(paths, c.path or 'unknown')
                end
                return paths
            end)(), ', ')))
    
    -- 恢复原始函数
    package.loaded['utils.vos'].get_file_accessible = original_get_accessible
end

-- 测试network_adapter_active_process - 上电锁逻辑
function TEST_Active_Process:test_active_process_power_lock()
    active_process.network_adapter_active_process(
        self.mock_self,
        1,
        'Nic'
    )
    
    -- 验证上电锁的加锁和解锁顺序
    local lock_sequence = {}
    for _, call in ipairs(fructl_calls) do
        if call.method == 'set_poweron_lock_until_success' then
            table.insert(lock_sequence, call.state)
        end
    end
    
    -- 应该是先加锁(true)，再解锁(false)
    lu.assertEquals(#lock_sequence, 2)
    lu.assertEquals(lock_sequence[1], true)
    lu.assertEquals(lock_sequence[2], false)
end

-- 测试network_adapter_active_process - ParseFirmwarePackage重试机制
function TEST_Active_Process:test_active_process_parse_retry_success()
    local parse_attempts = 0
    -- Mock前5次失败，第6次成功
    local original_parse = mock_client.UpdateServiceUpdateServiceParseFirmwarePackage
    mock_client.UpdateServiceUpdateServiceParseFirmwarePackage = function(self, ctx, file_path)
        table.insert(client_calls, {method = 'ParseFirmwarePackage'})
        parse_attempts = parse_attempts + 1
        if parse_attempts <= 5 then
            error('parse failed')
        end
        return {
            FirmwareDirectory = '/tmp/release/',
            FirmwareName = 'Firmware1'
        }
    end
    
    local ret = active_process.network_adapter_active_process(
        self.mock_self,
        1,
        'Nic'
    )
    
    -- 应该成功
    lu.assertEquals(ret, upgrade_defs.RET.OK)
    
    -- 应该重试了6次
    lu.assertEquals(parse_attempts, 6)
    
    -- 恢复原始函数
    mock_client.UpdateServiceUpdateServiceParseFirmwarePackage = original_parse
end

-- ========== 新增测试用例以提高代码覆盖率 ==========

-- 测试active_process - ParseFirmwarePackage重试1次后成功
function TEST_Active_Process:test_active_process_parse_retry_once()
    local parse_attempts = 0
    local original_parse = mock_client.UpdateServiceUpdateServiceParseFirmwarePackage
    mock_client.UpdateServiceUpdateServiceParseFirmwarePackage = function(self, ctx, file_path)
        table.insert(client_calls, {method = 'ParseFirmwarePackage'})
        parse_attempts = parse_attempts + 1
        if parse_attempts == 1 then
            error('parse failed first time')
        end
        return {
            FirmwareDirectory = '/tmp/release/',
            FirmwareName = 'Firmware1'
        }
    end
    
    local ret = active_process.network_adapter_active_process(
        self.mock_self,
        1,
        'Nic'
    )
    
    lu.assertEquals(ret, upgrade_defs.RET.OK)
    lu.assertEquals(parse_attempts, 2)
    
    -- 恢复
    mock_client.UpdateServiceUpdateServiceParseFirmwarePackage = original_parse
end

-- 测试active_process - get_firmware_name没找到Firmware文件
function TEST_Active_Process:test_active_process_no_firmware_in_dir()
    local original_dir = mock_utils_core.dir
    mock_utils_core.dir = function(path)
        if path == upgrade_defs.UPGRADE_NIC_DIR then
            return {'nic.hpm'}
        elseif path:match('/tmp/release/') then
            return {'file1.txt', 'file2.bin', 'other.tar'}  -- 没有Firmware开头的文件
        else
            return {}
        end
    end
    
    local ret = active_process.network_adapter_active_process(
        self.mock_self,
        1,
        'Nic'
    )
    
    lu.assertEquals(ret, upgrade_defs.RET.ERR)
    
    -- 恢复
    mock_utils_core.dir = original_dir
end

-- 测试active_process - UpdateActiveStatus调用时参数完整性
function TEST_Active_Process:test_active_process_update_status_params()
    local status_param = nil
    local original_update = mock_client.FirmwareActiveFirmwareActiveUpdateActiveStatus
    mock_client.FirmwareActiveFirmwareActiveUpdateActiveStatus = function(self, ctx, param)
        status_param = param
        table.insert(client_calls, {
            method = 'UpdateActiveStatus',
            param = param
        })
        return true
    end
    
    local ret = active_process.network_adapter_active_process(
        self.mock_self,
        1,
        'Nic'
    )
    
    lu.assertEquals(ret, upgrade_defs.RET.OK)
    lu.assertNotNil(status_param)
    lu.assertEquals(#status_param, 3)  -- 应该有3个参数
    
    -- 恢复
    mock_client.FirmwareActiveFirmwareActiveUpdateActiveStatus = original_update
end

-- 测试active_process - 清理时hpm文件不存在
function TEST_Active_Process:test_active_process_cleanup_hpm_not_exist()
    local original_get_accessible = package.loaded['utils.vos'].get_file_accessible
    local call_count = 0
    package.loaded['utils.vos'].get_file_accessible = function(path)
        table.insert(vos_calls, {method = 'get_file_accessible', path = path})
        call_count = call_count + 1
        if call_count <= 2 then
            return true  -- 前面的调用返回true
        end
        if path:match('%.hpm$') then
            return false  -- hpm文件不存在
        end
        return true
    end
    
    local ret = active_process.network_adapter_active_process(
        self.mock_self,
        1,
        'Nic'
    )
    
    lu.assertEquals(ret, upgrade_defs.RET.OK)
    
    -- 恢复
    package.loaded['utils.vos'].get_file_accessible = original_get_accessible
end

-- 测试active_process - 清理时解压目录不存在
function TEST_Active_Process:test_active_process_cleanup_dir_not_exist()
    local original_get_accessible = package.loaded['utils.vos'].get_file_accessible
    local call_count = 0
    package.loaded['utils.vos'].get_file_accessible = function(path)
        table.insert(vos_calls, {method = 'get_file_accessible', path = path})
        call_count = call_count + 1
        if call_count <= 2 then
            return true
        end
        if path:match('release') then
            return false  -- 解压目录不存在
        end
        return true
    end
    
    local ret = active_process.network_adapter_active_process(
        self.mock_self,
        1,
        'Nic'
    )
    
    lu.assertEquals(ret, upgrade_defs.RET.OK)
    
    -- 恢复
    package.loaded['utils.vos'].get_file_accessible = original_get_accessible
end

-- 测试active_process - 状态标志正确设置和清除
function TEST_Active_Process:test_active_process_state_flag_lifecycle()
    -- 初始状态
    self.mock_self.is_network_adapter_activing = false
    
    -- 执行active_process过程中，状态应该被设置
    local state_during_process = nil
    local original_upgrade_flash = mock_upgrade_flash.network_adapter_upgrade_flash
    mock_upgrade_flash.network_adapter_upgrade_flash = function(self, file_path)
        state_during_process = self.is_network_adapter_activing
        table.insert(upgrade_flash_calls, {method = 'network_adapter_upgrade_flash'})
        return 0
    end
    
    active_process.network_adapter_active_process(
        self.mock_self,
        1,
        'Nic'
    )
    
    -- 过程中应该为true
    lu.assertTrue(state_during_process)
    
    -- 结束后应该为false
    lu.assertFalse(self.mock_self.is_network_adapter_activing)
    
    -- 恢复
    mock_upgrade_flash.network_adapter_upgrade_flash = original_upgrade_flash
end

-- 测试active_process - 加锁和解锁的参数正确性
function TEST_Active_Process:test_active_process_lock_unlock_params()
    active_process.network_adapter_active_process(
        self.mock_self,
        1,
        'Nic'
    )
    
    local lock_call = nil
    local unlock_call = nil
    
    for _, call in ipairs(fructl_calls) do
        if call.method == 'set_poweron_lock_until_success' then
            if call.state == true then
                lock_call = call
            else
                unlock_call = call
            end
        end
    end
    
    lu.assertNotNil(lock_call)
    lu.assertNotNil(unlock_call)
    
    -- 验证参数
    lu.assertEquals(lock_call.sys_id, 1)
    lu.assertEquals(lock_call.reason, 'Nic')
    lu.assertEquals(unlock_call.sys_id, 1)
    lu.assertEquals(unlock_call.reason, 'Nic')
end

-- 测试active_process - ParseFirmwarePackage返回nil
function TEST_Active_Process:test_active_process_parse_returns_nil()
    local original_parse = mock_client.UpdateServiceUpdateServiceParseFirmwarePackage
    mock_client.UpdateServiceUpdateServiceParseFirmwarePackage = function(self, ctx, file_path)
        table.insert(client_calls, {method = 'ParseFirmwarePackage'})
        return nil  -- 返回nil
    end
    
    local ret = active_process.network_adapter_active_process(
        self.mock_self,
        1,
        'Nic'
    )
    
    lu.assertEquals(ret, upgrade_defs.RET.ERR)
    
    -- 恢复
    mock_client.UpdateServiceUpdateServiceParseFirmwarePackage = original_parse
end

-- 测试active_process - ParseFirmwarePackage返回空的FirmwareDirectory
function TEST_Active_Process:test_active_process_parse_empty_directory()
    local original_parse = mock_client.UpdateServiceUpdateServiceParseFirmwarePackage
    mock_client.UpdateServiceUpdateServiceParseFirmwarePackage = function(self, ctx, file_path)
        table.insert(client_calls, {method = 'ParseFirmwarePackage'})
        return {
            FirmwareDirectory = nil,  -- 目录为nil
            FirmwareName = 'Firmware1'
        }
    end
    
    local ret = active_process.network_adapter_active_process(
        self.mock_self,
        1,
        'Nic'
    )
    
    lu.assertEquals(ret, upgrade_defs.RET.ERR)
    
    -- 恢复
    mock_client.UpdateServiceUpdateServiceParseFirmwarePackage = original_parse
end

-- 测试active_process - 多个Firmware文件，匹配第一个
function TEST_Active_Process:test_active_process_multiple_firmware_files()
    local original_dir = mock_utils_core.dir
    mock_utils_core.dir = function(path)
        if path == upgrade_defs.UPGRADE_NIC_DIR then
            return {'nic.hpm'}
        elseif path:match('/tmp/release/') then
            return {'Firmware1', 'Firmware2', 'Firmware3'}  -- 多个Firmware文件
        else
            return {}
        end
    end
    
    local ret = active_process.network_adapter_active_process(
        self.mock_self,
        1,
        'Nic'
    )
    
    lu.assertEquals(ret, upgrade_defs.RET.OK)
    
    -- 恢复
    mock_utils_core.dir = original_dir
end

-- 测试active_process - upgrade_flash返回非OK状态
function TEST_Active_Process:test_active_process_upgrade_flash_returns_error_code()
    local original_upgrade_flash = mock_upgrade_flash.network_adapter_upgrade_flash
    mock_upgrade_flash.network_adapter_upgrade_flash = function(self, file_path)
        table.insert(upgrade_flash_calls, {method = 'network_adapter_upgrade_flash'})
        return upgrade_defs.RET.ERR  -- 返回错误码（-1）
    end
    
    local ret = active_process.network_adapter_active_process(
        self.mock_self,
        1,
        'Nic'
    )
    
    -- execute_active_upgrade 直接返回 upgrade_flash 的返回值
    lu.assertEquals(ret, upgrade_defs.RET.ERR)
    
    -- 恢复
    mock_upgrade_flash.network_adapter_upgrade_flash = original_upgrade_flash
end

-- 测试active_process - find_cached_upgrade_file找到文件
function TEST_Active_Process:test_active_process_find_cached_file_success()
    local file_found = false
    local original_dir = mock_utils_core.dir
    mock_utils_core.dir = function(path)
        if path == upgrade_defs.UPGRADE_NIC_DIR then
            file_found = true
            return {'nic.hpm', 'other.txt'}  -- 包含目标文件
        elseif path:match('/tmp/release/') then
            return {'Firmware1'}
        else
            return {}
        end
    end
    
    local ret = active_process.network_adapter_active_process(
        self.mock_self,
        1,
        'Nic'
    )
    
    lu.assertEquals(ret, upgrade_defs.RET.OK)
    lu.assertTrue(file_found)
    
    -- 恢复
    mock_utils_core.dir = original_dir
end

return TEST_Active_Process
