local lu = require 'luaunit'
local c_drive = require 'drive.drive_object'
local c_storageconfig = require 'storageconfig.storageconfig_object'
local common_def = require 'common_def'
local method_misc = require 'method_misc'
local sml = require 'sml'
local skynet = require 'skynet'
local c_drives_object = require 'drives.drives_object'

local hook_tasks = require 'hook_tasks'

TEST_Drive_Object = {}

local function with_patch(tbl, key, val, fn)
    local orig = tbl[key]
    tbl[key] = val
    local ok, err = pcall(fn)
    tbl[key] = orig
    if not ok then
        error(err)
    end
end

local function with_patch_global(key, val, fn)
    local orig = _G[key]
    _G[key] = val
    local ok, err = pcall(fn)
    _G[key] = orig
    if not ok then
        error(err)
    end
end

function TEST_Drive_Object:setUp()
    self.tasks = hook_tasks:hook()
end

function TEST_Drive_Object:tearDown()
    hook_tasks.unhook()
end

function TEST_Drive_Object:test_monitor_fault_state()
    local config = c_storageconfig.new({bus = 0, db = 1})
    config.all_ctrl_loaded = false
    local obj = {
        new_task = function(...) return {
            loop = function(obj, cb)
                cb(1)
                return {set_timeout_ms = function(...) return end}
            end
        } end,
        Protocol = 3,
        RefControllerId = 0,
        Presence = 0,
        LocateLed = 0,
        FaultLed = 1,
        InAFailedArray = 2,
        cont_bin = {
            get_debounced_val = function(i, n) return n end,
            clear_debounced_val = function() end
        },
        FirmwareStatusError = true
    }
    c_drive.monitor_fault_state(obj)
    lu.assertEquals(obj.InAFailedArray, 1)
    obj.Presence = 1
    c_drive.monitor_fault_state(obj)
    lu.assertEquals(obj.InAFailedArray, 0)
end

function TEST_Drive_Object:test_nvme_identified()
    local config = c_storageconfig.new({bus = 0, db = 1})
    config.all_ctrl_loaded = false
    local obj = {
        process_when_nvme_removed = function(nvme_obj)
            nvme_obj.SerialNumber = 'test'
        end
    }
    c_drive.nvme_identified(obj)
    lu.assertEquals(obj.SerialNumber, 'test')
end

function TEST_Drive_Object:test_nvme_identified_with_object()
    local config = c_storageconfig.new({bus = 0, db = 1})
    local init_nvme_flag = false
    local update_smart_info = false
    config.all_ctrl_loaded = false
    local obj = {
        update_by_mctp = function ()
            init_nvme_flag = true
        end,
        update_dynamic_info = function ()
        end,
        update_nvme_smart_log_info = function ()
        end,
        update_subhealth_info_from_mctp = function ()
            update_smart_info = true
        end,
        new_task = function(...) return {
            loop = function(obj, cb)
                task = {
                    stop = function()
                    end
                }
                cb(task)
                return {set_timeout_ms = function(...) return end}
            end
        } end
    }
    local mock_nvme = {
        protocol = 0,
        init_nvme_mi_mctp = function()
            return true
        end
    }
    c_drive.nvme_identified(obj, mock_nvme)
    lu.assertTrue(init_nvme_flag, "通过MCTP更新信息")
    c_drive.update_by_mctp(obj, mock_nvme)
    lu.assertTrue(update_smart_info, "更新subhealth")
end

-- 测试nvme_static_identified函数 - 全量覆盖
function TEST_Drive_Object:test_nvme_static_identified_with_nvme_object()
    -- 测试用例1：nvme对象存在且identify_pd为false的情况
    local task_created = false
    local task_loop_executed = false
    local static_info_updated = false
    local asset_info_updated = false
    local timeout_set_correctly = false

    local mock_nvme = {
        -- 模拟nvme对象
        slot = 1,
        model = "Test NVMe"
    }

    local task_obj = {}
    local obj = {
        ObjectName = "TestDrive",
        identify_pd = false,
        new_task = function(self, task_name)
            task_created = true
            lu.assertEquals(task_name[1], 'update_nvme_static')
            lu.assertEquals(task_name[2], "TestDrive")
            return task_obj
        end
    }

    -- 为task_obj添加loop方法
    task_obj.loop = function(self, callback)
        task_loop_executed = true
        -- 执行回调函数测试内部逻辑
        callback()
        return self -- 返回自身以支持链式调用
    end

    -- 为task_obj添加set_timeout_ms方法
    task_obj.set_timeout_ms = function(self, timeout)
        timeout_set_correctly = (timeout == 120000)
        return self -- 返回自身以支持链式调用
    end

    -- 为obj添加其他方法
    obj.update_drive_static_info_by_sepecific_obj = function(self, nvme)
        static_info_updated = true
        lu.assertEquals(nvme, mock_nvme)
    end

    obj.update_asset_data_info = function(self)
        asset_info_updated = true
    end

    -- 执行测试
    c_drive.nvme_static_identified(obj, mock_nvme)

    -- 验证结果
    lu.assertTrue(task_created, "任务应该被创建")
    lu.assertTrue(task_loop_executed, "任务循环应该被执行")
    lu.assertTrue(static_info_updated, "静态信息应该被更新")
    lu.assertTrue(asset_info_updated, "资产信息应该被更新")
    lu.assertTrue(timeout_set_correctly, "超时时间应该设置为120000毫秒")
end

function TEST_Drive_Object:test_nvme_static_identified_with_identify_pd_true()
    -- 测试用例2：nvme对象存在但identify_pd为true的情况（应该提前返回）
    local task_created = false
    local static_info_updated = false
    local asset_info_updated = false

    local mock_nvme = {
        slot = 1,
        model = "Test NVMe"
    }

    local task_obj = {}
    local obj = {
        ObjectName = "TestDrive",
        identify_pd = true, -- 设置为true，应该提前返回
        new_task = function(self, task_name)
            task_created = true
            return task_obj
        end
    }

    -- 为task_obj添加loop方法
    task_obj.loop = function(self, callback)
        -- 执行回调函数测试内部逻辑
        callback()
        return self -- 返回自身以支持链式调用
    end

    -- 为task_obj添加set_timeout_ms方法
    task_obj.set_timeout_ms = function(self, timeout)
        return self -- 返回自身以支持链式调用
    end

    -- 为obj添加其他方法
    obj.update_drive_static_info_by_sepecific_obj = function(self, nvme)
        static_info_updated = true
    end

    obj.update_asset_data_info = function(self)
        asset_info_updated = true
    end

    -- 执行测试
    c_drive.nvme_static_identified(obj, mock_nvme)

    -- 验证结果
    lu.assertTrue(task_created, "任务应该被创建")
    lu.assertFalse(static_info_updated, "identify_pd为true时，静态信息不应该被更新")
    lu.assertFalse(asset_info_updated, "identify_pd为true时，资产信息不应该被更新")
