-- 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 cjson = require 'cjson'
local signal = require 'mc.signal'
local c_biz_topo = require 'biz_topo.biz_topo'
local bs = require 'mc.bitstring'
local cmn = require 'common'
local c_bdf_config = require 'biz_topo.class.bdf_config'
local log = require 'mc.logging'

TestBizTopo = {}

-- MOCK 访问SMC
local biz_topo_node = {
    mds_obj = {
        RefSmcChip = {
            Read = function (...)
                return '\x31\x01\x30\x30\x30\x30\x30\x30\x30\x31\x30\x34\x30\x33\x30\x32\x30\x32\x33\x39\x34\x30'..
                       '\x00\x00\x00\x00\x09\x00\x00\x00\x00\x00' ..
                       '\x32\x01\x30\x30\x30\x30\x30\x30\x30\x31\x30\x34\x30\x33\x30\x32\x30\x32\x33\x39\x34\x30'..
                       '\x00\x00\x00\x00\x0B\x00\x00\x00\x00\x00'
            end
        },
        position = 1103
    }
}

-- 导入mds对象
local function load_test_sr_data(mds)
    local csr_objs = {}
    local pre_path = './test_data/'
    for i, v0 in ipairs(mds) do
        local file = io.open(pre_path .. v0[1], 'r')
        local mds_data_json = file:read('a')
        local objs = cjson.decode(mds_data_json).Objects
        for k, v in pairs(objs) do
            -- 槽位号和Location根据输入参数改写
            if v.ContainerSlot and v0[2] then
                v.ContainerSlot = v0[2]
            end
            if v.Location and v0[2] then
                v.Location = v.Location .. v0[2]
            end
            if v.RefPCIeAddrInfo then
                v.RefPCIeAddrInfo = v.RefPCIeAddrInfo .. '_' .. i
            end
            local csr_obj = {
                object = v,
                class_name = string.sub(k, 1, string.find(k, '_') - 1),
                position = i
            }
            csr_obj.object.name = k .. '_' .. i -- 对象名重命名
            table.insert(csr_objs, csr_obj)
        end
        file:close()
    end
    return csr_objs
end

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

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

-- sr格式: {{csr文件, 插在哪个槽位上}, ...}
local function biz_topo_new(sr)
    -- 初始化被测单例
    local obj = c_biz_topo.new()
    -- 导入mds数据，mds对象数据描述格式与CSR文件保持一致
    local csr_objs = load_test_sr_data(sr)
    local mock_complete_signal = signal.new()
    -- 模拟对象分发
    for _, v in ipairs(csr_objs) do
        obj:on_add_object(v.class_name, v.object, v.position, mock_complete_signal)
    end
    return obj
end

local function get_pcie_addr_info_by_slot(biz_topo, location, pcie_slot)
    for i, c in ipairs(biz_topo.target_pcie_connectors) do
        if c.ref_pcie_addr_info.mds_obj.Location == location and c.mds_obj.Slot == pcie_slot then
            return c.ref_pcie_addr_info.mds_obj
        end
    end
end

