-- 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 sml = require('sml')
local c_controller = require('controller.controller_object')
local lu = require('luaunit')
-- 必须在 rpc_service_controller 之前 require 并缓存模块表:TestCtrlConfigBackup 会在运行时
-- 清空重载 controller.ctrl_config_backup,导致 package.loaded 指向新表;而本文件顶部的
-- rpc_service_controller 捕获的是最初加载的表,只有对这张表打桩才对其生效
local ctrl_config_backup = require('controller.ctrl_config_backup')
local rpc_service_controller = require('rpc_services.rpc_service_controller')

TestStorage = {}

function TestStorage:test_start_update_task()
    local origin_func1 = sml.get_ctrl_info
    local origin_func2 = sml.update_ctrl_init_state

    local ctrl = {
        new_task = function()
            return {
                loop = function(obj, cb)
                    cb({ is_exit = false })
                    return {
                        set_timeout_ms = function() end,
                    }
                end,
            }
        end,
        Id = 1,
        TypeId = 20,
        tasks_pause = false,
        on_update = {
            emit = function() end,
        },
    }
    sml.update_ctrl_init_state = function()
        return 2
    end
    sml.get_ctrl_info = function()
        return true
    end
    pcall(c_controller.start_update_task, ctrl)
    sml.get_ctrl_info = origin_func1
    sml.update_ctrl_init_state = origin_func2
end

function TestStorage:test_stop_update_task()
    local ctrl = {
        Id = 1,
        TypeId = 20,
        stop = function() end,
        set_default_values = function() end,
        set_default_volume_manage_values = function() end,
        set_default_health_status = function() end,
        set_default_battery_info = function() end,
        set_default_phy_err = function() end,
        clear_asset_data_info = function() end,
    }
    local ok = pcall(c_controller.stop_related_tasks, ctrl)
    lu.assertEquals(ok, true)
end

function TestStorage:test_unregister_controller_to_sml()
    local origin_func = sml.unregister_controller
    local ctrl = {
        Id = 1,
        get_mapping_type_id = function()
            return 20
        end,
    }
    sml.unregister_controller = function()
        return 1
    end
    local ok = pcall(c_controller.unregister_controller_to_sml, ctrl)
    lu.assertEquals(ok, false)
    sml.unregister_controller = function()
        return 0
    end
    ok = pcall(c_controller.unregister_controller_to_sml, ctrl)
    lu.assertEquals(ok, true)
    sml.unregister_controller = origin_func
end

local function construct_ctx()
    local ctx = {}
    ctx.ChanType = 1
    ctx.get_initiator = function()
        -- 与 test_rpc_service_controller.make_ctx 保持一致:UT 环境里 log:operation 的
        -- initiator 需为字符串,传表会抛 "string expected, got table"
        return 'test_initiator'
    end

    return ctx
end

function TestStorage:test_controller_set_maintainPDFailHistory()
    -- ctrl_operate 配置类操作成功后同步配置备份,测试环境没有可用的 storageconfig db,
    -- stub 掉 get_instance,避免备份同步失败把设置成功路径误判为失败
    -- 注意:必须打桩文件顶部缓存的模块表(rpc_service_controller 实际使用的),
    -- 不能在此 require(会拿到 TestCtrlConfigBackup 重载后的新表)
    local orig_ccb_get_instance = ctrl_config_backup.get_instance
    ctrl_config_backup.get_instance = function()
        return {
            update_backup_prop = function() end,
        }
    end

    local ctrl = {
        Id = 1,
        OOBSupport = 1,
        is_working = false,
    }

    c_controller.collection.find = function()
        return {
            Id = 1,
            OOBSupport = 1,
            is_working = false,
        }
    end

    --设置成功
    sml.ctrl_operation = function()
        return 0
    end

    local ctx = construct_ctx()
    local ok, err = pcall(
        rpc_service_controller.ctrl_operate,
        rpc_service_controller,
        'SetMaintainPDFailHistoryState',
        ctrl.Id,
        ctx,
        1
    )

    lu.assertTrue(ok, 'ctrl_operate failed: ' .. tostring(err))

    --不支持带外管理(当前实现会直接返回错误,这里只验证会报错)
    c_controller.collection.find = function()
        return {
            Id = 1,
            OOBSupport = 0,
            is_working = false,
        }
    end
    local ret = pcall(
        rpc_service_controller.ctrl_operate,
        rpc_service_controller,
        'SetMaintainPDFailHistoryState',
        ctrl.Id,
        ctx,
        1
    )
    lu.assertEquals(ret, false)
    c_controller.collection.find = function()
        return {
            Id = 1,
            OOBSupport = 1,
            is_working = false,
        }
    end

    --非法输入:直接调用,不关心结果
    pcall(rpc_service_controller.ctrl_operate, rpc_service_controller, 'SetMaintainPDFailHistoryState', ctrl.Id, ctx, 3)

    --重复设置:同样只验证可调用
    pcall(rpc_service_controller.ctrl_operate, rpc_service_controller, 'SetMaintainPDFailHistoryState', ctrl.Id, ctx, 1)

    --raid卡繁忙:当前实现会抛错,这里期望 pcall 返回 false
    c_controller.collection.find = function()
        return {
            Id = 1,
            OOBSupport = 1,
            is_working = true,
        }
    end
    local ret = pcall(
        rpc_service_controller.ctrl_operate,
        rpc_service_controller,
        'SetMaintainPDFailHistoryState',
        ctrl.Id,
        ctx,
        1
    )
    lu.assertEquals(ret, false)
    c_controller.collection.find = function()
        return {
            Id = 1,
            OOBSupport = 1,
            is_working = false,
        }
    end

    --设置回拷返回失败
    sml.ctrl_operation = function()
        return 4248
    end
    local ret = pcall(
        rpc_service_controller.ctrl_operate,
        rpc_service_controller,
        'SetMaintainPDFailHistoryState',
        ctrl.Id,
        ctx,
        1
    )
    lu.assertEquals(ret, false)

    ctrl_config_backup.get_instance = orig_ccb_get_instance
end