-- 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 drive_collection = require('drive.drive_collection')
local volume_param_check = require('volume.volume_param_check')
local c_ctrl_info = require('sml.ctrl_info')
local c_ld_info = require('sml.ld_info')
local c_array_info = require('sml.array_info')
local common_def = require('common_def')
local project_dir = os.getenv('PROJECT_DIR')
local file_sec = require('utils.file')
local utils = require('mc.utils')
local error_engine = require('error_engine')
local task = require('mc.mdb.task_mgmt')

local controller_info = {
    Id = 0,
    DevFunction = 1,
    SocketId = 1,
    DevDevice = 1,
    TypeId = 14,
    Segment = 1,
    SystemId = 1,
    DevBus = 1,
    Name = 'HI1880_SP686C_M_16i_2G',
    OOBSupport = 1,
    CtrlOption1 = 2275649443,
    CtrlOption2 = 32647,
    CtrlOption3 = 0,
    path = 'Controller_1_0001010102',
    get_children = function()
        return {}
    end,
    RefChip = { path = 'aaa' },
}

local function construct_ctx()
    local ctx = {}
    ctx.ChanType = 1
    ctx.get_initiator = function()
        return {}
    end

    return ctx
end

local ctx = construct_ctx()

local function add_controller(self)
    -- mctp_service prepare 前增加的对象,会在 object_manager 模块缓存,直到 prepare 成功
    self.object_manager.mc:add_object('Controller', controller_info, 1)
    self.bus_monitor_service.on_os_state_changed:emit(true)
    -- 运行 mctp_start_task 任务,成功后 object_manager 会发出 prepare_ok 信号
    self.tasks:run_until(function()
        return self.controller_collection:get_by_controller_id(0) ~= nil
    end)

    ---@diagnostic disable-next-line: duplicate-set-field
    sml.get_ctrl_info = function()
        return c_ctrl_info.new(self.test_controller_data)
    end
    self.tasks:run_all_task()
    return self.controller_collection:get_by_controller_id(0)
end

local function add_raid_volume(self)
    local volume_list = { 1, 2 }
    sml.get_ctrl_ld_list = function(...)
        return volume_list
    end
    sml.get_ld_info = function(...)
        return c_ld_info.new(self.test_ld_info)
    end
    local controller = add_controller(self)
    self.tasks:run_until(function()
        local obj1 = self.volume_collection:get_ctrl_volume_by_id(controller.Id, 1)
        local obj2 = self.volume_collection:get_ctrl_volume_by_id(controller.Id, 2)
        return obj1 ~= nil and obj2 ~= nil
    end)

    local obj1 = self.volume_collection:get_ctrl_volume_by_id(controller.Id, 1)
    local obj2 = self.volume_collection:get_ctrl_volume_by_id(controller.Id, 2)
    self.tasks:run_all_task()
    return obj1, obj2
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为1:6的array对象
local function add_raid_array(self)
    -- 创建控制器对象
    self.bus_monitor_service.on_os_state_changed:emit(true)
    self.object_manager.mc:add_object('Controller', controller_info, 1)
    self.tasks:run_until(function()
        return self.controller_collection:get_by_controller_id(controller_info.Id) ~= nil
    end)
    local controller_obj = self.controller_collection:get_by_controller_id(controller_info.Id)
    controller_obj.CreateVolumeSupported = true
    ---@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 = { 2 }
        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_until(function()
        return self.array_collection:get_ctrl_array_by_id(controller_info.Id, 2) ~= nil
    end)
    local array_obj = self.array_collection:get_ctrl_array_by_id(controller_info.Id, 2)
    self.tasks:run_all_task()
    return array_obj
end

function TestStorage:test_volume_basic()
    local obj1, obj2 = add_raid_volume(self)
    lu.assertEquals(obj1.Id, 1)
    lu.assertEquals(obj2.Id, 2)

    sml.get_ctrl_ld_list = function(...)
        return {}
    end
    self.tasks:run_task('update_ld_list')
    self.tasks:run_all_task()
    obj1 = self.volume_collection:get_ctrl_volume_by_id(controller_info.Id, 1)
    lu.assertEquals(obj1, nil)
    obj2 = self.volume_collection:get_ctrl_volume_by_id(controller_info.Id, 2)
    lu.assertEquals(obj2, nil)

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

-- 测试直接删除控制器对象连带删除raid组
function TestStorage:test_raid_volume_del()
    local obj1, obj2 = add_raid_volume(self)
    lu.assertEquals(obj1.Id, 1)
    lu.assertEquals(obj2.Id, 2)
    self.object_manager.mc:del_object('Controller', controller_info, 1)
    self.tasks:run_all_task()
    obj1 = self.volume_collection:get_ctrl_volume_by_id(controller_info.Id, 1)
    lu.assertEquals(obj1, nil)
    obj2 = self.volume_collection:get_ctrl_volume_by_id(controller_info.Id, 2)
    lu.assertEquals(obj2, nil)
end