-- 模拟csr加载，检查业务TOPO计算结果
function TestBizTopo:test_construct_biz_topo()
    -- 00000001040302023940
    local sr = {
        {'IEU_00000001040302023940.json', 1},
        {'IEU_00000001040302023940.json', 2},
        {'BCU_00000001020302024339.json', 1},
        {'PSR.json'}
    }
    local biz_topo_obj = biz_topo_new(sr)
    biz_topo_obj:main()
    -- Riser1 PCIeSlot1
    local pcie_addr_info = get_pcie_addr_info_by_slot(biz_topo_obj, 'RiserCard1', 1)
    lu.assertEquals(pcie_addr_info.SlotID, 2)
    lu.assertEquals(pcie_addr_info.SocketID, 0)
    lu.assertEquals(pcie_addr_info.PortID, 0x0C)
    -- Riser1 PCIeSlot2
    pcie_addr_info = get_pcie_addr_info_by_slot(biz_topo_obj, 'RiserCard1', 2)
    lu.assertEquals(pcie_addr_info.SlotID, 3)
    lu.assertEquals(pcie_addr_info.SocketID, 0)
    lu.assertEquals(pcie_addr_info.PortID, 0x08)
    -- Riser2 PCIeSlot1
    pcie_addr_info = get_pcie_addr_info_by_slot(biz_topo_obj, 'RiserCard2', 1)
    lu.assertEquals(pcie_addr_info.SlotID, 5)
    lu.assertEquals(pcie_addr_info.SocketID, 1)
    lu.assertEquals(pcie_addr_info.PortID, 0x04)
    -- Riser2 PCIeSlot2
    pcie_addr_info = get_pcie_addr_info_by_slot(biz_topo_obj, 'RiserCard2', 2)
    lu.assertEquals(pcie_addr_info.SlotID, 6)
    lu.assertEquals(pcie_addr_info.SocketID, 1)
    lu.assertEquals(pcie_addr_info.PortID, 0x00)

    -- 00000001040302023945+00000001040302023947
    sr = {
        -- {板卡数据, 槽位号}
        {'IEU_00000001040302023945.json', 1},
        {'IEU_00000001040302023945.json', 2},
        {'IEU_00000001040302023947.json', 3},
        {'BCU_00000001020302024339.json', 1},
        {'PSR.json'}
    }
    biz_topo_obj = biz_topo_new(sr)
    biz_topo_obj:main()
    -- Riser1 PCIeSlot1
    pcie_addr_info = get_pcie_addr_info_by_slot(biz_topo_obj, 'RiserCard1', 1)
    lu.assertEquals(pcie_addr_info.SlotID, 3)
    lu.assertEquals(pcie_addr_info.SocketID, 0)
    lu.assertEquals(pcie_addr_info.PortID, 0x08)
    -- Riser2 PCIeSlot1
    pcie_addr_info = get_pcie_addr_info_by_slot(biz_topo_obj, 'RiserCard2', 1)
    lu.assertEquals(pcie_addr_info.SlotID, 6)
    lu.assertEquals(pcie_addr_info.SocketID, 1)
    lu.assertEquals(pcie_addr_info.PortID, 0x00)

    -- Riser3 PCIeSlot1
    pcie_addr_info = get_pcie_addr_info_by_slot(biz_topo_obj, 'RiserCard3', 1)
    lu.assertEquals(pcie_addr_info.SlotID, 7)
    lu.assertEquals(pcie_addr_info.SocketID, 1)
    lu.assertEquals(pcie_addr_info.PortID, 0x08)
    pcie_addr_info = get_pcie_addr_info_by_slot(biz_topo_obj, 'RiserCard3', 2)
    lu.assertEquals(pcie_addr_info.SlotID, 8)
    lu.assertEquals(pcie_addr_info.SocketID, 1)
    lu.assertEquals(pcie_addr_info.PortID, 0x0C)
end

function TestBizTopo:test_get_device()
    local src_connector = {
        mds_obj = {
            UpstreamResources = {
                {Name = "SerDes_1_8", ID = 8, Offset = 0, Width = 8},
                {Name = "SerDes_1_7", ID = 7, Offset = 0, Width = 4},
                {Name = "SerDes_1_10", ID = 10, Offset = 0, Width = 4}
            },
            ActualResourceOrder = {"SerDes_1_10", "SerDes_1_7", "SerDes_1_8"},
        },
        res_serdeses = {
            {
                mds_obj = {
                    Name = "SerDes_1_8",
                    ID = 8,
                    LinkWidth = 8,
                    WorkMode = 1,
                    ModeConfigs = {
                        {Mode = 1, Device = {8, 8, 9, 9, 10, 10, 11, 11}, ControllerIndex = {1, 1, 1, 1, 1, 1, 1, 1}},
                    }
                }
            },
            {
                mds_obj = {
                    Name = "SerDes_1_7",
                    ID = 7,
                    LinkWidth = 4,
                    WorkMode = 1,
                    ModeConfigs = {
                        {Mode = 1, Device = {12, 12, 13, 13}, ControllerIndex = {1, 1, 1, 1}},
                    }
                }
            },
            {
                mds_obj = {
                    Name = "SerDes_1_10",
                    ID = 10,
                    LinkWidth = 4,
                    WorkMode = 1,
                    ModeConfigs = {
                        {Mode = 1, Device = {14, 14, 15, 15}, ControllerIndex = {1, 1, 1, 1}}
                    }
                }
            }
        }
    }

    local device = c_biz_topo.get_device(src_connector, 0, 8, 0)
    lu.assertEquals(device, 0x0C)
    device = c_biz_topo.get_device(src_connector, 8, 8, 0)
    lu.assertEquals(device, 0x08)
end

-- BCU x16分2个x8 SerDes，到SEU是4个4x  示例类：BusinessConnector_CPU2UBCDD2 B4c
function TestBizTopo:test_get_device_offset_B4c()
    local src_connector = {
        mds_obj = {
            UpstreamResources = {
                {Name = "SerDes_1_5_A", ID = 5, Offset = 0, Width = 8},
                {Name = "SerDes_1_6_A", ID = 6, Offset = 0, Width = 8}
            }
        },
        res_serdeses = {
            {
                mds_obj = {
                    Name = "SerDes_1_5_A",
                    ID = 0,
                    SocketID = 1,
                    LinkWidth = 8,
                    WorkMode = 1,
                    ModeConfigs = {
                        {
                            Mode = 1,
                            Device = {12, 12, 13, 13, 14, 14, 15, 15},
                            ControllerIndex = {2, 2, 2, 2, 2, 2, 2, 2}
                        },
                    }
                }
            },
            {
                mds_obj = {
                    Name = "SerDes_1_6_A",
                    ID = 1,
                    SocketID= 1,
                    LinkWidth = 8,
                    WorkMode = 1,
                    ModeConfigs = {
                        {
                            Mode = 1,
                            Device = {
                                16, 16, 17, 17, 18, 18, 19, 19
                            },
                            ControllerIndex = {
                                2, 2, 2, 2, 2, 2, 2, 2
                            }
                        },
                    }
                }
            }
        }
    }

    local device = c_biz_topo.get_device(src_connector, 8, 4, 4)
    lu.assertEquals(device, 18)