end

function TEST_Drive_Object:test_nvme_static_identified_with_nil_nvme()
    -- 测试用例3：nvme对象为nil的情况（应该停止任务）
    local stop_task_called = false
    local stopped_task_name = nil

    local obj = {
        ObjectName = "TestDrive",
        stop_task = function(self, task_name)
            stop_task_called = true
            stopped_task_name = task_name
        end
    }

    -- 执行测试
    c_drive.nvme_static_identified(obj, nil)

    -- 验证结果
    lu.assertTrue(stop_task_called, "应该调用stop_task")
    lu.assertEquals(stopped_task_name[1], 'update_nvme_static')
    lu.assertEquals(stopped_task_name[2], "TestDrive")
end

function TEST_Drive_Object:test_nvme_static_identified_edge_cases()
    -- 测试用例4：边界情况测试
    local function_calls = {}

    local task_obj = {}
    local obj = {
        ObjectName = "",   -- 空字符串测试
        identify_pd = nil, -- nil值测试
        new_task = function(self, task_name)
            table.insert(function_calls, "new_task")
            return task_obj
        end
    }

    -- 为task_obj添加loop方法
    task_obj.loop = function(self, callback)
        table.insert(function_calls, "loop")
        callback()
        return self -- 返回自身以支持链式调用
    end

    -- 为task_obj添加set_timeout_ms方法
    task_obj.set_timeout_ms = function(self, timeout)
        table.insert(function_calls, "set_timeout_ms")
        return self -- 返回自身以支持链式调用
    end

    -- 为obj添加其他方法
    obj.update_drive_static_info_by_sepecific_obj = function(self, nvme)
        table.insert(function_calls, "update_drive_static_info_by_sepecific_obj")
    end

    obj.update_asset_data_info = function(self)
        table.insert(function_calls, "update_asset_data_info")
    end

    local mock_nvme = {}

    -- 执行测试
    c_drive.nvme_static_identified(obj, mock_nvme)

    -- 验证调用顺序
    local expected_calls = { "new_task", "loop", "update_drive_static_info_by_sepecific_obj", "update_asset_data_info",
        "set_timeout_ms" }
    lu.assertEquals(function_calls, expected_calls)
end