-- 测试OS下电对volume的影响
function TestStorage:test_volume_close_os()
    local obj1, obj2 = add_raid_volume(self)
    lu.assertEquals(obj1.Id, 1)
    lu.assertEquals(obj2.Id, 2)
    local controller_obj = self.controller_collection:get_by_controller_id(0)

    -- OS下电
    self.bus_monitor_service.on_os_state_changed:emit(false)
    self.tasks:run_all_task()
    lu.assertEquals(controller_obj.volume_list, {})

    -- MCTP准备完成
    self.bus_monitor_service.on_os_state_changed:emit(true)
    self.tasks:run_all_task()
    obj1 = self.volume_collection:get_ctrl_volume_by_id(controller_info.Id, 1)
    lu.assertEquals(obj1.Id, 1)
    obj2 = self.volume_collection:get_ctrl_volume_by_id(controller_info.Id, 2)
    lu.assertEquals(obj2.Id, 2)

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

function TestStorage:test_check_io_policy_1()
    local control_path = 'Controller_1_0001010102'
    add_raid_array(self)
    local rpc_service_controller = self.rpc_service_controller
    drive_collection.get_instance().get_drive_by_id = function(...)
        return true
    end
    volume_param_check.check_ld_data_created_in_new_array = function()
        return common_def.SM_CODE_SUCCESS
    end
    volume_param_check.convert_id_list_from_drive_to_pd = function()
        return 0
    end
    sml.create_ld_on_new_array = function(...)
        return common_def.SML_ERR_PD_CLEAR_IN_PROGRESS
    end
    controller_info.TypeId = 20
    controller_info.FirmwareVersion = '5.140.00-3515'
    local ok, _ = pcall(
        rpc_service_controller.ctrl_task_operate,
        rpc_service_controller,
        'CreateVolumeInNewArray',
        control_path,
        controller_info.Id,
        ctx,
        '0',
        1,
        0xff,
        'ggg',
        1024,
        0,
        0xff,
        0,
        0,
        0,
        0,
        0,
        0xff,
        0xff
    )
    self.tasks:run_all_task()
    lu.assertEquals(ok, false)
    controller_info.TypeId = 99

    -- 测试删除
    ---@diagnostic disable-next-line: duplicate-set-field
    sml.get_ctrl_array_list = function(...)
        return {}
    end
    self.object_manager.mc:del_object('Controller', controller_info, 1)
    self.tasks:run_all_task()
end

function TestStorage:test_check_io_policy_2()
    local control_path = 'Controller_1_0001010102'
    local array_obj = add_raid_array(self)
    local rpc_service_controller = self.rpc_service_controller
    controller_info.TypeId = 30
    controller_info.FirmwareVersion = '5.140.00-3515'
    local ok, _ = pcall(
        rpc_service_controller.ctrl_task_operate,
        rpc_service_controller,
        'CreateVolumeInExistingArray',
        control_path,
        controller_info.Id,
        ctx,
        array_obj.Id,
        0xff,
        0,
        0xff,
        'ggg',
        1024,
        0,
        0xff,
        0,
        0,
        0,
        0,
        0,
        0xff,
        0xff
    )
    self.tasks:run_all_task()
    lu.assertEquals(ok, false)
    controller_info.TypeId = 99

    -- 测试删除
    ---@diagnostic disable-next-line: duplicate-set-field
    sml.get_ctrl_array_list = function(...)
        return {}
    end
    self.object_manager.mc:del_object('Controller', controller_info, 1)
    self.tasks:run_all_task()
end

function TestStorage:test_create_volume_in_existing_array()
    local array_obj = add_raid_array(self)
    local rpc_service_controller = self.rpc_service_controller
    local ok, _ = pcall(
        rpc_service_controller.ctrl_operate,
        rpc_service_controller,
        'CreateVolumeInExistingArray',
        controller_info.Id,
        ctx,
        array_obj.Id,
        0xff,
        0,
        0xff,
        'ggg',
        1024,
        0,
        0xff,
        0,
        0,
        0,
        0,
        0,
        0xff,
        0xff
    )
    self.tasks:run_all_task()
    lu.assertEquals(ok, true)

    local controller_obj = self.controller_collection:get_by_controller_id(controller_info.Id)
    controller_obj.TypeId = 64
    ok, _ = pcall(
        rpc_service_controller.ctrl_operate,
        rpc_service_controller,
        'CreateVolumeInExistingArray',
        controller_info.Id,
        ctx,
        array_obj.Id,
        0xff,
        0,
        0xff,
        'ggg',
        1024,
        0,
        0xff,
        0,
        0,
        0,
        0,
        0,
        0xff,
        0xff
    )
    self.tasks:run_all_task()
    lu.assertEquals(ok, true)

    ok, _ = pcall(
        rpc_service_controller.ctrl_operate,
        rpc_service_controller,
        'CreateVolumeInExistingArray',
        controller_info.Id,
        ctx,
        array_obj.Id,
        0xff,
        50,
        0xff,
        'ggg',
        1024,
        0,
        0xff,
        0,
        0,
        0,
        0,
        0,
        0xff,
        0xff
    )
    self.tasks:run_all_task()
    lu.assertEquals(ok, true)

    -- 测试删除
    ---@diagnostic disable-next-line: duplicate-set-field
    sml.get_ctrl_array_list = function(...)
        return {}
    end
    self.object_manager.mc:del_object('Controller', controller_info, 1)
    self.tasks:run_all_task()