end

-- BCU x16分2个x8 SerDes，到SEU是4个4x
function TestBizTopo:test_get_device_offset_A1a_A1c()
    local src_connector = {
        mds_obj = {
            UpstreamResources = {
                {Name = "SerDes_0_5_A", ID = 5, Offset = 0, Width = 8},
                {Name = "SerDes_0_6_A", ID = 6, Offset = 0, Width = 8}
            },
            ActualResourceOrder = {"SerDes_0_6_A", "SerDes_0_5_A"},
        },
        res_serdeses = {
            {
                mds_obj = {
                    Name = "SerDes_0_5_A",
                    ID = 0,
                    SocketID = 0,
                    LinkWidth = 8,
                    WorkMode = 1,
                    ModeConfigs = {
                        {
                            Mode = 1,
                            Device = {12, 12, 13, 13, 14, 14, 15, 15},
                            ControllerIndex = {2, 2, 2, 2, 2, 2, 2, 2}
                        },
                    }
                }
            },
            {
                mds_obj = {
                    Name = "SerDes_0_6_A",
                    ID = 1,
                    SocketID = 0,
                    LinkWidth = 8,
                    WorkMode = 1,
                    ModeConfigs = {
                        {
                            Mode = 1,
                            Device = {16, 16, 17, 17, 18, 18, 19, 19},
                            ControllerIndex = {2, 2, 2, 2, 2, 2, 2, 2}
                        },
                    }
                }
            }
        }
    }

    -- Offset为0，A1a场景
    local device = c_biz_topo.get_device(src_connector, 0, 4, 4)
    lu.assertEquals(device, 16)

    -- Offset为8，A1c场景
    local device = c_biz_topo.get_device(src_connector, 8, 4, 4)
    lu.assertEquals(device, 12)
end

-- x8 riser插A1a
function TestBizTopo:test_get_device_offset_riser_riser_to_A1a_A1c()
    -- 默认顺序为A1a/A1c
    local src_connector = {
        mds_obj = {
            UpstreamResources = {
                {Name = "SerDes_0_5_A", ID = 5, Offset = 0, Width = 8},
                {Name = "SerDes_0_6_A", ID = 6, Offset = 0, Width = 8}
            },
            ActualResourceOrder = {"SerDes_0_6_A", "SerDes_0_5_A"},
        },
        res_serdeses = {
            {
                mds_obj = {
                    Name = "SerDes_0_5_A",
                    ID = 0,
                    SocketID = 0,
                    LinkWidth = 8,
                    WorkMode = 1,
                    ModeConfigs = {
                        {
                            Mode = 1,
                            Device = {12, 12, 13, 13, 14, 14, 15, 15},
                            ControllerIndex = {2, 2, 2, 2, 2, 2, 2, 2}
                        },
                    }
                }
            },
            {
                mds_obj = {
                    Name = "SerDes_0_6_A",
                    ID = 1,
                    SocketID = 0,
                    LinkWidth = 8,
                    WorkMode = 1,
                    ModeConfigs = {
                        {
                            Mode = 1,
                            Device = {16, 16, 17, 17, 18, 18, 19, 19},
                            ControllerIndex = {2, 2, 2, 2, 2, 2, 2, 2}
                        },
                    }
                }
            }
        }
    }

    -- link_width=8，port_offset=0,riser卡插A1a场景
    local device = c_biz_topo.get_device(src_connector, 0, 8, 0)
    lu.assertEquals(device, 16)

    -- link_width=16，port_offset=0,riser卡插A1a A1c场景
    local device = c_biz_topo.get_device(src_connector, 0, 16, 0)
    lu.assertEquals(device, 12)

end


-- x8分2个x4 SerDes  示例类：BusinessConnector_CPU2UBC1
function TestBizTopo:test_get_device_offset_1()
    local src_connector = {
        mds_obj = {
            UpstreamResources = {
                {Name = "SerDes_1_0_A", ID = 0, Offset = 0, Width = 4},
                {Name = "SerDes_1_1_A", ID = 1, Offset = 0, Width = 4}
            }
        },
        res_serdeses = {
            {
                mds_obj = {
                    Name = "SerDes_1_0_A",
                    ID = 0,
                    SocketID = 1,
                    LinkWidth = 4,
                    WorkMode = 1,
                    ModeConfigs = {
                        {Mode = 1, Device = {0, 0, 1, 1}, ControllerIndex = {0, 0, 0, 0}},
                    }
                }
            },
            {
                mds_obj = {
                    Name = "SerDes_1_1_A",
                    ID = 1,
                    LinkWidth = 4,
                    WorkMode = 1,
                    ModeConfigs = {
                        {Mode = 1, Device = {2, 2, 3, 3}, ControllerIndex = {0, 0, 0, 0}},
                    }
                }
            }
        }
    }

    local device = c_biz_topo.get_device(src_connector, 0, 4, 4)
    lu.assertEquals(device, 2)
