-- Copyright (c) 2024 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 sml = require('sml')
local c_array_info = require('sml.array_info')
local controller = {
    Id = 0,
    DevFunction = 1,
    SocketId = 1,
    DevDevice = 1,
    TypeId = 99,
    Segment = 1,
    SystemId = 1,
    DevBus = 1,
    Name = 'HI1880_SP686C_M_16i_2G',
    OOBSupport = 1,
    path = 'Controller_1_0001010102',
    CtrlOption1 = 2275649443,
    CtrlOption2 = 32647,
    CtrlOption3 = 0,
    get_children = function()
        return {}
    end,
}

local function make_array_info(test_data)
    return c_array_info.new({
        free_blocks_count = test_data.free_blocks_count,
        free_blocks_space = test_data.free_blocks_space,
        last_update_timestamp = test_data.last_update_timestamp,
        ld_count = test_data.ld_count,
        ld_ids = test_data.ld_ids,
        pd_count = test_data.pd_count,
        pd_enclosures = test_data.pd_enclosures,
        pd_ids = test_data.pd_ids,
        pd_slots = test_data.pd_slots,
        total_free_space = test_data.total_free_space,
        used_space = test_data.used_space,
    })
end

-- 创建key为0:6的array对象
local function add_raid_array(self)
    self.bus_monitor_service.on_os_state_changed:emit(true)
    -- 创建控制器对象
    self.tasks:run_all_task()
    self.object_manager.mc:add_object('Controller', controller, 1)
    self.tasks:run_all_task()

    ---@diagnostic disable-next-line: duplicate-set-field
    sml.get_ctrl_init_state = function(...)
        return 2
    end
    -- 测试增加raid组
    ---@diagnostic disable-next-line: duplicate-set-field
    sml.get_ctrl_array_list = function(...)
        local array_list = { 6 }
        return array_list
    end
    ---@diagnostic disable-next-line: duplicate-set-field
    sml.get_array_info = function(...)
        return make_array_info(self.test_array_info)
    end

    self.tasks:run_all_task()
    local array_obj = self.array_collection:get_ctrl_array_by_id(controller.Id, 6)
    return array_obj
end

-- 测试基本的array对象的加载和卸载
function TestStorage:test_raid_array_basic()
    --  测试添加array对象成功
    local array_obj = add_raid_array(self)
    lu.assertEquals(array_obj.Id, 6)
    lu.assertEquals(array_obj.RefControllerId, 0)

    -- 测试在更新raid组列表时删除raid组
    ---@diagnostic disable-next-line: duplicate-set-field
    sml.get_ctrl_array_list = function(...)
        return {}
    end
    self.tasks:run_all_task()
    array_obj = self.array_collection:get_ctrl_array_by_id(controller.Id, 6)
    lu.assertEquals(array_obj, nil)
    -- 删除受模块管理的对象
    self.object_manager.mc:del_object('Controller', controller, 1)
    self.tasks:run_all_task()
end

-- 测试直接删除控制器对象连带删除raid组
function TestStorage:test_raid_array_del()
    local array_obj = add_raid_array(self)
    lu.assertEquals(array_obj.Id, 6)
    lu.assertEquals(array_obj.RefControllerId, 0)
    self.object_manager.mc:del_object('Controller', controller, 1)
    self.tasks:run_all_task()
    array_obj = self.array_collection:get_ctrl_array_by_id(controller.Id, 6)
    lu.assertEquals(array_obj, nil)
end

-- 测试array对象的更新
function TestStorage:test_raid_array_update()
    local pd_info = {
        device_id = 0,
        controller_id = 0,
        slot_num = 3,
        enclosure_id = 0,
    }

    -- 新建drive对象
    local drive_info = {
        HddBackplaneStartSlot = 0,
        Presence = 1,
        RelativeSlot = 1,
        ObjectName = 'Drive1',
        LocateLed = 1,
        FaultLed = 0,
    }
    self.object_manager.mc:add_object('Drive', drive_info)

    -- 新建array
    local array_obj = add_raid_array(self)

    local drive = self.drive_collection:get_drive('Disk1')
    drive:identified(pd_info)
    self.tasks:run_all_task()

    -- 校验任务执行结果
    lu.assertEquals(array_obj.UsedSpaceMiB, self.test_array_info.used_space)
    lu.assertEquals(array_obj.TotalFreeSpaceMiB, self.test_array_info.total_free_space)
    lu.assertEquals(array_obj.FreeBlocksSpaceMiB, self.test_array_info.free_blocks_space)
    lu.assertEquals(array_obj.RefVolumes, self.test_array_info.ld_ids)
    lu.assertEquals(array_obj.RefPDSlots, self.test_array_info.pd_slots)
    lu.assertEquals(array_obj.RefPDEnclosures, self.test_array_info.pd_enclosures)
    lu.assertEquals(array_obj.RefDrives, { 'Disk1' })

    self.object_manager.mc:del_object('Controller', controller, 1)
    self.tasks:run_all_task()
end