end

function TestStorage:test_create_volume_in_new_array()
    local array_obj = add_raid_array(self)
    local rpc_service_controller = self.rpc_service_controller
    local ok, _ = pcall(
        rpc_service_controller.ctrl_operate,
        rpc_service_controller,
        'CreateVolumeInNewArray',
        controller_info.Id,
        { array_obj.RefDrives },
        1,
        0xff,
        'ggg',
        1024,
        0,
        0xff,
        0,
        0,
        0,
        0,
        0,
        0xff,
        0xff
    )
    self.tasks:run_all_task()
    lu.assertEquals(ok, false)

    -- 测试删除
    ---@diagnostic disable-next-line: duplicate-set-field
    sml.get_ctrl_array_list = function(...)
        return {}
    end
    self.object_manager.mc:del_object('Controller', controller_info, 1)
    self.tasks:run_all_task()
end

function TestStorage:test_set_volume_name()
    local obj1, _ = add_raid_volume(self)
    lu.assertEquals(obj1.Id, 1)
    lu.assertEquals(obj1.VolumeName, 'N/A')
    local controller_obj = self.controller_collection:get_by_controller_id(0)
    local rpc_service_volume = self.rpc_service_volume
    sml.set_ld_name = function()
        return 0
    end
    local ok, _ = pcall(
        rpc_service_volume.volume_operate,
        rpc_service_volume,
        'SetName',
        controller_obj.Id,
        obj1.Id,
        ctx,
        'changed'
    )
    self.tasks:run_all_task()
    lu.assertEquals(ok, true)
    self.object_manager.mc:del_object('Controller', controller_info, 1)
    self.tasks:run_all_task()
end

function TestStorage:test_set_volume_bootable()
    local obj1, _ = add_raid_volume(self)
    lu.assertEquals(obj1.Id, 1)
    lu.assertEquals(obj1.BootPriority, 0)
    local controller_obj = self.controller_collection:get_by_controller_id(0)
    local rpc_service_volume = self.rpc_service_volume
    sml.set_ld_boot_priority = function()
        return 0
    end
    local ok, _ =
        pcall(rpc_service_volume.volume_operate, rpc_service_volume, 'SetBootable', controller_obj.Id, obj1.Id, ctx, 1)
    self.tasks:run_all_task()
    lu.assertEquals(ok, true)
    self.object_manager.mc:del_object('Controller', controller_info, 1)
    self.tasks:run_all_task()
end

function TestStorage:test_set_volume_readpolicy()
    local obj1, _ = add_raid_volume(self)
    lu.assertEquals(obj1.Id, 1)
    lu.assertEquals(obj1.CurrentReadPolicy, 'NoReadAhead')
    local controller_obj = self.controller_collection:get_by_controller_id(0)
    local rpc_service_volume = self.rpc_service_volume
    sml.set_ld_readpolicy = function()
        return 0
    end
    local ok, _ = pcall(
        rpc_service_volume.volume_operate,
        rpc_service_volume,
        'SetReadPolicy',
        controller_obj.Id,
        obj1.Id,
        ctx,
        1
    )
    self.tasks:run_all_task()
    lu.assertEquals(ok, true)
    self.object_manager.mc:del_object('Controller', controller_info, 1)
    self.tasks:run_all_task()
end

function TestStorage:test_set_volume_writepolicy()
    local obj1, _ = add_raid_volume(self)
    lu.assertEquals(obj1.Id, 1)
    lu.assertEquals(obj1.CurrentWritePolicy, 'WriteThrough')
    local controller_obj = self.controller_collection:get_by_controller_id(0)
    local rpc_service_volume = self.rpc_service_volume
    sml.set_ld_writepolicy = function()
        return 0
    end
    local ok, _ = pcall(
        rpc_service_volume.volume_operate,
        rpc_service_volume,
        'SetWritePolicy',
        controller_obj.Id,
        obj1.Id,
        ctx,
        1
    )
    self.tasks:run_all_task()
    lu.assertEquals(ok, true)
    self.object_manager.mc:del_object('Controller', controller_info, 1)
    self.tasks:run_all_task()
end

function TestStorage:test_set_volume_iopolicy()
    local obj1, _ = add_raid_volume(self)
    lu.assertEquals(obj1.Id, 1)
    lu.assertEquals(obj1.CurrentReadPolicy, 'NoReadAhead')
    lu.assertEquals(obj1.CurrentWritePolicy, 'WriteThrough')
    local controller_obj = self.controller_collection:get_by_controller_id(0)
    local rpc_service_volume = self.rpc_service_volume
    sml.set_ld_io_policy = function()
        return 0
    end
    local ok, _ =
        pcall(rpc_service_volume.volume_operate, rpc_service_volume, 'SetIOPolicy', controller_obj.Id, obj1.Id, ctx, 1)
    self.tasks:run_all_task()
    lu.assertEquals(ok, true)
    self.object_manager.mc:del_object('Controller', controller_info, 1)
    self.tasks:run_all_task()