end

-- x8分2个x4 SerDes 与test_get_device_offset_1类似
function TestBizTopo:test_get_device_offset_2()
    local src_connector = {
        mds_obj = {
            UpstreamResources = {
                {Name = "SerDes_0_0_B", ID = 0, Offset = 0, Width = 4},
                {Name = "SerDes_0_1_B", ID = 1, Offset = 0, Width = 4}
            }
        },
        res_serdeses = {
            {
                mds_obj = {
                    Name = "SerDes_0_0_B",
                    ID = 7,
                    SocketID = 0,
                    LinkWidth = 4,
                    WorkMode = 1,
                    ModeConfigs = {
                        {Mode = 1, Device = {20, 20, 21, 21}, ControllerIndex = {3, 3, 3, 3}},
                    }
                }
            },
            {
                mds_obj = {
                    Name = "SerDes_0_1_B",
                    ID = 8,
                    SocketID = 0,
                    LinkWidth = 4,
                    WorkMode = 1,
                    ModeConfigs = {
                        {Mode = 1, Device = {22, 22, 23, 23}, ControllerIndex = {3, 3, 3, 3}},
                    }
                }
            }
        }
    }

    local device = c_biz_topo.get_device(src_connector, 0, 4, 4)
    lu.assertEquals(device, 22)
end

-- x8分1个x8 SerDes  示例类：BusinessConnector_CPU1UBC4
function TestBizTopo:test_get_device_offset_3()
    local src_connector = {
        mds_obj = {
            UpstreamResources = {
                {Name = "SerDes_0_5_B", ID = 5, Offset = 0, Width = 8}
            }
        },
        res_serdeses = {
            {
                mds_obj = {
                    Name = "SerDes_0_5_B",
                    ID = 12,
                    SocketID = 0,
                    LinkWidth = 8,
                    WorkMode = 1,
                    ModeConfigs = {
                        {Mode = 1, Device = {
                            32,
                            32,
                            33,
                            33,
                            34,
                            34,
                            35,
                            35},
                            ControllerIndex = {
                            5,
                            5,
                            5,
                            5,
                            5,
                            5,
                            5,
                            5}},
                    }
                }
            }
        }
    }

    local device = c_biz_topo.get_device(src_connector, 0, 4, 4)
    lu.assertEquals(device, 34)
end


function TestBizTopo:test_parse_link_width()
    local port_cnt, link_width
    -- 多个端口 2X8
    port_cnt, link_width = c_biz_topo.parse_link_width('2X8')
    lu.assertEquals(port_cnt, 2)
    lu.assertEquals(link_width, 8)
    -- 一个端口 X16
    port_cnt, link_width = c_biz_topo.parse_link_width('X16')
    lu.assertEquals(port_cnt, 1)
    lu.assertEquals(link_width, 16)
end

function TestBizTopo:test_get_matched_unit_config_static()
    local unit_config_list = {
        {
            mds_obj = {
                SlotType = 'IEU',
                SlotNumber = 1,
                Configurations = {
                    {
                        UID = '00000001040302044498',
                        Index = 2,
                        SrcPortName = {
                            "A1a",
                            "A2a",
                            "A2c"
                        },
                        TargetPortID = {
                            17,
                            33,
                            49
                        },
                        Slot = {
                            1,
                            2,
                            3
                        }
                    }
                }
            }
        }
    }
    local unit_config = c_biz_topo:get_matched_unit_config(unit_config_list, 'IEU', 1, '00000001040302044498')
    lu.assertNotIsNil(unit_config)

    unit_config = c_biz_topo:get_matched_unit_config(unit_config_list, 'IEU', 2, '00000001040302044498')
    lu.assertIsNil(unit_config)
end

local dynamic_unit_config_list = {
    {
        mds_obj = {
            SlotType = 'SEU',
            SlotNumber = 1,
            Configurations = {
                {
                    UID = '00000001030302024340',
                    Index = 0,
                    Default = true,
                    SrcPortName = {
                        "D7a",
                        "D6a"
                    },
                    TargetPortID = {
                        17,
                        49
                    },
                    Slot = {
                        44,
                        45,
                        46,
                        47
                    }
                }
            }
        }
    },
    {
        mds_obj = {
            SlotType = 'SEU',
            SlotNumber = 1,
            Configurations = {
                {
                    UID = '00000001030302024340',
                    Index = 0,
                    SrcPortName = {
                        "D4a",
                        "D5a"
                    },
                    TargetPortID = {
                        33,
                        49
                    },
                    Slot = {
                        44,
                        45,
                        46,
                        47
                    }
                }
            }
        }
    },
}