-- 测试查找物理盘的array
function TestStorage:test_raid_array_find_by_drive()
    local pd_info = {
        device_id = 0,
        controller_id = 0,
        slot_num = 3,
        enclosure_id = 0,
    }

    -- 新建drive对象
    local drive_info = {
        HddBackplaneStartSlot = 0,
        Presence = 1,
        RelativeSlot = 1,
        ObjectName = 'Drive1',
        LocateLed = 1,
        FaultLed = 0,
    }
    self.object_manager.mc:add_object('Drive', drive_info)

    -- 新建array
    local array_obj = add_raid_array(self)
    lu.assertNotEquals(array_obj, nil)

    local drive = self.drive_collection:get_drive('Disk1')
    drive:identified(pd_info)
    self.tasks:run_all_task()

    -- 校验任务执行结果
    array_obj = self.array_collection:get_ctrl_array_by_diskname('Disk1')
    lu.assertEquals(array_obj.UsedSpaceMiB, self.test_array_info.used_space)
    lu.assertEquals(array_obj.TotalFreeSpaceMiB, self.test_array_info.total_free_space)
    lu.assertEquals(array_obj.FreeBlocksSpaceMiB, self.test_array_info.free_blocks_space)
    lu.assertEquals(array_obj.RefVolumes, self.test_array_info.ld_ids)
    lu.assertEquals(array_obj.RefPDSlots, self.test_array_info.pd_slots)
    lu.assertEquals(array_obj.RefPDEnclosures, self.test_array_info.pd_enclosures)
    lu.assertEquals(array_obj.RefDrives, { 'Disk1' })
    array_obj = self.array_collection:get_ctrl_array_by_diskname('Disk0')
    lu.assertEquals(array_obj, nil)

    self.object_manager.mc:del_object('Controller', controller, 1)
    self.tasks:run_all_task()
end

-- 测试array对象中RefDrives属性的更新
function TestStorage:test_raid_array_update_drive()
    local pd_info_3 = {
        device_id = 0,
        controller_id = 0,
        slot_num = 3,
        enclosure_id = 0,
    }
    local pd_info_6 = {
        device_id = 0,
        controller_id = 0,
        slot_num = 6,
        enclosure_id = 0,
    }

    -- 新建drive对象
    local drive_info = {
        HddBackplaneStartSlot = 0,
        Presence = 1,
        RelativeSlot = 0,
        ObjectName = 'Drive0',
        LocateLed = 1,
        FaultLed = 0,
    }
    self.object_manager.mc:add_object('Drive', drive_info)
    drive_info = {
        HddBackplaneStartSlot = 0,
        Presence = 1,
        RelativeSlot = 1,
        ObjectName = 'Drive1',
        LocateLed = 1,
        FaultLed = 0,
    }
    self.object_manager.mc:add_object('Drive', drive_info)

    -- 新建array
    local array_obj = add_raid_array(self)

    local drive = self.drive_collection:get_drive('Disk0')
    drive:identified(pd_info_3)
    drive = self.drive_collection:get_drive('Disk1')
    drive:identified(pd_info_6)
    self.tasks:run_all_task()

    lu.assertEquals(array_obj.RefDrives, { 'Disk0', 'Disk1' })

    -- 删除drive对象
    drive:identified(nil)
    drive.EnclosureId = 0xffff
    drive.SlotNumber = 0xff
    drive.RefControllerId = 0xff
    self.tasks:run_all_task()
    lu.assertEquals(array_obj.RefDrives, { 'Disk0' })

    self.object_manager.mc:del_object('Controller', controller, 1)
    self.tasks:run_all_task()
end

-- 测试OS下电对array的影响
function TestStorage:test_raid_array_close_os()
    -- mctp_service prepare 前增加的对象,会在 object_manager 模块缓存,直到 prepare 成功
    local drive_info = {
        HddBackplaneStartSlot = 0,
        Presence = 1,
        RelativeSlot = 1,
        ObjectName = 'Drive1',
        LocateLed = 1,
        FaultLed = 0,
    }
    self.object_manager.mc:add_object('Drive', drive_info)
    -- 新建array
    local array_obj = add_raid_array(self)
    lu.assertEquals(array_obj.Id, 6)
    local controller_obj = self.controller_collection:get_by_controller_id(0)

    local drive = self.drive_collection:get_drive('Disk1')
    local pd_info = {
        device_id = 0,
        controller_id = 0,
        slot_num = 3,
        enclosure_id = 0,
    }
    drive:identified(pd_info)
    self.tasks:run_all_task()
    lu.assertEquals(controller_obj.array_list[6], true)
    array_obj = self.array_collection:get_ctrl_array_by_id(0, 6)
    lu.assertEquals(array_obj.Id, 6)

    -- OS下电
    self.bus_monitor_service.on_os_state_changed:emit(false)
    self.tasks:run_all_task()
    lu.assertEquals(controller_obj.array_list[6], nil)
    array_obj = self.array_collection:get_ctrl_array_by_id(0, 6)
    lu.assertEquals(array_obj, nil)

    -- MCTP准备完成
    self.bus_monitor_service.on_os_state_changed:emit(true)
    self.tasks:run_all_task()
    lu.assertEquals(controller_obj.array_list[6], true)
    array_obj = self.array_collection:get_ctrl_array_by_id(0, 6)
    lu.assertEquals(array_obj.Id, 6)

    -- 删除 controller
    self.object_manager.mc:del_object('Controller', controller, 1)
    self.tasks:run_all_task()
end