end

function TestStorage:test_set_volume_bgi_enable()
    local obj1, _ = add_raid_volume(self)
    lu.assertEquals(obj1.Id, 1)
    lu.assertEquals(obj1.BGIEnable, 0)
    local controller_obj = self.controller_collection:get_by_controller_id(0)
    local rpc_service_volume = self.rpc_service_volume
    sml.set_ld_bgi_enable = function()
        return 0
    end
    local ok, _ =
        pcall(rpc_service_volume.volume_operate, rpc_service_volume, 'SetBGIEnable', controller_obj.Id, obj1.Id, ctx, 1)
    self.tasks:run_all_task()
    lu.assertEquals(ok, true)
    self.object_manager.mc:del_object('Controller', controller_info, 1)
    self.tasks:run_all_task()
end

function TestStorage:test_set_volume_accesspolicy()
    local obj1, _ = add_raid_volume(self)
    lu.assertEquals(obj1.Id, 1)
    lu.assertEquals(obj1.AccessPolicy, 'ReadWrite')
    local controller_obj = self.controller_collection:get_by_controller_id(0)
    local rpc_service_volume = self.rpc_service_volume
    sml.set_ld_access_policy = function()
        return 0
    end
    controller_obj.TypeId = 14
    local ok, _ = pcall(
        rpc_service_volume.volume_operate,
        rpc_service_volume,
        'SetAccessPolicy',
        controller_obj.Id,
        obj1.Id,
        ctx,
        1
    )
    self.tasks:run_all_task()
    lu.assertEquals(ok, true)
    self.object_manager.mc:del_object('Controller', controller_info, 1)
    self.tasks:run_all_task()
end

function TestStorage:test_set_volume_diskcachepolicy()
    local obj1, _ = add_raid_volume(self)
    lu.assertEquals(obj1.Id, 1)
    lu.assertEquals(obj1.DriveCachePolicy, 0)
    local controller_obj = self.controller_collection:get_by_controller_id(0)
    local rpc_service_volume = self.rpc_service_volume
    sml.set_ld_disk_cache_policy = function()
        return 0
    end
    local ok, _ = pcall(
        rpc_service_volume.volume_operate,
        rpc_service_volume,
        'SetDiskCachePolicy',
        controller_obj.Id,
        obj1.Id,
        ctx,
        1
    )
    self.tasks:run_all_task()
    lu.assertEquals(ok, true)
    self.object_manager.mc:del_object('Controller', controller_info, 1)
    self.tasks:run_all_task()
end

function TestStorage:test_start_volume_fgi()
    local obj1, _ = add_raid_volume(self)
    lu.assertEquals(obj1.Id, 1)
    lu.assertEquals(obj1.CurrentForegroundInitState, 0)
    local controller_obj = self.controller_collection:get_by_controller_id(0)
    local rpc_service_volume = self.rpc_service_volume
    sml.start_ld_fgi = function()
        return 0
    end
    local ok, _ =
        pcall(rpc_service_volume.volume_operate, rpc_service_volume, 'StartFGI', controller_obj.Id, obj1.Id, ctx, 1)
    self.tasks:run_all_task()
    lu.assertEquals(ok, true)
    self.object_manager.mc:del_object('Controller', controller_info, 1)
    self.tasks:run_all_task()
end

function TestStorage:test_start_volume_fullinit()
    local obj1, _ = add_raid_volume(self)
    lu.assertEquals(obj1.Id, 1)
    lu.assertEquals(obj1.CurrentForegroundInitState, 0)
    local controller_obj = self.controller_collection:get_by_controller_id(0)
    local rpc_service_volume = self.rpc_service_volume
    task.create_task = function()
        return 0, nil, 0
    end
    task.get_task_obj = function()
        return nil
    end
    local ok, _ =
        pcall(rpc_service_volume.start_volume_fgi_task, rpc_service_volume, controller_obj, obj1.Id, obj1, ctx, 2)
    lu.assertEquals(ok, true)
    ok, _ = pcall(rpc_service_volume.start_volume_fgi_task, rpc_service_volume, controller_obj, obj1.Id, obj1, ctx, 2)
    lu.assertEquals(ok, true)

    ok, _ = pcall(rpc_service_volume.full_init_volume, rpc_service_volume, 1, controller_obj, obj1.Id, ctx, 2)
    self.tasks:run_all_task()
    lu.assertEquals(ok, true)

    obj1.ForegroundInitProgress = 100
    obj1.CurrentForegroundInitState = 0
    ok, _ = pcall(rpc_service_volume.full_init_volume, rpc_service_volume, 1, controller_obj, obj1.Id, ctx, 2)
    self.tasks:run_all_task()
    lu.assertEquals(ok, true)

    obj1.ForegroundInitProgress = 101
    ok, _ = pcall(rpc_service_volume.full_init_volume, rpc_service_volume, 1, controller_obj, obj1.Id, ctx, 2)
    self.tasks:run_all_task()
    lu.assertEquals(ok, true)

    obj1.ForegroundInitProgress = 0xFF
    ok, _ = pcall(rpc_service_volume.full_init_volume, rpc_service_volume, 1, controller_obj, obj1.Id, ctx, 2)
    self.tasks:run_all_task()
    lu.assertEquals(ok, true)

    self.object_manager.mc:del_object('Controller', controller_info, 1)
    ok, _ = pcall(rpc_service_volume.full_init_volume, rpc_service_volume, 1, controller_obj, obj1.Id, ctx, 2)
    self.tasks:run_all_task()
    lu.assertEquals(ok, false)