function TestBizTopo:test_get_matched_unit_config_dynamic()
    local sr = {
        {'SEU_00000001030302024340.json', 1},
        {'BCU_00000001020302024339.json', 1},
        {'PSR.json'}
    }
    local biz_topo_obj = biz_topo_new(sr)
    biz_topo_obj:main()

    table.insert(biz_topo_obj.biz_topo_node_list, biz_topo_node)
    -- 做动态建链的UID
    local unit_config = biz_topo_obj:get_matched_unit_config(dynamic_unit_config_list, 'SEU', 1, '00000001030302024340')
    lu.assertNotIsNil(unit_config)

    unit_config = biz_topo_obj:get_matched_unit_config(dynamic_unit_config_list, 'SEU', 2, '00000001030302024340')
    lu.assertIsNil(unit_config)
end

function TestBizTopo:test_find()
    -- 基本数据类型
    local index = c_biz_topo.find({4, 5, 6}, 6)
    lu.assertEquals(index, 3)

    -- table类型
    local obj_coll = {{name = 'A', id = 1}, {name = 'B', id = 2}}
    local obj = c_biz_topo.find(obj_coll, function (item)
        if item.name == 'B' then
            return true
        end
    end)
    lu.assertEquals(obj.id, 2)
end

function TestBizTopo:test_parse_port_name()
    local zone, port_id = c_biz_topo.parse_port_name('A2a')
    lu.assertEquals(zone, 1)
    lu.assertEquals(port_id, 5)
    local zone, port_id = c_biz_topo.parse_port_name('B5a')
    lu.assertEquals(zone, 2)
    lu.assertEquals(port_id, 17)
end

-- 功能: 多种pcie卡插法配置，找到最匹配的插法
local seu_unit_config_list = {
    {
        mds_obj = {
            SlotType = 'SEU',
            SlotNumber = 5,
            Configurations = {
                {
                    UID = '00000001030302024340',
                    Index = 0,
                    Default = true,
                    SrcPortName = {
                        "D7a",
                        "D6a"
                    },
                    TargetPortID = {
                        17,
                        49
                    },
                    Slot = {
                        44,
                        45,
                        46,
                        47
                    }
                },
                {
                    UID = '00000001030302046571',
                    Index = 0,
                    SrcPortName = {
                        "D4a",
                        "D5a"
                    },
                    TargetPortID = {
                        33,
                        17
                    },
                    Slot = {
                        46,
                        47
                    }
                },
                {
                    UID = '00000001030302024340',
                    Index = 0,
                    SrcPortName = {
                        "D4a",
                        "D5a"
                    },
                    TargetPortID = {
                        33,
                        49
                    },
                    Slot = {
                        44,
                        45,
                        46,
                        47
                    }
                },
                {
                    UID = '00000001030302024340',
                    Index = 0,
                    SrcPortName = {
                        "A4a"
                    },
                    TargetPortID = {
                        1
                    },
                    Slot = {
                        44,
                        45,
                        46,
                        47
                    }
                },
                {
                    UID = '00000001030302046571',
                    Index = 0,
                    Default = true,
                    SrcPortName = {
                        "D5a"
                    },
                    TargetPortID = {
                        17
                    },
                    Slot = {
                        46,
                        47
                    }
                }
            }
        }
    }
}

-- 用例场景: UnitConfiguration没有TargetPortID
-- 预期结果: 无法匹配，获取默认插法配置
local seu_unit_config_list_no_target_port_id = {
    {
        mds_obj = {
            SlotType = 'SEU',
            SlotNumber = 5,
            Configurations = {
                {
                    UID = '00000001030302024340',
                    Index = 0,
                    Default = true,
                    SrcPortName = {
                        "D7a",
                        "D6a"
                    },
                    TargetPortID = {
                    },
                    Slot = {
                        44,
                        45,
                        46,
                        47
                    }
                },
                {
                    UID = '00000001030302024340',
                    Index = 0,
                    SrcPortName = {
                        "D4a",
                        "D5a"
                    },
                    TargetPortID = {
                    },
                    Slot = {
                        44,
                        45,
                        46,
                        47
                    }
                },
                {
                    UID = '00000001030302024340',
                    Index = 0,
                    SrcPortName = {
                        "A4a"
                    },
                    TargetPortID = {
                    },
                    Slot = {
                        44,
                        45,
                        46,
                        47
                    }
                },
            }
        }
    }
}
function TestBizTopo:test_match_unit_config_with_topo_no_target_port_id()
    local sr = {
        {'SEU_00000001030302024340.json', 1},
        {'BCU_00000001020302024339.json', 1},
        {'PSR.json'}
    }
    local biz_topo_obj = biz_topo_new(sr)
    biz_topo_obj:main()

    table.insert(biz_topo_obj.biz_topo_node_list, biz_topo_node)

    -- 预期结果: 无法匹配，获取默认插法配置
    local unit_config = biz_topo_obj:get_matched_unit_config(seu_unit_config_list_no_target_port_id,
        'SEU', 5, '00000001030302024340')
    lu.assertNotIsNil(unit_config)
    lu.assertEquals(unit_config.Default, true)
