-- 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'
local c_drive = require 'drive.drive_object'
local method_misc = require 'method_misc'
local common_def = require 'common_def'

TestDriveFirmwareInfo = {}

function TestDriveFirmwareInfo:setUp()
    -- 每个测试用例自己管理 mock，这里不需要全局设置
end

function TestDriveFirmwareInfo:tearDown()
    -- 每个测试用例自己恢复 mock，这里不需要全局恢复
end

-- 测试用例1: 测试自研RAID卡管理的硬盘注册Revision属性变化回调
function TestDriveFirmwareInfo:test_drive_register_revision_callback()
    -- 创建Drive对象
    local signal_registered = false
    local drive_obj = {
        NodeId = 'HDDPlaneDisk0',
        Name = 'HDDPlaneDisk0',
        RefControllerTypeId = 0,
        register_firmware_info_flag = false,
        signal_slots = {},
        device_id = 0,
        identify_pd = false,
        on_identified_changed = {
            emit = function(self, value)
                -- Mock emit
            end
        },
        on_property_changed = {
            on = function(self, callback)
                signal_registered = true
                return {disconnect = function() end}
            end
        },
        register_firmware_info = function() end
    }
    
    -- 打桩pd对象
    local pd = {
        controller_type = common_def.VENDER_HUAWEI,
        controller_id = 0,
        slot_num = 0,
        enclosure_id = 0,
        device_id = 0,
        key = 'pd_key',
        ref_drive = nil
    }
    
    -- 打桩method_misc.test_controller_vendor
    local original_test_controller_vendor = method_misc.test_controller_vendor
    method_misc.test_controller_vendor = function(self, controller_type_id, vendor)
        return controller_type_id == common_def.VENDER_HUAWEI
    end
    
    -- 调用identified方法
    c_drive.identified(drive_obj, pd)
    
    -- 调用register_firmware_info
    c_drive.register_firmware_info(drive_obj)
    
    -- 验证：Revision属性的on_property_changed信号回调已注册
    lu.assertTrue(signal_registered)
    
    -- 恢复
    method_misc.test_controller_vendor = original_test_controller_vendor
end

-- 测试用例2: 测试非自研RAID卡管理的硬盘不注册回调
function TestDriveFirmwareInfo:test_drive_not_register_callback()
    -- 创建Drive对象
    local drive_obj = {
        NodeId = 'HDDPlaneDisk0',
        Name = 'HDDPlaneDisk0',
        RefControllerTypeId = 100,  -- 非自研RAID卡类型
        register_firmware_info_flag = false,
        signal_slots = {},
        on_property_changed = {
            on = function(self, callback)
                return {}
            end
        }
    }
    
    -- 打桩method_misc.test_controller_vendor返回false
    local original_test_controller_vendor = method_misc.test_controller_vendor
    method_misc.test_controller_vendor = function(self, controller_type_id, vendor)
        return false
    end
    
    -- 调用register_firmware_info
    c_drive.register_firmware_info(drive_obj)
    
    -- 验证：Revision属性的on_property_changed信号回调未注册
    lu.assertNil(drive_obj.signal_slots.revision_changed_slot)
    
    -- 恢复
    method_misc.test_controller_vendor = original_test_controller_vendor
end

-- 测试用例3: 测试Revision属性变化时注册FirmwareInfo
function TestDriveFirmwareInfo:test_revision_changed_register_firmware_info()
    local register_called = false
    local register_params = nil
    
    -- Mock retry_register_firmware_info
    local original_retry_register = method_misc.retry_register_firmware_info
    method_misc.retry_register_firmware_info = function(self, firmware_info_table, updateable, capability, max_package_size_mib, success_callback)
        register_called = true
        register_params = {
            Id = firmware_info_table.Id,
            Name = firmware_info_table.Name,
            Version = firmware_info_table.Version,
            Manufacturer = firmware_info_table.Manufacturer
        }
        if success_callback then
            success_callback()
        end
    end
    
    -- 创建Drive对象
    local drive_obj = {
        NodeId = 'HDDPlaneDisk0',
        Name = 'HDDPlaneDisk0',
        Manufacturer = 'HUAWEI',
        register_firmware_info_flag = false
    }
    
    -- 调用register_firmware_info_by_revision
    c_drive.register_firmware_info_by_revision(drive_obj, 'V1.0.0')
    
    -- 验证
    lu.assertTrue(register_called)
    lu.assertEquals(register_params.Id, 'HDDPlaneDisk0')
    lu.assertEquals(register_params.Name, 'HDDPlaneDisk0')
    lu.assertEquals(register_params.Version, 'V1.0.0')
    lu.assertEquals(register_params.Manufacturer, 'HUAWEI')
    lu.assertTrue(drive_obj.register_firmware_info_flag)
    
    -- 恢复
    method_misc.retry_register_firmware_info = original_retry_register
