-- 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 imu_cmd = require 'imu'
local mdb = require 'mc.mdb'
local c_pcie_device = require 'device.class.pcie_device'
local cmn = require 'common'
local client = require 'pcie_device.client'
local c_pcie_device_app = require 'pcie_device_app'
local common_interface = require 'common_interface'

TestPcieDevice = {}

local function reset_env()
    client.GetFruCtrlObjects = function()
        return {{PowerState = "ON", path = '/bmc/kepler/Systems/1'}}
    end
    imu_cmd.get_info_from_pmu =  function()
        return {0x44, 0x33, 0x22, 0x11} --base class code 是0x11
    end
    common_interface.get_instance = function()
        return {
            power_status = {"ON"}
        }
    end
end

function TestPcieDevice:test_query_class_code_from_pmu()
    local obj = c_pcie_device.new({
        DeviceName = "pcie-device",
        DeviceType = 8,
        SocketID = 1,
        DevBus = 150,
        DevDevice = 0,
        DevFunction = 0,
        BaseClassCode = 0,
        SubClassCode = 0,
        ProgrammingInterface = 0,
        MultihostPresence = 1,
        path = '/bmc/kepler/Systems/1',
        property_changed = {
            on = function()
            end
        }
    }, "123", {})
    obj:set_prop('DeviceType', 8)
    lu.assertEquals(obj:get_prop('DevBus'), 0x96)

    reset_env()
    obj:query_class_code_from_pmu()
    lu.assertEquals(obj:get_prop('BaseClassCode'), 0x11)

    -- 获取classcode nil
    reset_env()
    obj:set_prop('BaseClassCode', 0)
    imu_cmd.get_info_from_pmu = function()
        return nil
    end
    obj:query_class_code_from_pmu()
    lu.assertEquals(obj:get_prop('BaseClassCode'), 0xFE)

    -- DeviceType是Disk
    reset_env()
    obj:set_prop('BaseClassCode', 0)
    obj:set_prop('DeviceType', 8)
    obj:query_class_code_from_pmu()
    lu.assertEquals(obj:get_prop('BaseClassCode'), 0x11)

    -- 获取上电状态为空
    common_interface.get_instance = function() return end
    obj:set_prop('BaseClassCode', 0)
    pcall(function()
        obj:query_class_code_from_pmu()
    end)
    lu.assertEquals(obj:get_prop('BaseClassCode'), 0)
    common_interface.get_instance = function()
        return {
            power_status = {"OFF"}
        }
    end
    pcall(obj.query_class_code_from_pmu, obj)
    lu.assertEquals(obj:get_prop('BaseClassCode'), 0)

    reset_env()
    obj:set_prop('MultihostPresence', 0)
    local get_prop_bak = obj.get_prop
    obj.get_prop = function(prop)
        if prop == 'SocketID' then
            error("get prop error")
        end
    end
    pcall(obj.query_class_code_from_pmu, obj)
    obj.get_prop = get_prop_bak
    obj:set_prop('MultihostPresence', 1)
    lu.assertEquals(obj:get_prop('BaseClassCode'), 0)

    reset_env()
    obj:set_prop('DevBus', 255)
    pcall(obj.query_class_code_from_pmu, obj)
    lu.assertEquals(obj:get_prop('BaseClassCode'), 0)
    obj:set_prop('DevBus', 150)

    -- query task
    reset_env()
    obj:set_prop('BaseClassCode', 0)
    obj:set_prop('DeviceType', 8)
    obj.class_code_need_update = true
    cmn.skynet.fork_loop = function(_, cb)
        cb()
    end
    local sleep_bak = cmn.skynet.sleep
    cmn.skynet.sleep = function()
        error("break")
    end
    pcall(obj.query_from_pmu_task, obj)
    lu.assertEquals(obj:get_prop('BaseClassCode'), 0x11)
    cmn.skynet.sleep = sleep_bak
end

function TestPcieDevice:test_sync_pcie_addr_info()
    local obj = c_pcie_device.new({
        DeviceName = "pcie-device",
        DeviceType = 8,
        SocketID = 1,
        DevBus = 150,
        DevDevice = 0,
        DevFunction = 0,
        BaseClassCode = 0,
        SubClassCode = 0,
        ProgrammingInterface = 0,
        MultihostPresence = 1,
        path = '/bmc/kepler/Systems/1',
        property_changed = {
            on = function()
            end
        }
    }, "123", {})
    local pcie_addr_info_obj = {}
    pcie_addr_info_obj.mds_obj = {}
    pcie_addr_info_obj.mds_obj.property_changed = {
        on = function (_, func_prop_changed)
            pcall(func_prop_changed, 'SlotID', 1, {})
        end
    }
    pcie_addr_info_obj.get_prop = function ()
        return ''
    end
    pcie_addr_info_obj.set_prop = function ()
        return true
    end
    local ok = pcall(function ()
        obj:sync_pcie_addr_info(pcie_addr_info_obj)
    end)
    lu.assertEquals(ok, true)
end

function TestPcieDevice:test_get_device_silk()
    local req = {}
    req.Data = '0000:01:00.0'
    local device_type_parameter = '0x02'
    local rsp_body = 'test'
    c_pcie_device_app.device_service = {
        pcie_device_list = {}
    }
    local ok = pcall(function()
        c_pcie_device_app:get_device_silk(device_type_parameter,rsp_body,req)
    end)
    lu.assertEquals(ok, false)
end

function TestPcieDevice:test_get_device_model()
    local req = {}
    req.Data = '0000:01:00.0'
    local rsp_body = 'test'
    c_pcie_device_app.device_service = {
        pcie_device_list = {
            [1] = {
                mds = {
                    Bus = 1,
                    Device = 0,
                    Function = 0
                }
            }
        },
        pcie_card_list = {
            [1] = {
                mds = {
                    DeviceName = 'test'
                }
            }
        }
    }
    local ok = pcall(function()
        c_pcie_device_app:get_device_model(rsp_body,req)
    end)
    lu.assertEquals(ok, true)

    req = {}
    req.Data = '0000:01:00.0'
    req_body = 'test'
    c_pcie_device_app.device_service = {
        pcie_device_list = {}
    }
    ok = pcall(function()
        c_pcie_device_app:get_device_model(rsp_body,req)
    end)
    lu.assertEquals(ok, false)
end

function TestPcieDevice:test_get_device_location_name()
    local req = {}
    req.DeviceType = '0x01'
    req.InfoData = '0000:01:00.0'
    c_pcie_device_app.device_service = {
        pcie_device_list = {}
    }
    c_pcie_device_app.get_npu_device_location = function()
        return false
    end
    local ok = pcall(function()
        c_pcie_device_app:get_device_location_name(req)
    end)
    lu.assertEquals(ok, true)

    req = {}
    req.DeviceType = '0x01'
    req.InfoData = '0000:01:00.0'
    c_pcie_device_app.device_service = {
        pcie_device_list = {
            [1] = {
                mds = {
                    DeviceType = '0x01',
                    Bus = 1,
                    Device = 0,
                    Function = 0
                }
            }
        },
        pcie_card_list = {
            [1] = {
                mds = {
                    DeviceName = 'test'
                }
            }
        }
    }
    c_pcie_device_app.get_npu_device_location = function()
        return false
    end
    local ok = pcall(function()
        c_pcie_device_app:get_device_location_name(req)
    end)
    lu.assertEquals(ok, false)
end