end

-- 用例场景: UnitConfiguration没有SrcPortName
-- 预期结果: 无法匹配，获取默认插法配置
local seu_unit_config_list_no_src_port_name = {
    {
        mds_obj = {
            SlotType = 'SEU',
            SlotNumber = 5,
            Configurations = {
                {
                    UID = '00000001030302024340',
                    Index = 0,
                    Default = true,
                    SrcPortName = {
                    },
                    TargetPortID = {
                        17,
                        49
                    },
                    Slot = {
                        44,
                        45,
                        46,
                        47
                    }
                },
                {
                    UID = '00000001030302024340',
                    Index = 0,
                    SrcPortName = {
                    },
                    TargetPortID = {
                        33,
                        49
                    },
                    Slot = {
                        44,
                        45,
                        46,
                        47
                    }
                },
                {
                    UID = '00000001030302024340',
                    Index = 0,
                    SrcPortName = {
                    },
                    TargetPortID = {
                        1
                    },
                    Slot = {
                        44,
                        45,
                        46,
                        47
                    }
                },
            }
        }
    }
}
function TestBizTopo:test_match_unit_config_with_topo_no_src_port_name()
    local sr = {
        {'SEU_00000001030302024340.json', 1},
        {'BCU_00000001020302024339.json', 1},
        {'PSR.json'}
    }
    local biz_topo_obj = biz_topo_new(sr)
    biz_topo_obj:main()

    table.insert(biz_topo_obj.biz_topo_node_list, biz_topo_node)

    local unit_config = biz_topo_obj:get_matched_unit_config(seu_unit_config_list_no_src_port_name,
        'SEU', 5, '00000001030302024340')
    lu.assertNotIsNil(unit_config)
    lu.assertEquals(unit_config.Default, true)
end


local bs_topo = bs.new([[<<
    target_port_id:8,
    index:8,
    uid:24/string,
    port_id:8,
    _:5/string
>>]])

local function create_biz_topo_node(test_data, slot)
    local data = ''
    for _, d in pairs(test_data) do
        data = data .. bs_topo:pack(d)
    end
    return {
        mds_obj = {
            Slot = slot,
            RefSmcChip = {
                Read = function(...)
                    return data
                end
            }
        }
    }
end

-- 用例场景: cpld读取的拓扑信息为空
-- 预期结果: 无法匹配，获取默认插法配置
function TestBizTopo:test_match_unit_config_with_topo_no_cpld_info()
    local sr = {
        {'SEU_00000001030302024340.json', 1},
        {'BCU_00000001020302024339.json', 1},
        {'PSR.json'}
    }
    local biz_topo_obj = biz_topo_new(sr)
    biz_topo_obj:main()

    local biz_topo_node_data = {}

    -- 模拟bcu smc命令
    local biz_topo_node = create_biz_topo_node(biz_topo_node_data)
    table.insert(biz_topo_obj.biz_topo_node_list, biz_topo_node)

    local unit_config = biz_topo_obj:get_matched_unit_config(seu_unit_config_list, 'SEU', 5, '00000001030302024340')
    lu.assertNotIsNil(unit_config)
    lu.assertEquals(unit_config.Default, true)
end

-- 用例场景: cpld读取的uid与UnitConfiguration的uid不匹配
-- 预期结果: 无法匹配，获取默认插法配置
function TestBizTopo:test_match_unit_config_with_topo_uid_not_match_cpld_info()
    local sr = {
        {'SEU_00000001030302024340.json', 1},
        {'BCU_00000001020302024339.json', 1},
        {'PSR.json'}
    }
    local biz_topo_obj = biz_topo_new(sr)
    biz_topo_obj:main()

    local biz_topo_node_data = {
        {target_port_id = 33, index = 0, uid = '00000001030302046571', port_id = 9},
        {target_port_id = 17, index = 0, uid = '00000001030302046571', port_id = 12}
    }

    -- 模拟bcu smc命令
    local biz_topo_node = create_biz_topo_node(biz_topo_node_data)
    table.insert(biz_topo_obj.biz_topo_node_list, biz_topo_node)

    local unit_config = biz_topo_obj:get_matched_unit_config(seu_unit_config_list, 'SEU', 5, '00000001030302024340')
    lu.assertNotIsNil(unit_config)
    lu.assertEquals(unit_config.Default, true)
end