end

function TestStorage:test_cancel_volume_fgi()
    local obj1, _ = add_raid_volume(self)
    lu.assertEquals(obj1.Id, 1)
    lu.assertEquals(obj1.CurrentForegroundInitState, 0)
    local controller_obj = self.controller_collection:get_by_controller_id(0)
    local rpc_service_volume = self.rpc_service_volume
    sml.cancel_ld_fgi = function()
        return 0
    end
    local ok, _ =
        pcall(rpc_service_volume.volume_operate, rpc_service_volume, 'CancelFGI', controller_obj.Id, obj1.Id, ctx, 1)
    self.tasks:run_all_task()
    lu.assertEquals(ok, true)
    self.object_manager.mc:del_object('Controller', controller_info, 1)
    self.tasks:run_all_task()
end

function TestStorage:test_set_volume_cache_enable()
    local obj1, _ = add_raid_volume(self)
    lu.assertEquals(obj1.Id, 1)
    lu.assertEquals(obj1.SSDCachecadeVolume, 0)
    local controller_obj = self.controller_collection:get_by_controller_id(0)
    local rpc_service_volume = self.rpc_service_volume
    sml.set_ld_cachecade = function()
        return 0
    end
    local ok, _ = pcall(
        rpc_service_volume.volume_operate,
        rpc_service_volume,
        'SetCachecadeEnable',
        controller_obj.Id,
        obj1.Id,
        ctx,
        1
    )
    self.tasks:run_all_task()
    lu.assertEquals(ok, true)
    self.object_manager.mc:del_object('Controller', controller_info, 1)
    self.tasks:run_all_task()
end

function TestStorage:test_set_volume_capacitysize()
    local obj1, _ = add_raid_volume(self)
    lu.assertEquals(obj1.Id, 1)
    lu.assertEquals(obj1.CapacityBytes, 0)
    local controller_obj = self.controller_collection:get_by_controller_id(0)
    local rpc_service_volume = self.rpc_service_volume
    -- 打桩sml库返回成功
    sml.set_ld_capacity_size = function()
        return 0
    end
    -- 验证设置容量为最大0xFFFFFFFF
    local ok, _ = pcall(
        rpc_service_volume.volume_operate,
        rpc_service_volume,
        'SetCapacitySize',
        controller_obj.Id,
        obj1.Id,
        ctx,
        common_def.STORAGE_INFO_INVALID_DWORD,
        0
    )
    self.tasks:run_all_task()
    lu.assertEquals(ok, true)

    -- 验证设置容量单位为MB
    ok, _ = pcall(
        rpc_service_volume.volume_operate,
        rpc_service_volume,
        'SetCapacitySize',
        controller_obj.Id,
        obj1.Id,
        ctx,
        1,
        0
    )
    self.tasks:run_all_task()
    lu.assertEquals(ok, true)

    -- 验证设置容量单位为GB
    ok, _ = pcall(
        rpc_service_volume.volume_operate,
        rpc_service_volume,
        'SetCapacitySize',
        controller_obj.Id,
        obj1.Id,
        ctx,
        1,
        1
    )
    self.tasks:run_all_task()
    lu.assertEquals(ok, true)

    -- 验证设置容量单位为TB
    ok, _ = pcall(
        rpc_service_volume.volume_operate,
        rpc_service_volume,
        'SetCapacitySize',
        controller_obj.Id,
        obj1.Id,
        ctx,
        1,
        2
    )
    self.tasks:run_all_task()
    lu.assertEquals(ok, true)

    -- 验证设置容量入参校验失败
    ok, _ = pcall(
        rpc_service_volume.volume_operate,
        rpc_service_volume,
        'SetCapacitySize',
        controller_obj.Id,
        obj1.Id,
        ctx,
        1,
        3
    )
    self.tasks:run_all_task()
    lu.assertEquals(ok, false)

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

