-- 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 def = require 'biz_topo.def'
local comm = require 'common'
local c_biz_topo_service = require 'biz_topo.biz_topo_service'
local ipmi = require 'ipmi'
local cc = ipmi.types.Cc
local c_device_service = require 'device.device_service'
local mdb = require 'mc.mdb'
local cmn = require 'common'

TestBizTopoService = {}

local pcie_card_list = {
    [1] = "test_pcie",
    [2] = "test_pcie"
}
local ocp_card_list = {
    [3] = "test_ocp",
    [4] = "test_ocp"
}

local test_topo_service = {
    device_loader = {
        persistent_load_info = {
            [def.device_type.PCIE_CARD] = pcie_card_list,
            [def.device_type.OCP_CARD] = ocp_card_list
        }
    }
}

-- 测试套间执行前调用
function TestBizTopoService:setupClass()
end

-- 测试套件执行后调用
function TestBizTopoService:teardownClass()
end

function TestBizTopoService:test_parse_pcie_card_bdf_data()

end

function TestBizTopoService:test_get_device_present_status()
    -- 1. 测试非法场景 非法的devtype
    local req = {
        DeviceType = 0x3,
    }
    local present = c_biz_topo_service.get_device_present_status(test_topo_service, req)
    lu.assertIsNil(present)

    -- 2. 测试正常场景 获取PCIeCard 在位状态
    req.DeviceType = comm.ipmi_type.IPMI_PCIE_CARD_TYPE
    present = c_biz_topo_service.get_device_present_status(test_topo_service, req)
    lu.assertEquals(present, 3)

    -- 3. 测试正常场景 获取OCPCard 在位状态
    req.DeviceType = comm.ipmi_type.IPMI_OCP_CARD_TYPE
    present = c_biz_topo_service.get_device_present_status(test_topo_service, req)
    lu.assertEquals(present, 12)
end

function TestBizTopoService:test_update_integrated_pcie_config()
    --测试tail长度与DataLen不一致的异常场景
    local req = {
        DataLen = 1,
        Tail = '123'
    }
    local context = {
        ChanType = 1
    }
    local ok, _ = pcall(function()
        c_biz_topo_service.update_integrated_pcie_config(test_topo_service, req, context)
    end)
    lu.assertEquals(ok, false)
end

function TestBizTopoService:test_update_bdf_cfgs()
    local config = {
        socket = 1,
        bus = 5,
        controller_index  = 2,
        controller_type  = 7,
    }
    local biz_topo_data = {
        bdfconfigs = {
            [1] = {
                mds_obj = {
                    BDFConfigs = {
                        {1,2,3,4,5,6,7}
                    }
                },
                config_new = function()
                    return { PortId = 1, ControllerIndex = 2, Segment = 3,
                        Bus = 4, Device = 5, Function = 6, Type = 7 }
                end
            }
        },
        init_bdf_map = function()
        end
    }
    c_biz_topo_service.update_bdf_cfgs(biz_topo_data, config)
    lu.assertEquals(biz_topo_data.bdfconfigs[1].mds_obj.BDFConfigs, {{1, 2, 3, 5, 5, 6, 7}})
    local config_2 = {
        socket = 1,
        bus = 5,
        controller_index  = 3,
        controller_type  = 7,
    }
    c_biz_topo_service.update_bdf_cfgs(biz_topo_data, config_2)
    lu.assertEquals(biz_topo_data.bdfconfigs[1].mds_obj.BDFConfigs, {{1, 2, 3, 5, 5, 6, 7}})
end

function TestBizTopoService:test_get_exu_smc()
    local mdb_bak = mdb

    mdb.get_object = function()
        return 1
    end
    local smc = c_biz_topo_service.get_exu_smc(c_biz_topo_service)
    lu.assertEquals(smc, 1)

    mdb.get_object = function()
        error('break')
    end
    local smc = c_biz_topo_service.get_exu_smc(c_biz_topo_service)
    lu.assertEquals(smc, nil)

    mdb = mdb_bak
end

function TestBizTopoService:test_unload_ocp()
    local c_get_instance = c_device_service.get_instance
    c_device_service.get_instance = function()
        return {
            pcie_device_list = {
                {
                    get_prop = function(prop)
                        if prop == 'DeviceType' then
                            return def.com_type.OCP_CARD
                        elseif prop == 'SlotID' then
                            return 1
                        elseif prop == 'Segment' then
                            return 0
                        elseif prop == 'SocketID' then
                            return 0
                        elseif prop == 'DevBus' then
                            return 2
                        elseif prop == 'DevDevice' then
                            return 3
                        elseif prop == 'DevFunction' then
                            return 4
                        end
                    end
                },
                {
                    get_prop = function(prop)
                        if prop == 'DeviceType' then
                            return def.com_type.OCP_CARD
                        elseif prop == 'SlotID' then
                            return 2
                        elseif prop == 'Segment' then
                            return 0
                        elseif prop == 'SocketID' then
                            return 0
                        elseif prop == 'DevBus' then
                            return 2
                        elseif prop == 'DevDevice' then
                            return 3
                        elseif prop == 'DevFunction' then
                            return 4
                        end
                    end
                },
                {
                    get_prop = function(prop)
                        if prop == 'DeviceType' then
                            return def.com_type.PCIE_CARD
                        elseif prop == 'SlotID' then
                            return 2
                        elseif prop == 'Segment' then
                            return 0
                        elseif prop == 'SocketID' then
                            return 0
                        elseif prop == 'DevBus' then
                            return 2
                        elseif prop == 'DevDevice' then
                            return 3
                        elseif prop == 'DevFunction' then
                            return 4
                        end
                    end
                }
            }
        }
    end

    local ret = c_biz_topo_service.unload_ocp(c_biz_topo_service, 1, 1)
    lu.assertEquals(ret, nil)

    ret = c_biz_topo_service.unload_ocp(c_biz_topo_service, 0, 0)
    lu.assertEquals(ret, nil)

    c_device_service.get_instance = c_get_instance