end

-- 测试用例4: 测试Revision属性变化时更新FirmwareInfo
function TestDriveFirmwareInfo:test_revision_changed_update_firmware_info()
    local get_cached_object_called = false
    local new_revision = 'V2.0.0'
    
    -- Mock firmware info object
    local mock_firmware_info_obj = {
        Version = 'V1.0.0'
    }
    
    -- require 对应的模块
    local mdb = require 'mc.mdb'
    local object_manage = require 'mc.orm.object_manage'
    local skynet_module = require 'skynet'
    
    -- 保存原始方法
    local original_get_cached_object = mdb.get_cached_object
    local original_get_instance = object_manage.get_instance
    local original_fork = skynet_module.fork
    local original_sleep = skynet_module.sleep
    
    -- Mock mdb.get_cached_object
    mdb.get_cached_object = function(bus, path, interface)
        get_cached_object_called = true
        return mock_firmware_info_obj
    end
    
    -- Mock object_manage.get_instance
    object_manage.get_instance = function()
        return {bus = 0}
    end
    
    -- 覆盖 skynet.fork，让它执行回调函数
    skynet_module.fork = function(cb, ...)
        cb(...)  -- 立即同步执行回调
        return true
    end
    
    skynet_module.sleep = function(ticks)
        -- Do nothing
    end
    
    -- 创建Drive对象
    local drive_obj = {
        NodeId = 'HDDPlaneDisk0',
        Name = 'HDDPlaneDisk0',
        register_firmware_info_flag = true
    }
    
    -- 调用update_firmware_info
    c_drive.update_firmware_info(drive_obj, new_revision)
    
    -- 验证
    lu.assertTrue(get_cached_object_called, "mdb.get_cached_object should be called")
    lu.assertEquals(mock_firmware_info_obj.Version, new_revision, "Version should be updated")
    
    -- 恢复原始方法
    mdb.get_cached_object = original_get_cached_object
    object_manage.get_instance = original_get_instance
    skynet_module.fork = original_fork
    skynet_module.sleep = original_sleep
end

-- 测试用例5: 测试硬盘拔出时注销FirmwareInfo
function TestDriveFirmwareInfo:test_drive_unregister_firmware_info()
    local unregister_called = false
    local unregister_id = nil
    local disconnect_called = false
    
    -- Mock retry_unregister_firmware_info
    local original_retry_unregister = method_misc.retry_unregister_firmware_info
    method_misc.retry_unregister_firmware_info = function(self, firmware_id, success_callback)
        unregister_called = true
        unregister_id = firmware_id
        if success_callback then
            success_callback()
        end
    end
    
    -- 创建Drive对象
    local drive_obj = {
        NodeId = 'HDDPlaneDisk0',
        register_firmware_info_flag = true,
        signal_slots = {
            revision_changed_slot = {
                disconnect = function(self)
                    disconnect_called = true
                end
            }
        }
    }
    
    -- 调用unregister_firmware_info
    c_drive.unregister_firmware_info(drive_obj)
    
    -- 验证
    lu.assertTrue(unregister_called)
    lu.assertEquals(unregister_id, 'HDDPlaneDisk0')
    lu.assertTrue(disconnect_called)
    lu.assertNil(drive_obj.signal_slots.revision_changed_slot)
    lu.assertFalse(drive_obj.register_firmware_info_flag)
    
    -- 恢复
    method_misc.retry_unregister_firmware_info = original_retry_unregister
end

-- 测试用例6: 测试method_misc的retry_register_firmware_info重试机制
function TestDriveFirmwareInfo:test_retry_register_firmware_info()
    local call_count = 0
    local success_callback_called = false
    
    -- 保存原始的模块
    local original_client = package.loaded['storage.client']
    local original_context = package.loaded['mc.context']
    
    -- require 对应的模块
    local skynet_module = require 'skynet'
    
    -- 保存原始方法
    local original_fork = skynet_module.fork
    local original_sleep = skynet_module.sleep
    
    -- Mock client
    package.loaded['storage.client'] = {
        PFirmwareInventoryFirmwareInventoryAdd = function(ctx, param, updateable, capability, max_package_size_mib)
            call_count = call_count + 1
            if call_count < 3 then
                return false, 'error'
            else
                return true, nil
            end
        end
    }
    
    -- Mock context
    package.loaded['mc.context'] = {
        new = function()
            return {}
        end
    }
    
    -- 覆盖 skynet.fork，让它执行回调函数
    skynet_module.fork = function(cb, ...)
        cb(...)  -- 立即执行
        return true
    end
    
    skynet_module.sleep = function(ticks)
        -- Do nothing
    end
    
    -- 重新加载 method_misc
    package.loaded['method_misc'] = nil
    local method_misc_reload = require 'method_misc'
    
    -- 准备测试数据
    local firmware_info_data = {
        Id = 'HDDPlaneDisk0',
        Name = 'HDDPlaneDisk0',
        Version = 'V1.0.0',
        Manufacturer = 'HUAWEI'
    }
    
    -- 调用retry_register_firmware_info
    method_misc_reload:retry_register_firmware_info(firmware_info_data, true, 4, 10, function()
        success_callback_called = true
    end)
    
    -- 验证
    lu.assertEquals(call_count, 3)
    lu.assertTrue(success_callback_called)
    
    -- 恢复
    skynet_module.fork = original_fork
    skynet_module.sleep = original_sleep
    package.loaded['storage.client'] = original_client
    package.loaded['mc.context'] = original_context
    package.loaded['method_misc'] = nil