function TestStorage:test_set_volume_stripsize()
    local obj1, _ = add_raid_volume(self)
    lu.assertEquals(obj1.Id, 1)
    lu.assertEquals(obj1.OptimumIOSizeBytes, 512)
    local controller_obj = self.controller_collection:get_by_controller_id(0)
    local rpc_service_volume = self.rpc_service_volume
    sml.set_ld_strip_size = function()
        return 0
    end
    local ok, _ =
        pcall(rpc_service_volume.volume_operate, rpc_service_volume, 'SetStripSize', controller_obj.Id, obj1.Id, ctx, 1)
    self.tasks:run_all_task()
    lu.assertEquals(ok, true)
    -- 验证条带大小不在控制器支持的范围内
    ok, _ =
        pcall(rpc_service_volume.volume_operate, rpc_service_volume, 'SetStripSize', controller_obj.Id, obj1.Id, ctx, 3)
    self.tasks:run_all_task()
    lu.assertEquals(ok, false)
    volume_param_check.check_ld_strip_size = function()
        return common_def.SM_CODE_SUCCESS
    end
    -- 验证设置条带大小为1MB
    ok, _ = pcall(
        rpc_service_volume.volume_operate,
        rpc_service_volume,
        'SetStripSize',
        controller_obj.Id,
        obj1.Id,
        ctx,
        11
    )
    self.tasks:run_all_task()
    lu.assertEquals(ok, true)
    self.object_manager.mc:del_object('Controller', controller_info, 1)
    self.tasks:run_all_task()
end

function TestStorage:test_volume_abnormal()
    local volume_list = { 1, 2 }
    sml.get_ctrl_ld_list = function(...)
        return volume_list
    end
    add_raid_volume(self)

    -- 默认逻辑盘状态为0(offline),所以预期产生告警
    sml.get_ld_info = function(...)
        return c_ld_info.new(self.test_ld_info)
    end
    self.tasks:run_all_task()
    lu.assertEquals(self.c_storageconfig.obj.VolumesStateAbnormal, 1)

    -- 将逻辑盘1的状态改为3(optimal),逻辑盘2的状仍为0(offline),仍然预期产生告警
    sml.get_ld_info = function(_, Id)
        if Id == 1 then
            self.test_ld_info.drive_state = 3
        else
            self.test_ld_info.drive_state = 0
        end
        return c_ld_info.new(self.test_ld_info)
    end
    self.tasks:run_all_task()
    lu.assertEquals(self.c_storageconfig.obj.VolumesStateAbnormal, 1)

    -- 将所有逻辑盘的状态改为3(optimal),预期不产生告警
    sml.get_ld_info = function(_, Id)
        self.test_ld_info.drive_state = 3
        return c_ld_info.new(self.test_ld_info)
    end
    self.tasks:run_all_task()
    lu.assertEquals(self.c_storageconfig.obj.VolumesStateAbnormal, 0)

    -- 逻辑盘不存在,预期不产生告警
    self.object_manager.mc:del_object('Controller', controller_info, 1)
    self.tasks:run_all_task()
    lu.assertEquals(self.c_storageconfig.obj.VolumesStateAbnormal, 0)
end

local function construct_test_in_failed_array_topo(self)
    sml.get_ctrl_ld_list = function(...)
        return { 0 }
    end
    sml.get_ld_info = function(...)
        -- 初始逻辑盘的状态为Optimal
        self.test_ld_info.drive_state = 3
        return c_ld_info.new(self.test_ld_info)
    end
    sml.get_ctrl_array_list = function(...)
        return { 0 }
    end
    sml.get_array_info = function(...)
        return make_array_info(self.test_array_info)
    end
    local drive_0 = { HddBackplaneStartSlot = 0, Presence = 1, RelativeSlot = 0, ObjectName = 'Drive0' }
    local drive_1 = { HddBackplaneStartSlot = 0, Presence = 1, RelativeSlot = 1, ObjectName = 'Drive1' }
    self.object_manager.mc:add_object('Drive', drive_0)
    self.object_manager.mc:add_object('Drive', drive_1)
    -- mctp_service prepare 前增加的对象,会在 object_manager 模块缓存,直到 prepare 成功
    self.object_manager.mc:add_object('Controller', controller_info, 1)
    self.bus_monitor_service.on_os_state_changed:emit(true)
    self.tasks:run_until(function()
        local volume = self.volume_collection:get_ctrl_volume_by_id(0, 0)
        local array = self.array_collection:get_ctrl_array_by_id(0, 0)
        return volume and array
    end)
    -- 建立映射关系
    local drive_0_obj = self.drive_collection:get_drive(drive_0.Name)
    drive_0_obj:identified({ controller_id = 0, slot_num = 3, enclosure_id = 0, device_id = 1 })
    local drive_1_obj = self.drive_collection:get_drive(drive_1.Name)
    drive_1_obj:identified({ controller_id = 0, slot_num = 6, enclosure_id = 0, device_id = 2 })
    self.tasks:run_until(function()
        local volume = self.volume_collection:get_ctrl_volume_by_id(0, 0)
        return #volume.RefDriveList == 2 and #volume.optimal_drive_list == 2
    end)
    return drive_0_obj, drive_1_obj