end

function TestBizTopoService:test_monitor_ocp_presence()
    local c_biz_topo_service_bak = c_biz_topo_service
    local get_exu_smc_bak = c_biz_topo_service.get_exu_smc
    local c_get_instance = c_device_service.get_instance
    local sleep_bak = cmn.skynet.sleep
    cmn.skynet.fork = function(cb)
        cb()
    end
    cmn.skynet.sleep = function()
        error('break')
    end

    c_biz_topo_service.get_exu_smc = function()
    end
    c_device_service.get_instance = function()
        return {
            ocp_card_list = {
                {
                    get_prop = function(prop)
                        if prop == 'DeviceType' then
                            return def.com_type.OCP_CARD
                        elseif prop == 'SlotID' then
                            return 1
                        elseif prop == 'Segment' then
                            return 0
                        elseif prop == 'SocketID' then
                            return 0
                        elseif prop == 'DevBus' then
                            return 2
                        elseif prop == 'DevDevice' then
                            return 3
                        elseif prop == 'DevFunction' then
                            return 4
                        end
                    end
                },
                {
                    get_prop = function(prop)
                        if prop == 'DeviceType' then
                            return def.com_type.OCP_CARD
                        elseif prop == 'SlotID' then
                            return 2
                        elseif prop == 'Segment' then
                            return 0
                        elseif prop == 'SocketID' then
                            return 0
                        elseif prop == 'DevBus' then
                            return 2
                        elseif prop == 'DevDevice' then
                            return 3
                        elseif prop == 'DevFunction' then
                            return 4
                        end
                    end
                }
            },
            pcie_device_list = {
                {
                    get_prop = function(prop)
                        if prop == 'DeviceType' then
                            return def.com_type.OCP_CARD
                        elseif prop == 'SlotID' then
                            return 1
                        elseif prop == 'Segment' then
                            return 0
                        elseif prop == 'SocketID' then
                            return 0
                        elseif prop == 'DevBus' then
                            return 2
                        elseif prop == 'DevDevice' then
                            return 3
                        elseif prop == 'DevFunction' then
                            return 4
                        end
                    end
                },
                {
                    get_prop = function(prop)
                        if prop == 'DeviceType' then
                            return def.com_type.OCP_CARD
                        elseif prop == 'SlotID' then
                            return 2
                        elseif prop == 'Segment' then
                            return 0
                        elseif prop == 'SocketID' then
                            return 0
                        elseif prop == 'DevBus' then
                            return 2
                        elseif prop == 'DevDevice' then
                            return 3
                        elseif prop == 'DevFunction' then
                            return 4
                        end
                    end
                }
            }
        }
    end
    local ok, _ = pcall(function()
        c_biz_topo_service.monitor_ocp_presence(c_biz_topo_service)
        c_biz_topo_service.monitor_ocp_presence(c_biz_topo_service)
    end)
    lu.assertEquals(ok, true)

    c_biz_topo_service.monitor_ocp_task = false
    c_biz_topo_service.get_exu_smc = function()
        return {
            Read = function()
                return "\x01\x01"
            end
        }
    end
    ok, _ = pcall(function()
        c_biz_topo_service.monitor_ocp_presence(c_biz_topo_service)
    end)
    lu.assertEquals(ok, false)

    c_biz_topo_service.monitor_ocp_task = false
    c_biz_topo_service.get_exu_smc = function()
        return {
            Read = function()
                return "\x00\x00"
            end
        }
    end
    ok, _ = pcall(function()
        c_biz_topo_service.monitor_ocp_presence(c_biz_topo_service)
    end)
    lu.assertEquals(ok, false)

    c_biz_topo_service = c_biz_topo_service_bak
    c_biz_topo_service.get_exu_smc = get_exu_smc_bak
    cmn.skynet.sleep = sleep_bak 
    c_device_service.get_instance = c_get_instance
end

function TestBizTopoService:test_update_bcu_src_conn_ready()
    cmn.skynet.fork = function(cb)
        cb()
    end
    cmn.skynet.sleep = function()
    end
    local biz_topo = {
        src_biz_connector_container = {}
    }
    local signal_mgr = {
        get = function()
            return {
                emit = function()
                end
            }
        end
    }
    c_biz_topo_service.biz_topo = biz_topo
    c_biz_topo_service.signal_mgr = signal_mgr
    c_biz_topo_service:update_bcu_src_conn_ready()
    lu.assertEquals(c_biz_topo_service.bcu_src_conn_ready, true)
end