function TEST_Drive_Object:test_nvme_static_identified_task_name_generation()
    -- 测试用例5：测试任务名称生成的正确性
    local captured_task_names = {}

    local task_obj = {}
    local obj = {
        ObjectName = "Drive_Slot_5",
        identify_pd = false,
        new_task = function(self, task_name)
            table.insert(captured_task_names, { task_name[1], task_name[2] })
            return task_obj
        end
    }

    -- 为task_obj添加loop方法
    task_obj.loop = function(self, callback)
        callback()
        return self -- 返回自身以支持链式调用
    end

    -- 为task_obj添加set_timeout_ms方法
    task_obj.set_timeout_ms = function(self, timeout)
        return self -- 返回自身以支持链式调用
    end

    -- 为obj添加其他方法
    obj.update_drive_static_info_by_sepecific_obj = function(self, nvme) end
    obj.update_asset_data_info = function(self) end

    local mock_nvme = { model = "Samsung NVMe" }

    -- 执行测试
    c_drive.nvme_static_identified(obj, mock_nvme)

    -- 验证任务名称
    lu.assertEquals(#captured_task_names, 1)
    lu.assertEquals(captured_task_names[1][1], 'update_nvme_static')
    lu.assertEquals(captured_task_names[1][2], "Drive_Slot_5")
end

function TEST_Drive_Object:test_update_static_drive_info()
    local obj = {
        model = "Test Model",
        manufacturer = "Test Manufacturer",
        firmware_version = "1.0.0",
        interface_type = "NVMe",
        media_type = "SSD",
        serial_num = "123456789",
        form_factor = "2.5 inch"
    }

    drive = {RefControllerTypeId = 1}

    c_drive.update_static_drive_info(drive, obj)

    lu.assertEquals(drive.Model, "Test Model")
    lu.assertEquals(drive.Manufacturer, "Test Manufacturer")
    lu.assertEquals(drive.Revision, "1.0.0")
    lu.assertEquals(drive.Protocol, "NVMe")
    lu.assertEquals(drive.MediaType, "SSD")
    lu.assertEquals(drive.SerialNumber, "123456789")
    lu.assertEquals(drive.FormFactor, "2.5 inch")
end

-- 测试update_nvme_systemid函数 - nvme_configs为空的情况
-- 测试目的：验证当config_manager的nvme_configs为空时，函数应该提前返回，不设置system_id
-- 前置条件：config_manager.get_instance().nvme_configs为空表
-- 测试步骤：调用update_nvme_systemid函数
-- 预期结果：nvme.system_id应该为nil，函数提前返回
function TEST_Drive_Object:test_update_nvme_systemid_empty_configs()
    local config_manager = require 'config_manager'
    local original_get_instance = config_manager.get_instance
    
    -- Mock config_manager实例，设置nvme_configs为空表
    local mock_instance = {
        nvme_configs = {}
    }
    config_manager.get_instance = function()
        return mock_instance
    end

    -- 准备测试数据
    local drive_obj = {
        Id = 1,
        board_path = '',
        ObjectIdentifier = {1, 2, 3, 'test_segment'}
    }
    local nvme = {
        Slot = 1
    }

    -- 执行测试
    c_drive.update_nvme_systemid(drive_obj, nvme)

    -- 验证结果：由于nvme_configs为空，函数应该提前返回，system_id应该为nil
    lu.assertNil(nvme.system_id)

    -- 恢复原始函数
    config_manager.get_instance = original_get_instance
end

-- 测试update_nvme_systemid函数 - board_path为空，需要获取board_obj的完整流程
-- 测试目的：验证当drive_obj的board_path为空时，函数能够通过get_board_obj_prop获取board_path，
--           并成功调用mdb.get_object和config_manager.get_nvme_systemid来设置system_id
-- 前置条件：config_manager的nvme_configs不为空，drive_obj.board_path为空字符串
-- 测试步骤：
--   1. 调用get_board_obj_prop获取board对象信息
--   2. 设置drive_obj.board_path
--   3. 调用mdb.get_object获取backplane对象
--   4. 调用config_manager.get_nvme_systemid获取system_id
-- 预期结果：drive_obj.board_path应该被设置为'/test/path'，nvme.system_id应该被设置为100
function TEST_Drive_Object:test_update_nvme_systemid_get_board_path()
    local config_manager = require 'config_manager'
    local mdb = require 'mc.mdb'
    local object_manage = require 'mc.orm.object_manage'
    local client = require 'storage.client'

    -- 保存原始函数引用，用于测试后恢复
    local original_get_instance_cm = config_manager.get_instance
    local original_get_instance_om = object_manage.get_instance
    local original_get_object = mdb.get_object
    local original_get_board_objects = client.GetBoardObjects

    -- Mock config_manager实例，包含nvme_configs和get_nvme_systemid方法
    local mock_config_instance = {
        nvme_configs = {
            {MultiHostMappings = {}}
        },
        get_nvme_systemid = function(self, uid, slot_id)
            -- 验证参数正确性
            lu.assertEquals(uid, 'test_uid')
            lu.assertEquals(slot_id, 1)
            return 100
        end
    }
    config_manager.get_instance = function()
        return mock_config_instance
    end

    -- Mock object_manage实例，提供bus对象
    local mock_om_instance = {
        bus = 'test_bus'
    }
    object_manage.get_instance = function()
        return mock_om_instance
    end

    -- Mock mdb.get_object，验证调用参数并返回backplane对象
    local mock_board_obj = {
        UID = 'test_uid',
        path = '/test/path'
    }
    mdb.get_object = function(bus, path, interface)
        -- 验证mdb.get_object的调用参数
        lu.assertEquals(bus, 'test_bus')
        lu.assertEquals(path, '/test/path')
        lu.assertEquals(interface, 'bmc.kepler.Systems.Board.Unit')
        return mock_board_obj
    end

    -- Mock client.GetBoardObjects，返回匹配的board对象
    -- 注意：get_board_obj_prop使用string.match(path, '.*_(.+)')提取路径最后一个下划线后的段
    -- 对于路径'/test/path_test_segment'，string.match会提取出'test_segment'
    -- 需要与drive_obj.ObjectIdentifier[4]匹配
    -- 路径格式：最后一个下划线后的部分应该等于ObjectIdentifier[4]
    -- 例如：路径'/test/path_test_segment'匹配ObjectIdentifier[4]='test_segment'
    local mock_board_objects = {
        ['/test/path_test_segment'] = {
            Position = 'test_position',
            NodeId = 'test_node',
            SilkText = 'test_silk',
            path = '/test/path'  -- 这个path会被get_board_obj_prop提取并设置到drive_obj.board_path
        }
    }
    -- Mock GetBoardObjects方法，支持冒号调用（client:GetBoardObjects()）
    -- 冒号调用会自动传递self作为第一个参数，但这里我们忽略self参数
    -- client是一个实例对象，GetBoardObjects是它的方法
    client.GetBoardObjects = function(self)
        return mock_board_objects
    end

    -- 准备测试数据：drive_obj的board_path为空，需要通过get_board_obj_prop获取
    -- ObjectIdentifier[4] = 'test_segment' 用于匹配board对象的路径
    -- get_board_obj_prop会从路径中提取最后一个下划线后的段进行匹配
    -- string.match('/test/path_test_segment', '.*_(.+)') 会返回 'test_segment'
    local drive_obj = {
        Id = 1,
        board_path = '',
        ObjectIdentifier = {1, 2, 3, 'segment'}  -- 用于匹配board对象路径中的最后一个段
    }
    local nvme = {
        Slot = 1
    }

    -- 执行测试
    c_drive.update_nvme_systemid(drive_obj, nvme)

    -- 验证结果
    -- 1. board_path应该被正确设置（从board对象的path字段获取）
    lu.assertEquals(drive_obj.board_path, '/test/path')
    -- 2. system_id应该被正确设置（通过config_manager.get_nvme_systemid获取）
    lu.assertEquals(nvme.system_id, 100)

    -- 恢复原始函数
    config_manager.get_instance = original_get_instance_cm
    object_manage.get_instance = original_get_instance_om
    mdb.get_object = original_get_object
    client.GetBoardObjects = original_get_board_objects
end

-- 测试update_nvme_systemid函数 - board_path已存在的情况
-- 测试目的：验证当drive_obj的board_path已经存在时，函数应该直接使用该path，
--           跳过get_board_obj_prop的调用，直接调用mdb.get_object获取backplane对象
-- 前置条件：drive_obj.board_path已设置为'/existing/path'
-- 测试步骤：
--   1. 跳过get_board_obj_prop调用（因为board_path已存在）
--   2. 直接使用现有的board_path调用mdb.get_object
--   3. 调用config_manager.get_nvme_systemid获取system_id
-- 预期结果：nvme.system_id应该被设置为200，board_path保持不变
function TEST_Drive_Object:test_update_nvme_systemid_existing_board_path()
    local config_manager = require 'config_manager'
    local mdb = require 'mc.mdb'
    local object_manage = require 'mc.orm.object_manage'

    -- 保存原始函数引用
    local original_get_instance_cm = config_manager.get_instance
    local original_get_instance_om = object_manage.get_instance
    local original_get_object = mdb.get_object

    -- Mock config_manager实例
    local mock_config_instance = {
        nvme_configs = {
            {MultiHostMappings = {}}
        },
        get_nvme_systemid = function(self, uid, slot_id)
            -- 验证get_nvme_systemid的调用参数
            lu.assertEquals(uid, 'test_uid')
            lu.assertEquals(slot_id, 2)
            return 200
        end
    }
    config_manager.get_instance = function()
        return mock_config_instance
    end

    -- Mock object_manage实例
    local mock_om_instance = {
        bus = 'test_bus'
    }
    object_manage.get_instance = function()
        return mock_om_instance
    end

    -- Mock mdb.get_object，验证使用已存在的board_path
    local mock_board_obj = {
        UID = 'test_uid',
        path = '/test/path'
    }
    mdb.get_object = function(bus, path, interface)
        -- 验证使用的是已存在的board_path，而不是通过get_board_obj_prop获取的
        lu.assertEquals(bus, 'test_bus')
        lu.assertEquals(path, '/existing/path')
        return mock_board_obj
    end

    -- 准备测试数据：board_path已存在
    local drive_obj = {
        Id = 1,
        board_path = '/existing/path',  -- board_path已设置，不需要通过get_board_obj_prop获取
        ObjectIdentifier = {1, 2, 3, 'test_segment'}
    }
    local nvme = {
        Slot = 2
    }

    -- 执行测试
    c_drive.update_nvme_systemid(drive_obj, nvme)

    -- 验证结果：system_id应该被正确设置
    lu.assertEquals(nvme.system_id, 200)

    -- 恢复原始函数
    config_manager.get_instance = original_get_instance_cm
    object_manage.get_instance = original_get_instance_om
    mdb.get_object = original_get_object
end

-- 测试update_nvme_systemid函数 - get_board_obj_prop返回空对象的情况
-- 测试目的：验证当client.GetBoardObjects返回nil时，get_board_obj_prop返回空对象，
--           函数应该无法获取board_path，因此不会设置system_id
-- 前置条件：client.GetBoardObjects返回nil
-- 测试步骤：
--   1. 调用get_board_obj_prop，由于GetBoardObjects返回nil，返回空对象
--   2. board_path保持为空字符串
--   3. 由于board_path为空，不会调用mdb.get_object
-- 预期结果：drive_obj.board_path应该保持为空字符串，nvme.system_id应该为nil
function TEST_Drive_Object:test_update_nvme_systemid_empty_board_obj()
    local config_manager = require 'config_manager'
    local client = require 'storage.client'

    -- 保存原始函数引用
    local original_get_instance = config_manager.get_instance
    local original_get_board_objects = client.GetBoardObjects

    -- Mock config_manager实例
    local mock_instance = {
        nvme_configs = {
            {MultiHostMappings = {}}
        }
    }
    config_manager.get_instance = function()
        return mock_instance
    end

    -- Mock client.GetBoardObjects返回nil，模拟无法获取board对象的情况
    client.GetBoardObjects = function(self)
        return nil
    end

    -- 准备测试数据
    local drive_obj = {
        Id = 1,
        board_path = '',
        ObjectIdentifier = {1, 2, 3, 'test_segment'}
    }
    local nvme = {
        Slot = 1
    }

    -- 执行测试
    c_drive.update_nvme_systemid(drive_obj, nvme)

    -- 验证结果
    -- 1. board_path应该保持为空，因为GetBoardObjects返回nil
    lu.assertEquals(drive_obj.board_path, '')
    -- 2. system_id应该为nil，因为无法获取board_path
    lu.assertNil(nvme.system_id)

    -- 恢复原始函数
    config_manager.get_instance = original_get_instance
    client.GetBoardObjects = original_get_board_objects
end

-- 测试update_nvme_systemid函数 - get_board_obj_prop返回的board_obj没有path字段的情况
-- 测试目的：验证当GetBoardObjects返回的board对象没有path字段时，
--           函数应该无法设置board_path，因此不会设置system_id
-- 前置条件：GetBoardObjects返回的board对象缺少path字段
-- 测试步骤：
--   1. 调用get_board_obj_prop获取board对象
--   2. board对象没有path字段，board_path保持为空字符串
--   3. 由于board_path为空，不会调用mdb.get_object
-- 预期结果：drive_obj.board_path应该保持为空字符串，nvme.system_id应该为nil
function TEST_Drive_Object:test_update_nvme_systemid_board_obj_no_path()
    local config_manager = require 'config_manager'
    local client = require 'storage.client'

    -- 保存原始函数引用
    local original_get_instance = config_manager.get_instance
    local original_get_board_objects = client.GetBoardObjects

    -- Mock config_manager实例
    local mock_instance = {
        nvme_configs = {
            {MultiHostMappings = {}}
        }
    }
    config_manager.get_instance = function()
        return mock_instance
    end

    -- Mock client.GetBoardObjects返回的board对象缺少path字段
    local mock_board_objects = {
        ['/test/path_test_segment'] = {
            Position = 'test_position',
            NodeId = 'test_node',
            SilkText = 'test_silk'
            -- 注意：没有 path 字段，模拟异常情况
        }
    }
    client.GetBoardObjects = function(self)
        return mock_board_objects
    end

    -- 准备测试数据
    local drive_obj = {
        Id = 1,
        board_path = '',
        ObjectIdentifier = {1, 2, 3, 'test_segment'}
    }
    local nvme = {
        Slot = 1
    }

    -- 执行测试
    c_drive.update_nvme_systemid(drive_obj, nvme)

    -- 验证结果
    -- 1. board_path应该保持为空，因为board对象没有path字段
    lu.assertEquals(drive_obj.board_path, '')
    -- 2. system_id应该为nil，因为无法获取有效的board_path
    lu.assertNil(nvme.system_id)

    -- 恢复原始函数
    config_manager.get_instance = original_get_instance
    client.GetBoardObjects = original_get_board_objects
end

-- 测试update_nvme_systemid函数 - mdb.get_object调用失败的情况
-- 测试目的：验证当mdb.get_object抛出异常时，函数应该捕获异常并记录错误日志，
--           不会设置system_id，函数提前返回
-- 前置条件：mdb.get_object抛出异常
-- 测试步骤：
--   1. 获取board_path
--   2. 调用mdb.get_object时抛出异常
--   3. pcall捕获异常，记录错误日志
--   4. 函数提前返回
-- 预期结果：应该记录错误日志，nvme.system_id应该为nil
function TEST_Drive_Object:test_update_nvme_systemid_mdb_get_object_failed()
    local config_manager = require 'config_manager'
    local mdb = require 'mc.mdb'
    local object_manage = require 'mc.orm.object_manage'
    local client = require 'storage.client'

    -- 保存原始函数引用
    local original_get_instance_cm = config_manager.get_instance
    local original_get_instance_om = object_manage.get_instance
    local original_get_object = mdb.get_object
    local original_get_board_objects = client.GetBoardObjects

    -- Mock config_manager实例
    local mock_config_instance = {
        nvme_configs = {
            {MultiHostMappings = {}}
        }
    }
    config_manager.get_instance = function()
        return mock_config_instance
    end

    -- Mock object_manage实例
    local mock_om_instance = {
        bus = 'test_bus'
    }
    object_manage.get_instance = function()
        return mock_om_instance
    end

    -- Mock mdb.get_object抛出异常，模拟调用失败的情况
    mdb.get_object = function(bus, path, interface)
        error('mdb.get_object failed')
    end

    -- Mock client.GetBoardObjects返回有效的board对象
    local mock_board_objects = {
        ['/test/path_test_segment'] = {
            Position = 'test_position',
            NodeId = 'test_node',
            SilkText = 'test_silk',
            path = '/test/path'
        }
    }
    client.GetBoardObjects = function(self)
        return mock_board_objects
    end

    -- 准备测试数据
    local drive_obj = {
        Id = 1,
        board_path = '',
        ObjectIdentifier = {1, 2, 3, 'test_segment'}
    }
    local nvme = {
        Slot = 1
    }

    -- 执行测试
    c_drive.update_nvme_systemid(drive_obj, nvme)

    -- 验证结果：system_id应该为nil，因为mdb.get_object失败
    lu.assertNil(nvme.system_id)

    -- 恢复原始函数
    config_manager.get_instance = original_get_instance_cm
    object_manage.get_instance = original_get_instance_om
    mdb.get_object = original_get_object
    client.GetBoardObjects = original_get_board_objects
end

-- 测试update_nvme_systemid函数 - get_nvme_systemid返回nil的情况
-- 测试目的：验证当config_manager.get_nvme_systemid返回nil时（找不到匹配的配置），
--           函数应该将nvme.system_id设置为nil
-- 前置条件：所有前置步骤成功（获取board_path、mdb.get_object成功），但get_nvme_systemid返回nil
-- 测试步骤：
--   1. 获取board_path成功
--   2. 调用mdb.get_object成功，获取backplane对象
--   3. 调用config_manager.get_nvme_systemid返回nil（找不到匹配的配置）
-- 预期结果：nvme.system_id应该被设置为nil
function TEST_Drive_Object:test_update_nvme_systemid_get_systemid_nil()
    local config_manager = require 'config_manager'
    local mdb = require 'mc.mdb'
    local object_manage = require 'mc.orm.object_manage'
    local client = require 'storage.client'

    -- 保存原始函数引用
    local original_get_instance_cm = config_manager.get_instance
    local original_get_instance_om = object_manage.get_instance
    local original_get_object = mdb.get_object
    local original_get_board_objects = client.GetBoardObjects

    -- Mock config_manager实例，get_nvme_systemid返回nil，模拟找不到匹配配置的情况
    local mock_config_instance = {
        nvme_configs = {
            {MultiHostMappings = {}}
        },
        get_nvme_systemid = function(self, uid, slot_id)
            -- 返回nil，模拟找不到匹配的system_id配置
            return nil
        end
    }
    config_manager.get_instance = function()
        return mock_config_instance
    end

    -- Mock object_manage实例
    local mock_om_instance = {
        bus = 'test_bus'
    }
    object_manage.get_instance = function()
        return mock_om_instance
    end

    -- Mock mdb.get_object成功返回backplane对象
    local mock_board_obj = {
        UID = 'test_uid',
        path = '/test/path'
    }
    mdb.get_object = function(bus, path, interface)
        return mock_board_obj
    end

    -- Mock client.GetBoardObjects返回有效的board对象
    local mock_board_objects = {
        ['/test/path_test_segment'] = {
            Position = 'test_position',
            NodeId = 'test_node',
            SilkText = 'test_silk',
            path = '/test/path'
        }
    }
    client.GetBoardObjects = function(self)
        return mock_board_objects
    end

    -- 准备测试数据
    local drive_obj = {
        Id = 1,
        board_path = '',
        ObjectIdentifier = {1, 2, 3, 'test_segment'}
    }
    local nvme = {
        Slot = 1
    }

    -- 执行测试
    c_drive.update_nvme_systemid(drive_obj, nvme)

    -- 验证结果：system_id应该为nil，因为get_nvme_systemid返回nil
    lu.assertNil(nvme.system_id)

    -- 恢复原始函数
    config_manager.get_instance = original_get_instance_cm
    object_manage.get_instance = original_get_instance_om
    mdb.get_object = original_get_object
    client.GetBoardObjects = original_get_board_objects
end

function TEST_Drive_Object:test_process_when_nvme_removed()
    local ret
    local obj = {
        FaultLed = 1,
        LinkFault = true,
        stop_task = function(...) return {
            loop = function(obj, cb)
                cb(1)
                return {set_timeout_ms = function(...) return end}
            end
        } end,
        set_default_values = function()
        end,
        set_presence = function()
        end,
        set_fault_led_by_smc = function()
        end,
        set_link_fault = function()
            ret = true
        end
    }
    c_drive.process_when_nvme_removed(obj)
    lu.assertEquals(ret, true)
end


function TEST_Drive_Object:test_check_missing()
    local drive_obj = {
        Missing = 0,
        EnclosureId = 1,
        SlotNumber = 2
    }
    local pd_list = {
        {
            enclosure_id = 1,
            slot_num = 2
        }
    }
    c_drive.check_missing(drive_obj, pd_list)
    lu.assertEquals(drive_obj.missing_count, 0)
    drive_obj.SlotNumber = 3
    c_drive.check_missing(drive_obj, pd_list)
    lu.assertEquals(drive_obj.Missing, 0)
    drive_obj.missing_count = 5
    c_drive.check_missing(drive_obj, pd_list)
    lu.assertEquals(drive_obj.Missing, 2)
end

function TEST_Drive_Object:test_set_slot_power_state_by_smc()
    local drive_obj = {SlotPowerState = 0}
    c_drive.set_slot_power_state_by_smc(drive_obj, 0)
    lu.assertEquals(drive_obj.SlotPowerState, 0)
    c_drive.set_slot_power_state_by_smc(drive_obj, 1)
end

function TEST_Drive_Object:test_collect_nvme_predictive_failure_data_nil_nvme_obj()
    local drive_obj = {
        Name = 'TestDrive',
        nvme_predictive_failure_data = {}
    }
    local ret = c_drive.collect_nvme_predictive_failure_data(drive_obj, nil)
    lu.assertEquals(ret, false)
end

function TEST_Drive_Object:test_collect_nvme_predictive_failure_data_no_mctp_obj()
    local drive_obj = {
        Name = 'TestDrive',
        nvme_predictive_failure_data = {}
    }
    local nvme_obj = {
        nvme_mi_mctp_obj = nil
    }
    local ret = c_drive.collect_nvme_predictive_failure_data(drive_obj, nvme_obj)
    lu.assertEquals(ret, false)
end

function TEST_Drive_Object:test_collect_nvme_predictive_failure_data_no_nvme_mi_obj()
    local drive_obj = {
        Name = 'TestDrive',
        nvme_predictive_failure_data = {}
    }
    local nvme_obj = {
        nvme_mi_mctp_obj = {
            nvme_mi_obj = nil
        }
    }
    local ret = c_drive.collect_nvme_predictive_failure_data(drive_obj, nvme_obj)
    lu.assertEquals(ret, false)
end

function TEST_Drive_Object:test_collect_nvme_predictive_failure_data_get_hw_smart_failed()
    local nvme_admin_command_process = require 'nvme.nvme_mi_protocol.nvme_admin_command_process'
    local origin_get_hw_smart = nvme_admin_command_process.get_hw_defined_smart_log_raw
    nvme_admin_command_process.get_hw_defined_smart_log_raw = function()
        return nil
    end
    local drive_obj = {
        Name = 'TestDrive',
        nvme_predictive_failure_data = {}
    }
    local nvme_obj = {
        nvme_mi_mctp_obj = {
            nvme_mi_obj = {}
        },
        uuid_index = 1
    }
    local ret = c_drive.collect_nvme_predictive_failure_data(drive_obj, nvme_obj)
    lu.assertEquals(ret, false)
    nvme_admin_command_process.get_hw_defined_smart_log_raw = origin_get_hw_smart
end

function TEST_Drive_Object:test_collect_nvme_predictive_failure_data_get_smart_failed()
    local nvme_admin_command_process = require 'nvme.nvme_mi_protocol.nvme_admin_command_process'
    local origin_get_hw_smart = nvme_admin_command_process.get_hw_defined_smart_log_raw
    local origin_get_smart = nvme_admin_command_process.get_smart_log_raw
    nvme_admin_command_process.get_hw_defined_smart_log_raw = function()
        return 'hw_smart_data'
    end
    nvme_admin_command_process.get_smart_log_raw = function()
        return nil
    end
    local drive_obj = {
        Name = 'TestDrive',
        nvme_predictive_failure_data = {}
    }
    local nvme_obj = {
        nvme_mi_mctp_obj = {
            nvme_mi_obj = {}
        },
        uuid_index = 1
    }
    local ret = c_drive.collect_nvme_predictive_failure_data(drive_obj, nvme_obj)
    lu.assertEquals(ret, false)
    nvme_admin_command_process.get_hw_defined_smart_log_raw = origin_get_hw_smart
    nvme_admin_command_process.get_smart_log_raw = origin_get_smart
end

function TEST_Drive_Object:test_collect_nvme_predictive_failure_data_smart_too_short()
    local nvme_admin_command_process = require 'nvme.nvme_mi_protocol.nvme_admin_command_process'
    local nvme_mi_def = require 'nvme.nvme_mi_protocol.nvme_mi_def'
    local origin_get_hw_smart = nvme_admin_command_process.get_hw_defined_smart_log_raw
    local origin_get_smart = nvme_admin_command_process.get_smart_log_raw
    nvme_admin_command_process.get_hw_defined_smart_log_raw = function()
        return 'hw_smart_data'
    end
    nvme_admin_command_process.get_smart_log_raw = function()
        return string.rep('\x00', nvme_mi_def.SMART_LOG_HOST_READ_END - 1)
    end
    local drive_obj = {
        Name = 'TestDrive',
        nvme_predictive_failure_data = {}
    }
    local nvme_obj = {
        nvme_mi_mctp_obj = {
            nvme_mi_obj = {}
        },
        uuid_index = 1
    }
    local ret = c_drive.collect_nvme_predictive_failure_data(drive_obj, nvme_obj)
    lu.assertEquals(ret, false)
    nvme_admin_command_process.get_hw_defined_smart_log_raw = origin_get_hw_smart
    nvme_admin_command_process.get_smart_log_raw = origin_get_smart
end

function TEST_Drive_Object:test_collect_nvme_predictive_failure_data_success()
    local nvme_admin_command_process = require 'nvme.nvme_mi_protocol.nvme_admin_command_process'
    local nvme_mi_def = require 'nvme.nvme_mi_protocol.nvme_mi_def'
    local origin_get_hw_smart = nvme_admin_command_process.get_hw_defined_smart_log_raw
    local origin_get_smart = nvme_admin_command_process.get_smart_log_raw
    nvme_admin_command_process.get_hw_defined_smart_log_raw = function()
        return 'hw_smart_data'
    end
    local smart_data = string.rep('\x01', nvme_mi_def.SMART_LOG_HOST_READ_END + 10)
    nvme_admin_command_process.get_smart_log_raw = function()
        return smart_data
    end
    local drive_obj = {
        Name = 'TestDrive',
        nvme_predictive_failure_data = {}
    }
    local nvme_obj = {
        nvme_mi_mctp_obj = {
            nvme_mi_obj = {}
        },
        uuid_index = 1
    }
    local ret = c_drive.collect_nvme_predictive_failure_data(drive_obj, nvme_obj)
    lu.assertEquals(ret, true)
    lu.assertEquals(drive_obj.nvme_predictive_failure_data['HwDefinedSmartData'], '68775F736D6172745F64617461')
    lu.assertEquals(#drive_obj.nvme_predictive_failure_data['HostReadCommands'], 32)
    nvme_admin_command_process.get_hw_defined_smart_log_raw = origin_get_hw_smart
    nvme_admin_command_process.get_smart_log_raw = origin_get_smart
end

-- 覆盖 update_static_drive_info：SAS/SATA 盘更新 Model、Revision、Protocol 等
function TEST_Drive_Object:test_update_static_drive_info()
    local obj = {
        is_nvme = false,
        register_firmware_info_flag = false,
        passthrough_firmware_version = common_def.INVALID_STRING,
        RefControllerTypeId = 0
    }
    local orig_vendor = method_misc.test_controller_vendor
    method_misc.test_controller_vendor = function() return false end
    local pd_info = {
        model = 'ST1000',
        manufacturer = 'Vendor',
        firmware_version = '1.0',
        interface_type = 2,
        media_type = 'HDD',
        serial_num = 'SN123',
        form_factor = 1
    }
    c_drive.update_static_drive_info(obj, pd_info)
    lu.assertEquals(obj.Model, 'ST1000')
    lu.assertEquals(obj.Manufacturer, 'Vendor')
    lu.assertEquals(obj.Revision, '1.0')
    lu.assertEquals(obj.Protocol, 2)
    lu.assertEquals(obj.SerialNumber, 'SN123')
    lu.assertEquals(obj.is_protocol_valid, true)
    method_misc.test_controller_vendor = orig_vendor
end

-- 覆盖 update_rebuild_state_and_progress：fw_state 为 EPD/FW_SYSTEM 时清零
function TEST_Drive_Object:test_update_rebuild_state_and_progress_epd()
    local obj = { RebuildState = 1, RebuildProgress = 50 }
    local pd_info = { fw_state = common_def.PD_STATE.EPD, proginfo = {} }
    c_drive.update_rebuild_state_and_progress(obj, pd_info)
    lu.assertEquals(obj.RebuildState, 0)
    lu.assertEquals(obj.RebuildProgress, 0)
end

-- 覆盖 update_rebuild_state_and_progress：正常 proginfo
function TEST_Drive_Object:test_update_rebuild_state_and_progress_progress()
    local obj = { RebuildState = 0, RebuildProgress = 0 }
    local pd_info = {
        fw_state = 1,
        proginfo = { rebuild_state = 2, rebuild_progress = 80 }
    }
    c_drive.update_rebuild_state_and_progress(obj, pd_info)
    lu.assertEquals(obj.RebuildState, 2)
    lu.assertEquals(obj.RebuildProgress, 80)
end

-- 覆盖 check_missing：pd_list 匹配且 Missing~=1 时置 0
function TEST_Drive_Object:test_check_missing_matched()
    local obj = {
        EnclosureId = 0,
        SlotNumber = 1,
        Missing = 2,
        missing_count = 2
    }
    local pd_list = { { enclosure_id = 0, slot_num = 1 } }
    c_drive.check_missing(obj, pd_list)
    lu.assertEquals(obj.Missing, 0)
    lu.assertEquals(obj.missing_count, 0)
end

-- 覆盖 check_missing：不匹配则 missing_count 递增，达阈值后 Missing=2
function TEST_Drive_Object:test_check_missing_not_matched()
    local obj = {
        EnclosureId = 0,
        SlotNumber = 1,
        Missing = 0,
        missing_count = 0
    }
    local pd_list = { { enclosure_id = 1, slot_num = 2 } }
    for _ = 1, 6 do
        c_drive.check_missing(obj, pd_list)
    end
    lu.assertEquals(obj.Missing, 2)
end

-- 覆盖 generate_link_abnormal：Missing 已为 2 时不重复触发
function TEST_Drive_Object:test_generate_link_abnormal_when_missing_2()
    local obj = { Missing = 2 }
    c_drive.generate_link_abnormal(obj, true, 'OOB')
    lu.assertEquals(obj.Missing, 2)
end

-- 覆盖 generate_link_abnormal：断言值变化
function TEST_Drive_Object:test_generate_link_abnormal_assert()
    local obj = { Missing = 0 }
    c_drive.generate_link_abnormal(obj, true, 'OOB')
    lu.assertEquals(obj.Missing, 1)
    c_drive.generate_link_abnormal(obj, false, 'OOB')
    lu.assertEquals(obj.Missing, 0)
end

-- 覆盖 update_raid_drive_info：含 proginfo、spareblock、writeamp 等分支
function TEST_Drive_Object:test_update_raid_drive_info_full()
    local emitted = false
    local obj = setmetatable({
        write_amplification_info = {},
        on_update_volume_list = { emit = function(_, _) emitted = true end },
        update_raid_drive_firmware_status = function() end,
        SLCSpareBlockPercentage = common_def.INVALID_U8,
        TLCSpareBlockPercentage = common_def.INVALID_U8,
        spare_block_last_check_time = 0,
        PredictedMediaLifeLeftPercent = common_def.INVALID_U8
    }, { __index = c_drive })
    local pd_info = {
        temperature = 40,
        coerced_size = 1024,
        device_speed = 12,
        link_speed = 6,
        fw_state = 0,
        power_on_hours = 1000,
        rotation_speed = 0,
        block_size = 512,
        sas_addr1 = 0, sas_addr2 = 0,
        remnant_media_wearout = 99,
        prefail_count = 0,
        media_err_count = 0,
        other_err_count = 0,
        proginfo = { patrol_state = 1, rebuild_state = 0, rebuild_progress = 0 },
        power_state = 1,
        boot_priority = 0,
        hot_spare = 0,
        halflife = 0,
        last_prefail_event_seq_num = 0,
        spareblock = { slc_value = 50, tlc_value = 30 },
        writeamp = { update_support_flag = 1 },
        hw_defined_write_amp = {
            valid_flag = 1,
            nand_write_l = 0, nand_write_h = 0,
            host_write_l = 0, host_write_h = 0
        },
        vendor_write_amp = { valid_flag = 1, nand_write = 0, host_write = 0 }
    }
    obj:update_raid_drive_info(pd_info)
    lu.assertEquals(obj.TemperatureCelsius, 40)
    lu.assertEquals(obj.CapacityMiB, 1024)
    lu.assertEquals(obj.PatrolState, 1)
    lu.assertEquals(obj.SLCSpareBlockPercentage, 50)
    lu.assertEquals(obj.TLCSpareBlockPercentage, 30)
    lu.assertEquals(obj.write_amplification_info.update_support_flag, 1)
    lu.assertEquals(obj.write_amplification_info.hw_defined_valid_flag, 1)
    lu.assertEquals(obj.write_amplification_info.vendor_valid_flag, 1)
    lu.assertTrue(emitted)

    lu.assertEquals(obj.PredictedMediaLifeLeftPercent, 99)
    pd_info.remnant_media_wearout = 255
    obj:update_raid_drive_info(pd_info)
    lu.assertEquals(obj.PredictedMediaLifeLeftPercent, 99)
end

-- 覆盖 update_prefail_state：prefail_count / halflife 分支
function TEST_Drive_Object:test_update_prefail_state()
    local obj = { FailurePredicted = 0 }
    setmetatable(obj, { __index = c_drive })
    c_drive.update_prefail_state(obj, { prefail_count = 1, halflife = 0 })
    lu.assertEquals(obj.PredictiveFailure, 1)
    obj.PredictiveFailure = 0
    c_drive.update_prefail_state(obj, { prefail_count = 0, halflife = 1 })
    lu.assertEquals(obj.PredictiveFailure, 1)
    obj.FailurePredicted = 1
    c_drive.update_prefail_state(obj, { prefail_count = 0, halflife = 0 })
    lu.assertEquals(obj.PredictiveFailure, 1)
end

-- 覆盖 update_write_amp_info：writeamp、hw_defined_write_amp、vendor_write_amp
function TEST_Drive_Object:test_update_write_amp_info()
    local obj = { write_amplification_info = {} }
    setmetatable(obj, { __index = c_drive })
    local pd_info = {
        writeamp = { update_support_flag = 1 },
        hw_defined_write_amp = {
            valid_flag = 1,
            nand_write_l = 1, nand_write_h = 2,
            host_write_l = 3, host_write_h = 4
        },
        vendor_write_amp = { valid_flag = 1, nand_write = 10, host_write = 20 }
    }
    c_drive.update_write_amp_info(obj, pd_info)
    lu.assertEquals(obj.write_amplification_info.update_support_flag, 1)
    lu.assertEquals(obj.write_amplification_info.hw_defined_valid_flag, 1)
    lu.assertEquals(obj.write_amplification_info.hw_defined_nand_write_l, 1)
    lu.assertEquals(obj.write_amplification_info.hw_defined_nand_write_h, 2)
    lu.assertEquals(obj.write_amplification_info.vendor_nand_write, 10)
    lu.assertEquals(obj.write_amplification_info.vendor_host_write, 20)
end

-- 覆盖 record_maintaince_log_for_spare_black：spareblock 双无效提前返回
function TEST_Drive_Object:test_record_maintaince_log_for_spare_black_invalid_spareblock()
    local obj = setmetatable({
        Id = 1,
        SLCSpareBlockPercentage = 50,
        TLCSpareBlockPercentage = 50
    }, { __index = c_drive })
    c_drive.record_maintaince_log_for_spare_black(obj, {
        slc_value = common_def.INVALID_U8,
        tlc_value = common_def.INVALID_U8
    }, false)
    lu.assertNil(obj.spare_block_last_check_time)
end

-- 覆盖 record_maintaince_log_for_spare_black：此次记录前硬盘冗余信息双无效（log 分支）
function TEST_Drive_Object:test_record_maintaince_log_for_spare_black_self_invalid()
    local obj = setmetatable({
        Id = 1,
        SLCSpareBlockPercentage = common_def.INVALID_U8,
        TLCSpareBlockPercentage = common_def.INVALID_U8
    }, { __index = c_drive })
    c_drive.record_maintaince_log_for_spare_black(obj, {
        slc_value = 50,
        tlc_value = 50
    }, false)
    lu.assertNil(obj.spare_block_last_check_time)
end

function TEST_Drive_Object:test_init_update_asset_data_info()
    local obj = {
        Presence = 1,
        Revision = "xxx",
        Model = "test123",
        SerialNumber = "123456",
        Manufacturer = "test",
        InventoryManufacturer = "",
        InventoryModel = "",
        InventoryFirmwareVersion = "",
        InventorySerialNumber = "",
        Protocol = 255,
        set_default_values = function(self) end,
        restore_drive_info = function(self) end,
        update_location_indicator_state = function(self) end,
        on_property_changed = {on = function(self, callback) end},
        on_identified_changed = {on = function(self, callback) end},
        new_task = function(self, config) return {loop = function(callback) end} end,
        update_drive_physical_context = function(self) end,
        monitor_fault_state = function(self) end,
        on_pd_update = {on = function(self, callback) end},
        on_pd_update_smart = {on = function(self, callback) end},
        on_dump_log = {on = function(self, callback) end},
        diagnose_info_update_proc = function(self) end,
        update_asset_data_info = function(self)
            self.InventoryManufacturer = self.Manufacturer
            self.InventoryModel = self.Model
            self.InventorySerialNumber = self.SerialNumber
            self.InventoryFirmwareVersion = self.Revision
        end
    }
    c_drive.init(obj)
    lu.assertEquals(obj.InventoryManufacturer, "test")
    lu.assertEquals(obj.InventoryModel, "test123")
    lu.assertEquals(obj.InventoryFirmwareVersion, "xxx")
    lu.assertEquals(obj.InventorySerialNumber, "123456")
    lu.assertEquals(obj.Protocol, 5)
end

-- 覆盖 pd_log_check_collect_startup（1570-1600）：首次/后续分支
function TEST_Drive_Object:test_pd_log_check_collect_startup_branches()
    local obj = setmetatable({}, { __index = c_drive })

    -- enable=false
    lu.assertFalse(obj:pd_log_check_collect_startup(0, 1, 5, 100, false, 0))

    -- 后续收集：interval_sec>0 且 gap>interval_sec
    lu.assertTrue(obj:pd_log_check_collect_startup(100, 1, 5, 100 + 3601, true, 0))
    -- 后续收集：interval_sec==0 -> false
    lu.assertFalse(obj:pd_log_check_collect_startup(100, 0, 5, 100 + 3601, true, 0))

    -- 首次收集：start_time_in_hour==255 立即触发
    lu.assertTrue(obj:pd_log_check_collect_startup(0, 1, common_def.STORAGE_INFO_INVALID_BYTE, 100, true, 0))

    -- 首次收集：start_time_in_hour>23 归一到 0，且 window_start 负数 clamp
    with_patch_global('os', setmetatable({
        date = function(fmt)
            if fmt == '%H' then return '0' end
            if fmt == '%M' then return '0' end
            if fmt == '%S' then return '0' end
            return '0'
        end
    }, { __index = os }), function()
        lu.assertTrue(obj:pd_log_check_collect_startup(0, 1, 25, 100, true, 0))
    end)

    -- 首次收集：不在窗口内，但距离启动达到间隔
    with_patch_global('os', setmetatable({
        date = function(fmt)
            if fmt == '%H' then return '10' end
            if fmt == '%M' then return '0' end
            if fmt == '%S' then return '0' end
            return '0'
        end
    }, { __index = os }), function()
        lu.assertTrue(obj:pd_log_check_collect_startup(0, 1, 5, 4000, true, 0))
    end)
end

-- 覆盖 update_dump_log（1669-1684）：触发 emit 与 sleep
function TEST_Drive_Object:test_update_dump_log_triggers_emit_and_sleep()
    local emitted = false
    local slept = false

    local orig_get_instance = c_drives_object.get_instance
    c_drives_object.get_instance = function()
        return { obj = { LogAutoCollectEnable = true, LogAutoCollectInterval = 1 } }
    end

    local orig_get_ctrl_init_state = sml.get_ctrl_init_state
    sml.get_ctrl_init_state = function()
        return 2
    end

    with_patch(os, 'time', function() return 123456 end, function()
        with_patch(skynet, 'sleep', function() slept = true end, function()
            local drive = setmetatable({
                RefControllerId = 1,
                dump_info = {
                    startup_time = 0,
                    last_dump_time = 0,
                    dump_interval = 1,
                    first_start_time_in_hour = common_def.STORAGE_INFO_INVALID_BYTE,
                    log_auto_collect_enable = true
                },
                on_dump_log = { emit = function() emitted = true end }
            }, { __index = c_drive })

            drive:update_dump_log()
            lu.assertTrue(emitted)
            lu.assertTrue(slept)
            lu.assertEquals(drive.dump_info.last_dump_time, 123456)
        end)
    end)

    sml.get_ctrl_init_state = orig_get_ctrl_init_state
    c_drives_object.get_instance = orig_get_instance
end