end

local function del_drive_object(self)
    local drive_0 = { HddBackplaneStartSlot = 0, Presence = 1, RelativeSlot = 0, ObjectName = 'Drive0' }
    local drive_1 = { HddBackplaneStartSlot = 0, Presence = 1, RelativeSlot = 1, ObjectName = 'Drive1' }
    self.object_manager.mc:del_object('Drive', drive_0)
    self.object_manager.mc:del_object('Drive', drive_1)
end

function TestStorage:test_volume_drive_in_failed_array()
    -- 0、构造测试用的topo
    -- controller_0
    --      |______volume_0
    --                 |_____array_0
    --                           |______drive_0
    --                           |______drive_1
    local _, drive_1_obj = construct_test_in_failed_array_topo(self)
    -- 1、构造硬盘1不在位
    drive_1_obj.Presence = 0
    drive_1_obj.EnclosureId = 0xffff
    drive_1_obj.SlotNumber = 0xff
    drive_1_obj.RefControllerId = 0xff
    drive_1_obj:identified(nil)
    self.tasks:run_until(function()
        local array = self.array_collection:get_ctrl_array_by_id(0, 0)
        return array and #array.RefDrives == 1
    end)
    self.tasks:run_until(function()
        local volume = self.volume_collection:get_ctrl_volume_by_id(0, 0)
        return volume and #volume.RefDriveList == 1
    end)

    -- 2、构造逻辑盘0状态异常
    sml.get_ld_info = function(...)
        self.test_ld_info.drive_state = 2
        return c_ld_info.new(self.test_ld_info)
    end
    self.tasks:run_until(function()
        local volume = self.volume_collection:get_ctrl_volume_by_id(0, 0)
        return volume and volume.State == 2
    end)

    -- 3、硬盘1告警
    lu.assertEquals(drive_1_obj.InAFailedArray, 1)

    -- 4、构造逻辑盘0删除
    sml.get_ctrl_ld_list = function(...)
        return {}
    end
    self.tasks:run_until(function()
        local volume = self.volume_collection:get_ctrl_volume_by_id(0, 0)
        return volume == nil
    end)

    -- 4、硬盘1解除告警
    lu.assertEquals(drive_1_obj.InAFailedArray, 0)

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

function TestStorage:test_volume_basic_info()
    local obj1, obj2 = add_raid_volume(self)
    lu.assertEquals(obj1.Id, 1)
    lu.assertEquals(obj2.Id, 2)
    local volume_info = c_ld_info.new(self.test_ld_info)

    obj1:update_volume_basic_info(volume_info)
    lu.assertEquals(obj1.RebuildState, self.test_ld_info.progress_info.rebuild_state)
    lu.assertEquals(obj1.RebuildProgress, self.test_ld_info.progress_info.rebuild_progress)
    lu.assertEquals(obj1.AccelerationMethod, common_def.LD_ACCELERATION_METHOD_LIST[self.test_ld_info.accelerator])
    lu.assertEquals(obj1.CacheLineSizeKiB, self.test_ld_info.cache_line_size)
    self.object_manager.mc:del_object('Controller', controller_info, 1)
    self.tasks:run_all_task()
end

local function dump_volume_info_to_stub_file(volume_obj, obj_info_path)
    -- 调用逻辑盘收集日志到桩文件中
    local fp_w = file_sec.open_s(obj_info_path, 'w+')
    lu.assertNotIsNil(fp_w)
    volume_obj:dump_info(fp_w)
    fp_w:close()

    local file = file_sec.open_s(obj_info_path, 'r')
    lu.assertNotIsNil(file)
    local content = utils.close(file, pcall(file.read, file, '*a'))
    lu.assertNotIsNil(content)
    return content
end

-- 测试逻辑盘dump日志
function TestStorage:test_volume_basic_info()
    local obj1, obj2 = add_raid_volume(self)
    lu.assertEquals(obj1.Id, 1)
    lu.assertEquals(obj2.Id, 2)

    local obj_info_path = project_dir .. '/test/unit/logical_drive_info.txt'
    local content = dump_volume_info_to_stub_file(obj1, obj_info_path)
    -- 检查逻辑盘收集的信息
    lu.assertNotEquals(string.find(content, 'Acceleration Method                      : Unknown'), nil)
    lu.assertNotEquals(string.find(content, 'Cache Line Size                          : Unknown'), nil)
    lu.assertNotEquals(string.find(content, 'Rebuild in Progress                      : Yes'), nil)

    obj2.AccelerationMethod = 'None'
    obj2.CacheLineSizeKiB = 1
    obj2.RebuildState = 0
    content = dump_volume_info_to_stub_file(obj2, obj_info_path)
    lu.assertNotEquals(string.find(content, 'Acceleration Method                      : None'), nil)
    lu.assertNotEquals(string.find(content, 'Cache Line Size                          : 64 KB'), nil)
    lu.assertNotEquals(string.find(content, 'Rebuild in Progress                      : No'), nil)

    obj2.RebuildState = 255
    content = dump_volume_info_to_stub_file(obj2, obj_info_path)
    lu.assertNotEquals(string.find(content, 'Rebuild in Progress                      : N/A'), nil)

    obj2.RebuildState = 2
    content = dump_volume_info_to_stub_file(obj2, obj_info_path)
    lu.assertNotEquals(string.find(content, 'Rebuild in Progress                      : Unknown'), nil)

    -- 删除文件
    utils.remove_file(obj_info_path)
    self.object_manager.mc:del_object('Controller', controller_info, 1)
    self.tasks:run_all_task()
