-- Unit tests for controller_firmware.controller_firmware_object
--
-- 覆盖 controller_firmware_mgmt 的构造、对象管理和查询接口，覆盖率要求 100%

local lu = require 'luaunit'

----------------------------------------------------------------------
-- Mock 依赖
----------------------------------------------------------------------

-- mock skynet：fork/sleep 立即执行或空操作，方便测试同步观察结果
local mock_skynet = {
    fork = function(func) func() end,
    sleep = function(_) end
}
package.loaded['skynet'] = mock_skynet

-- mock 日志：只提供空实现，避免输出干扰
local mock_log = {
    notice  = function(...) end,
    warning = function(...) end,
    error   = function(...) end
}
package.loaded['mc.logging'] = mock_log

-- mock controller.controller_object：通过 collection.find_by_position 返回控制器对象
local mock_controller = {
    collection = {
        find_by_position = function(self, position)
            -- 默认返回一个简单的 controller 对象；具体行为在单测中按需重写
            return {
                Id = 'ctrl-default',
                DeviceName = 'RAID-CTRL',
                OOBSupport = 1,
                registered_state = true,
            }
        end
    }
}
package.loaded['controller.controller_object'] = mock_controller

----------------------------------------------------------------------
-- 引入被测模块
----------------------------------------------------------------------
-- 清掉test_controller_upgrade.lua中对controller_firmware_object的打桩
package.loaded['controller_firmware.controller_firmware_object'] = nil
local controller_firmware = require 'controller_firmware.controller_firmware_object'
local mgmt = controller_firmware.get_instance()

----------------------------------------------------------------------
-- 测试用例
----------------------------------------------------------------------

TEST_Controller_Firmware_Obj = {}

function TEST_Controller_Firmware_Obj:setUp()
    -- 每个用例前清空内部状态
    mgmt:ctor()

end

-- 1. ctor 初始化 controller_firmware_objs
function TEST_Controller_Firmware_Obj:test_ctor_initializes_state()
    -- ctor 在 setUp 中已经调用过，这里再次调用确认幂等
    mgmt.controller_firmware_objs = { foo = { firmware_obj = {}, controller_obj = {} } }
    mgmt:ctor()
    lu.assertEquals(type(mgmt.controller_firmware_objs), 'table')
    lu.assertEquals(next(mgmt.controller_firmware_objs), nil)
end

-- 2. on_add_object 正常添加 ControllerFirmware 对象，并关联 controller 对象
function TEST_Controller_Firmware_Obj:test_on_add_object_success()
    -- mock controller.collection.find_by_position：直接返回一个 controller
    local old_collection = mock_controller.collection
    mock_controller.collection = {
        find_by_position = function(self, position)
            return {
                Id = 'ctrl1',
                DeviceName = 'RAID-CTRL-1',
                OOBSupport = 1,
                registered_state = true,
            }
        end
    }

    local firmware_obj = { ComponentID = 1, ComponentIDEx = 2 }
    mgmt:on_add_object('ControllerFirmware', firmware_obj, 'slot1')

    local info = mgmt.controller_firmware_objs['slot1']
    lu.assertNotNil(info)
    lu.assertEquals(info.firmware_obj.ComponentID, 1)
    lu.assertEquals(info.firmware_obj.ComponentIDEx, 2)
    lu.assertEquals(info.controller_obj.Id, 'ctrl1')

    mock_controller.collection = old_collection
end

-- 3. on_add_object 对非 ControllerFirmware 类不做处理
function TEST_Controller_Firmware_Obj:test_on_add_object_ignore_other_class()
    mgmt:on_add_object('OtherClass', {}, 'slotX')
    lu.assertEquals(next(mgmt.controller_firmware_objs), nil)
end

