-- Copyright (c) 2025 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.
-- See the Mulan PSL v2 for more details.

local lu = require 'luaunit'
local skynet = require 'skynet'
local sync_task = require 'sync_task'
local controller_collection = require 'controller.controller_collection'
local volume_collection = require 'volume.volume_collection'
local rpc_service_controller = require 'rpc_services.rpc_service_controller'
local storage_bus = require 'storage_bus'

TEST_Rpc_Service_Controller = {}

function TEST_Rpc_Service_Controller:test_ctrl_task_operate_get_operated_id_nil_old_list()
    local controller_id = 1
    local controller_path = 'Controller_1_1'
    local ctx = { get_initiator = function() return {} end }

    local call_count = 0
    local controller = {
        Id = controller_id,
        OOBSupport = 1,
        is_working = false,
        get_ctrl_volume_list = function()
            call_count = call_count + 1
            if call_count == 1 then
                return nil
            end
            return {}
        end,
        on_update_volume_array = { emit = function() end }
    }

    local orig_get_by = controller_collection.get_by_controller_id
    controller_collection.get_by_controller_id = function(_, id)
        if id == controller_id then
            return controller
        end
        return nil
    end

    local orig_check = rpc_service_controller.check_params_before_task
    rpc_service_controller.check_params_before_task = function() end

    local orig_fork = skynet.fork
    skynet.fork = function(cb, ...)
        cb(...)
    end

    local orig_create = sync_task.create_task
    sync_task.create_task = function()
        return 'task_id_nil_old'
    end

    local update_task_prop_calls = {}
    local orig_update = sync_task.update_task_prop
    sync_task.update_task_prop = function(task_id, prop)
        update_task_prop_calls[#update_task_prop_calls + 1] = { task_id = task_id, prop = prop }
    end

    local orig_delete_volume = rpc_service_controller.delete_volume
    rpc_service_controller.delete_volume = function()
    end

    local bus = storage_bus.get_instance() and storage_bus.get_instance().bus or nil
    if not bus then
        rpc_service_controller.bus = {}
    end

    local ok, task_id = pcall(rpc_service_controller.ctrl_task_operate, rpc_service_controller,
        'DeleteVolume', controller_path, controller_id, ctx, 0)

    lu.assertTrue(ok)
    lu.assertEquals(task_id, 'task_id_nil_old')

    local last_prop = update_task_prop_calls[#update_task_prop_calls]
    lu.assertNotNil(last_prop)
    lu.assertEquals(last_prop.prop.MessageArgs and last_prop.prop.MessageArgs[1] or '', '')

    rpc_service_controller.delete_volume = orig_delete_volume
    controller_collection.get_by_controller_id = orig_get_by
    rpc_service_controller.check_params_before_task = orig_check
    skynet.fork = orig_fork
    sync_task.create_task = orig_create
    sync_task.update_task_prop = orig_update
end

function TEST_Rpc_Service_Controller:test_ctrl_task_operate_get_operated_id_nil_new_list()
    local controller_id = 1
    local controller_path = 'Controller_1_1'
    local ctx = { get_initiator = function() return {} end }

    local call_count = 0
    local controller = {
        Id = controller_id,
        OOBSupport = 1,
        is_working = false,
        get_ctrl_volume_list = function()
            call_count = call_count + 1
            if call_count == 1 then
                return {}
            end
            return nil
        end,
        on_update_volume_array = { emit = function() end }
    }

    local orig_get_by2 = controller_collection.get_by_controller_id
    controller_collection.get_by_controller_id = function(_, id)
        if id == controller_id then
            return controller
        end
        return nil
    end

    local orig_check2 = rpc_service_controller.check_params_before_task
    rpc_service_controller.check_params_before_task = function() end

    local orig_fork = skynet.fork
    skynet.fork = function(cb, ...)
        cb(...)
    end

    local orig_create = sync_task.create_task
    sync_task.create_task = function()
        return 'task_id_nil_new'
    end

    local update_task_prop_calls = {}
    local orig_update = sync_task.update_task_prop
    sync_task.update_task_prop = function(task_id, prop)
        update_task_prop_calls[#update_task_prop_calls + 1] = { task_id = task_id, prop = prop }
    end

    local orig_delete_volume2 = rpc_service_controller.delete_volume
    rpc_service_controller.delete_volume = function()
    end

    if not rpc_service_controller.bus then
        rpc_service_controller.bus = {}
    end

    local ok, task_id = pcall(rpc_service_controller.ctrl_task_operate, rpc_service_controller,
        'DeleteVolume', controller_path, controller_id, ctx, 0)

    lu.assertTrue(ok)
    lu.assertEquals(task_id, 'task_id_nil_new')

    rpc_service_controller.delete_volume = orig_delete_volume2

    local last_prop = update_task_prop_calls[#update_task_prop_calls]
    lu.assertNotNil(last_prop)
    lu.assertEquals(last_prop.prop.MessageArgs and last_prop.prop.MessageArgs[1] or '', '')

    controller_collection.get_by_controller_id = orig_get_by2
    rpc_service_controller.check_params_before_task = orig_check2
    skynet.fork = orig_fork
    sync_task.create_task = orig_create
    sync_task.update_task_prop = orig_update
end

function TEST_Rpc_Service_Controller:test_ctrl_task_operate_operated_id_and_url()
    local controller_id = 1
    local controller_path = 'Controller_1_1'
    local ctx = { get_initiator = function() return {} end }

    local old_list = {
        { controller_id = controller_id, volume_id = 1 }
    }
    local new_list = {
        { controller_id = controller_id, volume_id = 1 },
        { controller_id = controller_id, volume_id = 2 }
    }
    local call_count = 0
    local controller = {
        Id = controller_id,
        OOBSupport = 1,
        is_working = false,
        TypeId = 14,
        FirmwareVersion = '',
        get_ctrl_volume_list = function()
            call_count = call_count + 1
            if call_count == 1 then
                return old_list
            end
            return new_list
        end,
        on_update_volume_array = { emit = function() end }
    }

    local orig_get_by3 = controller_collection.get_by_controller_id
    controller_collection.get_by_controller_id = function(_, id)
        if id == controller_id then
            return controller
        end
        return nil
    end

    local orig_check3 = rpc_service_controller.check_params_before_task
    rpc_service_controller.check_params_before_task = function() end

    local orig_vc = volume_collection.get_instance
    volume_collection.get_instance = function()
        return {
            get_ctrl_volume_by_id = function(_, cid, vid)
                if cid == controller_id and vid == 1 then
                    return {}
                end
                return nil
            end
        }
    end

    local orig_fork = skynet.fork
    skynet.fork = function(cb, ...)
        cb(...)
    end

    local orig_create = sync_task.create_task
    sync_task.create_task = function()
        return 'task_id_url'
    end

    local update_task_prop_calls = {}
    local orig_update = sync_task.update_task_prop
    sync_task.update_task_prop = function(task_id, prop)
        update_task_prop_calls[#update_task_prop_calls + 1] = { task_id = task_id, prop = prop }
    end

    local orig_create_vol = rpc_service_controller.create_volume_in_new_array
    rpc_service_controller.create_volume_in_new_array = function()
    end

    if not rpc_service_controller.bus then
        rpc_service_controller.bus = {}
    end

    local ok, task_id = pcall(rpc_service_controller.ctrl_task_operate, rpc_service_controller,
        'CreateVolumeInNewArray', controller_path, controller_id, ctx, '', 0, 0xff, 'vol', 1024, 0, 0xff, 0, 0, 0, 0, 0, 0xff, 0xff)

    rpc_service_controller.create_volume_in_new_array = orig_create_vol

    lu.assertTrue(ok)
    lu.assertEquals(task_id, 'task_id_url')

    local last_prop = update_task_prop_calls[#update_task_prop_calls]
    lu.assertNotNil(last_prop)
    local url = last_prop.prop.MessageArgs and last_prop.prop.MessageArgs[1] or ''
    lu.assertTrue(url ~= nil and string.find(url, 'LogicalDrive2') ~= nil)
    lu.assertTrue(url ~= nil and string.find(url, 'RAIDStorage1') ~= nil)

    controller_collection.get_by_controller_id = orig_get_by3
    rpc_service_controller.check_params_before_task = orig_check3
    volume_collection.get_instance = orig_vc
    skynet.fork = orig_fork
    sync_task.create_task = orig_create
    sync_task.update_task_prop = orig_update
end