end

function TestStorage:test_rpc_error_code()
    local error_messageid = error_engine.get_controller_error_message(0x1451)
    lu.assertEquals(error_messageid, 'DifferentDriveSectorsSize')
    error_messageid = error_engine.get_controller_error_message(0x1325)
    lu.assertEquals(error_messageid, 'DriveStatusNotSupported')
end

function TestStorage:test_create_volume_in_existing_array_failed()
    local array_obj = add_raid_array(self)
    local rpc_service_controller = self.rpc_service_controller
    sml.add_ld_on_exist_array = function(...)
        return common_def.SML_ERR_PD_CLEAR_IN_PROGRESS
    end
    local ok, _ = pcall(
        rpc_service_controller.ctrl_operate,
        rpc_service_controller,
        'CreateVolumeInExistingArray',
        controller_info.Id,
        ctx,
        array_obj.Id,
        0xff,
        0,
        0xff,
        'ggg',
        1024,
        0,
        0xff,
        0,
        0,
        0,
        0,
        0,
        0xff,
        0xff
    )
    self.tasks:run_all_task()
    lu.assertEquals(ok, false)

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

function TestStorage:test_create_volume_in_new_array_failed()
    add_raid_array(self)
    local rpc_service_controller = self.rpc_service_controller
    drive_collection.get_instance().get_drive_by_id = function(...)
        return true
    end
    volume_param_check.check_ld_data_created_in_new_array = function()
        return common_def.SM_CODE_SUCCESS
    end
    volume_param_check.convert_id_list_from_drive_to_pd = function()
        return 0
    end
    sml.create_ld_on_new_array = function(...)
        return common_def.SML_ERR_PD_CLEAR_IN_PROGRESS
    end
    local ok, _ = pcall(
        rpc_service_controller.ctrl_operate,
        rpc_service_controller,
        'CreateVolumeInNewArray',
        controller_info.Id,
        ctx,
        '0',
        1,
        0xff,
        'ggg',
        1024,
        0,
        0xff,
        0,
        0,
        0,
        0,
        0,
        0xff,
        0xff
    )
    self.tasks:run_all_task()
    lu.assertEquals(ok, false)
    self.object_manager.mc:del_object('Controller', controller_info, 1)
    self.tasks:run_all_task()
end

function TestStorage:test_volume_drive_in_rebuild()
    -- 0、构造测试用的topo
    -- controller_0
    --      |______volume_0
    --                 |_____array_0
    --                           |______drive_0
    --                           |______drive_1
    local _, drive_1_obj = construct_test_in_failed_array_topo(self)

    self.tasks:run_until(function()
        local drive = self.drive_collection:get_drive_by_id(0, 0)
        return #drive.RefVolumeList == 1
    end)

    -- 1、构造硬盘1不在位
    drive_1_obj.Presence = 0
    drive_1_obj.EnclosureId = 0xffff
    drive_1_obj.SlotNumber = 0xff
    drive_1_obj.RefControllerId = 0xff
    drive_1_obj.InAFailedArray = 0
    drive_1_obj:identified(nil)

    self.tasks:run_until(function()
        local array = self.array_collection:get_ctrl_array_by_id(0, 0)
        return array and #array.RefDrives == 1
    end)
    self.tasks:run_until(function()
        local volume = self.volume_collection:get_ctrl_volume_by_id(0, 0)
        return volume and #volume.RefDriveList == 1
    end)

    -- 2、构造逻辑盘0状态异常
    sml.get_ld_info = function(...)
        self.test_ld_info.drive_state = 2
        return c_ld_info.new(self.test_ld_info)
    end
    self.tasks:run_until(function()
        local volume = self.volume_collection:get_ctrl_volume_by_id(0, 0)
        return volume and volume.State == 2
    end)

    -- 3、硬盘1告警
    lu.assertEquals(drive_1_obj.InAFailedArray, 1)

    -- 4、构造逻辑盘0重构完成
    sml.get_ld_info = function(...)
        self.test_ld_info.drive_state = 3
        return c_ld_info.new(self.test_ld_info)
    end
    self.tasks:run_until(function()
        local volume = self.volume_collection:get_ctrl_volume_by_id(0, 0)
        return volume.State == 3
    end)

    -- 4、硬盘1解除告警
    lu.assertEquals(drive_1_obj.InAFailedArray, 0)

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