-- 4. on_add_object 在 controller 找不到时不会插入记录
function TEST_Controller_Firmware_Obj:test_on_add_object_controller_not_found()
    local old_collection = mock_controller.collection
    local retry_times = 0
    mock_controller.collection = {
        find_by_position = function(self, position)
            retry_times = retry_times + 1
            return nil
        end
    }

    mgmt:on_add_object('ControllerFirmware', { ComponentID = 1, ComponentIDEx = 2 }, 'slot2')
    -- 等待逻辑内部重试结束（mock_skynet.sleep 为空实现，循环会立刻跑完）
    lu.assertEquals(next(mgmt.controller_firmware_objs), nil)

    mock_controller.collection = old_collection
end

-- 5. on_delete_object 会清除指定 position 的记录
function TEST_Controller_Firmware_Obj:test_on_delete_object_clears_record()
    mgmt.controller_firmware_objs['slot1'] = {
        firmware_obj = { ComponentID = 1, ComponentIDEx = 2 },
        controller_obj = { Id = 'ctrl1' }
    }

    mgmt:on_delete_object('ControllerFirmware', {}, 'slot1')
    lu.assertEquals(mgmt.controller_firmware_objs['slot1'], nil)
end

-- 6. find_upgradable_raid_firmware_obj 仅返回 OOBSupport==1 的对象
function TEST_Controller_Firmware_Obj:test_find_upgradable_raid_firmware_obj_filters_oob()
    mgmt.controller_firmware_objs = {
        slot1 = {
            firmware_obj = { ComponentID = 1, ComponentIDEx = 2 },
            controller_obj = { Id = 'ctrl1', OOBSupport = 1 }
        },
        slot2 = {
            firmware_obj = { ComponentID = 1, ComponentIDEx = 2 },
            controller_obj = { Id = 'ctrl2', OOBSupport = 0 }
        }
    }

    local res = mgmt:find_upgradable_raid_firmware_obj(1, 2)
    lu.assertEquals(#res, 1)
    lu.assertEquals(res[1].ref_controller.Id, 'ctrl1')
    lu.assertEquals(res[1].Position, 'slot1')
end

-- 7. has_valid_upgradable_raid 只在存在 OOBSupport==1 且 registered_state==true 时返回 true
function TEST_Controller_Firmware_Obj:test_has_valid_upgradable_raid_true_and_false()
    -- 情况一：有符合条件的 controller
    mgmt.controller_firmware_objs = {
        slot1 = {
            firmware_obj = {},
            controller_obj = { Id = 'ctrl1', OOBSupport = 1, registered_state = true }
        }
    }
    lu.assertTrue(mgmt:has_valid_upgradable_raid())

    -- 情况二：OOBSupport=1 但未注册
    mgmt.controller_firmware_objs = {
        slot1 = {
            firmware_obj = {},
            controller_obj = { Id = 'ctrl1', OOBSupport = 1, registered_state = false }
        }
    }
    lu.assertFalse(mgmt:has_valid_upgradable_raid())

    -- 情况三：完全没有 controller
    mgmt.controller_firmware_objs = {}
    lu.assertFalse(mgmt:has_valid_upgradable_raid())
end

-- 8. get_cfg_match_controller_version 返回匹配控制器的 FirmwareVersion
function TEST_Controller_Firmware_Obj:test_get_cfg_match_controller_version()
    mgmt.controller_firmware_objs = {
        slot1 = {
            firmware_obj = { ComponentID = 1, ComponentIDEx = 2 },
            controller_obj = { Id = 'ctrl1', FirmwareVersion = '1.0.0' }
        },
        slot2 = {
            firmware_obj = { ComponentID = 2, ComponentIDEx = 3 },
            controller_obj = { Id = 'ctrl2', FirmwareVersion = '2.0.0' }
        }
    }

    local ver = mgmt:get_cfg_match_controller_version(1, 2)
    lu.assertEquals(ver, '1.0.0')

    local ver_none = mgmt:get_cfg_match_controller_version(9, 9)
    lu.assertEquals(ver_none, '')
end

return TEST_Controller_Firmware_Obj