-- 用例场景: cpld读取的拓扑信息与UnitConfiguration部分配置一致
-- 预期结果: 无法匹配，获取默认插法配置
function TestBizTopo:test_match_unit_config_with_topo_uid_part_match_cpld_info()
    local sr = {
        {'SEU_00000001030302024340.json', 1},
        {'BCU_00000001020302024339.json', 1},
        {'PSR.json'}
    }
    local biz_topo_obj = biz_topo_new(sr)
    biz_topo_obj:main()

    local biz_topo_node_data = {
        {target_port_id = 17, index = 0, uid = '00000001030302024340', port_id = 12}
    }

    -- 模拟bcu smc命令
    local biz_topo_node = create_biz_topo_node(biz_topo_node_data)
    table.insert(biz_topo_obj.biz_topo_node_list, biz_topo_node)

    local unit_config = biz_topo_obj:get_matched_unit_config(seu_unit_config_list, 'SEU', 5, '00000001030302024340')
    lu.assertNotIsNil(unit_config)
    lu.assertEquals(unit_config.Default, true)
end

function printTable(t, indent)
    indent = indent or ""
    for k, v in pairs(t) do
        if type(v) == "table" then
            print(indent .. tostring(k) .. ":")
            printTable(v, indent .. "  ")
        else
            print(indent .. tostring(k) .. " = " .. tostring(v))
        end
    end
end

-- 用例场景: cpld读取的portId与UnitConfiguration的portId不匹配
-- 预期结果: 插法错误，target_port_id不一致，选默认的插法配置
function TestBizTopo:test_match_unit_config_with_topo_port_id_mismatch_cpld_info()
    local sr = {
        {'SEU_00000001030302024340.json', 1},
        {'BCU_00000001020302024339.json', 1},
        {'PSR.json'}
    }
    local biz_topo_obj = biz_topo_new(sr)
    biz_topo_obj:main()

    local biz_topo_node_data = {
        {target_port_id = 33, index = 0, uid = '00000001030302024340', port_id = 13},
        {target_port_id = 49, index = 0, uid = '00000001030302024340', port_id = 17}
    }

    -- 模拟bcu smc命令
    local biz_topo_node_test = create_biz_topo_node(biz_topo_node_data)
    table.insert(biz_topo_obj.biz_topo_node_list, biz_topo_node_test)

    biz_topo_obj.topo_info = {
        [1] = {
            ['D'] = {
                [13] = {
                    [0] = {
                        target_port_id = 33,
                        index = 0,
                        uid = '00000001030302024340',
                        port_id = 13,
                    }
                },
                [17] = {
                    [0] = {
                        target_port_id = 1, -- 预期是49
                        index = 0,
                        uid = '00000001030302024340',
                        port_id = 17,
                    }
                }
            }
        }
    }

    local unit_config = biz_topo_obj:get_matched_unit_config(seu_unit_config_list, 'SEU', 5, '00000001030302024340')
    
    lu.assertNotIsNil(unit_config)
    lu.assertEquals(unit_config.Default, true)
end

-- 用例场景: cpld读取的portId与UnitConfiguration的portId不匹配
-- 预期结果: 插法不全，获取最接近的插法配置
function TestBizTopo:test_match_unit_config_with_topo_incomplete_cpld_info()
    local sr = {
        {'SEU_00000001030302024340.json', 1},
        {'BCU_00000001020302024339.json', 1},
        {'PSR.json'}
    }
    local biz_topo_obj = biz_topo_new(sr)
    biz_topo_obj:main()

    local biz_topo_node_data = {
        {target_port_id = 33, index = 0, uid = '00000001030302024340', port_id = 13},
        {target_port_id = 49, index = 0, uid = '00000001030302024340', port_id = 17}
    }

    -- 模拟bcu smc命令
    local biz_topo_node_test = create_biz_topo_node(biz_topo_node_data)
    table.insert(biz_topo_obj.biz_topo_node_list, biz_topo_node_test)

    biz_topo_obj.topo_info = {
        [1] = {
            ['D'] = {
                [13] = {
                    [0] = {
                        target_port_id = 33,
                        index = 0,
                        uid = '00000001030302024340',
                        port_id = 13,
                    }
                }
            }
        }
    }

    local unit_config = biz_topo_obj:get_matched_unit_config(seu_unit_config_list, 'SEU', 5, '00000001030302024340')

    lu.assertNotIsNil(unit_config)
    lu.assertIsNil(unit_config.Default)
    lu.assertEquals(unit_config.SrcPortName[1], "D4a")
    lu.assertEquals(unit_config.SrcPortName[2], "D5a")
    lu.assertEquals(unit_config.UID, '00000001030302024340')
    lu.assertEquals(unit_config.matched_times, 1)
    lu.assertEquals(unit_config.port_num, 2)
    lu.assertEquals(unit_config.status, 5)
end

function TestBizTopo:test_init_bdf_map()
    cmn.skynet.fork = function(cb)
        cb()
    end
    local obj = {
        mds_obj = {
            SocketId = nil,
        },
        configs = {
            { type = 0, port_id = 1, bus = 1, device = 1, func = 1 },
            { type = 1, port_id = 1, controller_index = 1 },
            { type = 2, port_id = 1 },
            { type = 3, port_id = 1 },
            { type = 4, port_id = 1 },
            { type = 5, port_id = 1 }
        },
        build_bdf_cfgs = function()
        end,
        check_db = function()
        end
    }
    c_biz_topo.bdf_config_map = {}

    c_biz_topo:init_bdf_map(obj)
    obj.mds_obj.SocketId = 1
    c_biz_topo:init_bdf_map(obj)

    lu.assertEquals(c_biz_topo.bdf_config_map, {{[0]={{1, 1, 1}}, {}, {}, {}, {}, {}}})