end

-- 测试用例7: 测试method_misc的retry_unregister_firmware_info重试机制
function TestDriveFirmwareInfo:test_retry_unregister_firmware_info()
    local call_count = 0
    local success_callback_called = false
    
    -- 保存原始的模块
    local original_client = package.loaded['storage.client']
    local original_context = package.loaded['mc.context']
    
    -- require 对应的模块
    local skynet_module = require 'skynet'
    
    -- 保存原始方法
    local original_fork = skynet_module.fork
    local original_sleep = skynet_module.sleep
    
    -- Mock client
    package.loaded['storage.client'] = {
        PFirmwareInventoryFirmwareInventoryDelete = function(ctx, firmware_id)
            call_count = call_count + 1
            if call_count < 3 then
                return false, 'error'
            else
                return true, nil
            end
        end
    }
    
    -- Mock context
    package.loaded['mc.context'] = {
        new = function()
            return {}
        end
    }
    
    -- 覆盖 skynet.fork，让它执行回调函数
    skynet_module.fork = function(cb, ...)
        cb(...)  -- 立即执行
        return true
    end
    
    skynet_module.sleep = function(ticks)
        -- Do nothing
    end
    
    -- 重新加载 method_misc
    package.loaded['method_misc'] = nil
    local method_misc_reload = require 'method_misc'
    
    -- 调用retry_unregister_firmware_info
    method_misc_reload:retry_unregister_firmware_info('HDDPlaneDisk0', function()
        success_callback_called = true
    end)
    
    -- 验证
    lu.assertEquals(call_count, 3)
    lu.assertTrue(success_callback_called)
    
    -- 恢复
    skynet_module.fork = original_fork
    skynet_module.sleep = original_sleep
    package.loaded['storage.client'] = original_client
    package.loaded['mc.context'] = original_context
    package.loaded['method_misc'] = nil
end

-- 测试用例8: 测试update_static_drive_info主动注册FirmwareInfo
function TestDriveFirmwareInfo:test_update_static_drive_info_register()
    local register_by_revision_called = false
    local register_revision = nil
    
    -- 保存原始的 method_misc
    local original_test_controller_vendor = method_misc.test_controller_vendor
    
    -- Mock test_controller_vendor
    method_misc.test_controller_vendor = function(self, controller_type_id, vendor)
        return controller_type_id == common_def.VENDER_HUAWEI
    end
    
    -- 创建Drive对象（需要包含所有必要的方法）
    local drive_obj = {
        NodeId = 'HDDPlaneDisk0',
        RefControllerTypeId = common_def.VENDER_HUAWEI,
        register_firmware_info_flag = false,
        is_nvme = false,
        Model = '',
        Manufacturer = '',
        passthrough_firmware_version = common_def.INVALID_STRING,
        Revision = '',
        Protocol = 0,
        -- 添加register_firmware_info_by_revision方法
        register_firmware_info_by_revision = function(self, revision)
            register_by_revision_called = true
            register_revision = revision
        end
    }
    
    -- 准备pd_info
    local pd_info = {
        model = 'TestModel',
        manufacturer = 'HUAWEI',
        firmware_version = 'V1.0.0',
        interface_type = 'SATA'
    }
    
    -- 调用update_static_drive_info
    c_drive.update_static_drive_info(drive_obj, pd_info)
    
    -- 验证
    lu.assertTrue(register_by_revision_called)
    lu.assertEquals(register_revision, 'V1.0.0')
    lu.assertEquals(drive_obj.Model, 'TestModel')
    lu.assertEquals(drive_obj.Manufacturer, 'HUAWEI')
    lu.assertEquals(drive_obj.Revision, 'V1.0.0')
    
    -- 恢复
    method_misc.test_controller_vendor = original_test_controller_vendor
end

return TestDriveFirmwareInfo