end

function TestBizTopo:test_check_config()
    local fork_bak = cmn.skynet.fork
    cmn.skynet.fork = function(cb)
        cb()
    end
    c_bdf_config.config_new = function()
        return { PortId = 1, ControllerIndex = 2, Segment = 3,
            Bus = 4, Device = 5, Function = 6 }
    end
    local no_type = c_bdf_config:check_config({{1}})
    lu.assertEquals(no_type, false)

    c_bdf_config.config_new = function()
        return { PortId = 1, ControllerIndex = 2, Segment = 3,
            Bus = 4, Device = 5, Function = 6, Type = 7 }
    end
    local normal_type = c_bdf_config:check_config({{1}, {2}})
    lu.assertEquals(normal_type, true)

    cmn.skynet.fork = fork_bak
end

function TestBizTopo:test_check_db()
    local sleep_bak = cmn.skynet.sleep
    cmn.skynet.sleep = function()
        log:raise("break")
    end

    c_bdf_config.mds_obj = {
        SocketId = 1,
        ConfigLength = 2,
    }

    c_bdf_config.check_config = function()
        return false
    end

    local db = {
        BDFConfig = {
            SocketId = {
                eq = function()
                    return {
                        exec = function()
                        end
                    }
                end
            }
        },
        select = function()
            return {
                where = function()
                    return {
                        first = function()
                            return {
                                BDFConfigs = {1}
                            }
                        end
                    }
                end
            }
        end,
        delete = function()
            return {
                where = function()
                    return {
                        first = function()
                            return {
                                BDFConfigs = {1}
                            }
                        end
                    }
                end
            }
        end
    }
    local ok, _ = pcall(c_bdf_config.check_db, c_bdf_config, db)
    lu.assertEquals(ok, false)
    cmn.skynet.sleep = sleep_bak
end

function TestBizTopo:test_get_target_conn_by_addr_obj()
    local addr_obj = {
        position = '1',
        mds_obj = {
            name = 'ref-name'
        }
    }
    c_biz_topo.biz_connector_list = {
        {
            position = '1',
            mds_obj = {
                RefPCIeAddrInfo = 'ref-name'
            }
        }
    }
    local biz_conn = c_biz_topo:get_target_conn_by_addr_obj(addr_obj)
    lu.assertEquals(biz_conn, {
        position = '1',
        mds_obj = {
            RefPCIeAddrInfo = 'ref-name'
        }
    })
end

function TestBizTopo:test_parse_max_link_rate()
    local ret = c_biz_topo.mock_parse_max_link_rate('PCIe')
     lu.assertEquals(ret, "")
end

function TestBizTopo:test_build_eth_connector_cfgs()
    local src_connector = {
        bcu_index = 1,
        res_serdeses = {
            [1] = {
                mds_obj = {
                    SocketID = 1,
                    ModeConfigs = {
                        {Mode = 1},
                        {
                            Mode = 6, 
                            DieId = 1, 
                            ControllerIndex = {
                                1,2,3,4,5,6,7,8,9,10
                            }
                        }
                    }
                }
            }
        },
        mds_obj = {
            name = "src-name"
        }
    }
    local pfid_map = {
    }
    local bdf_config_map = {
        [1] = {
            [1] = {
                1,2,3,4,5,6,7,8,9,10
            }
        }
    }
    local t_connector = {}
    c_biz_topo.pfid_map = pfid_map
    c_biz_topo.bdf_config_map = bdf_config_map
    c_biz_topo:build_eth_connector_cfgs(src_connector, t_connector, nil)
    lu.assertEquals(src_connector.c_idxs, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
    lu.assertEquals(t_connector.start_lane, 0)
end

function TestBizTopo:test_check_conn_slot()
    local sleep_bak = cmn.skynet.sleep
    cmn.skynet.sleep = function()
        c_biz_topo.target_pcie_connectors = {}
    end

    c_biz_topo.target_pcie_connectors = {
        {
            mds_obj = {
                Slot = 0
            },
            position = 'position'
        }
    }
    c_biz_topo:check_conn_slot()

    lu.assertEquals(#c_biz_topo.target_pcie_connectors, 0)
    cmn.skynet.sleep = sleep_bak
end

function TestBizTopo:test_get_pcie_addr_by_pos()
    c_biz_topo.target_pcie_connectors = {
        {
            ref_pcie_addr_info = {
                get_prop = function()
                    return 2
                end
            },
            ref_mgmt_connector = {
                GroupPosition = '010203'
            }
        }
    }
    local ret = c_biz_topo:get_pcie_addr_by_pos('01020303')
    lu.assertNotEquals(ret, nil)
end