-- 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 device_mgmt = require 'device_mgmt.device_mgmt'
local gpu_mgmt = require 'device_mgmt.gpu_mgmt'
local log = require 'mc.logging'
local org_freedesktop_dbus = require 'sd_bus.org_freedesktop_dbus'
local match_rule = org_freedesktop_dbus.MatchRule
local mdb = require 'mc.mdb'
local comm_fun = require 'device_mgmt.comm_fun'

TestGpuMgmtObj = {}

local mds_obj = {
}

function TestGpuMgmtObj:setupClass()
end

function TestGpuMgmtObj:teardownClass()
end

function TestGpuMgmtObj:test_device_mgmt()
    local gpu_mgmt_bak = gpu_mgmt
    gpu_mgmt.new = function()
        log:raise("gpu init error")
    end
    local ok, ret = pcall(function()
        local device_mgmt = device_mgmt.new({})
    end)
    lu.assertEquals(ok, true)
    lu.assertEquals(ret, nil)

    gpu_mgmt = gpu_mgmt_bak
end

function TestGpuMgmtObj:test_listen_device_obj_property_change()
    local resource_obj = {}
    local msg = {
        read = function()
            return 'bmc.dev.Gpu.Power', {
                PowerWatts = {
                    value = function()
                        return 100
                    end
                },
                PowerBrakeState = {
                    value = function()
                        return 1
                    end
                },
                ExternalPowerSufficient = {
                    value = function()
                        return 0
                    end
                }
            }
        end
    }
    local bus = {
        match = function(self, property_changed_sig, cb)
            cb(msg)
            return 'sig'
        end
    }
    local c_signal = match_rule.signal
    match_rule.signal = function()
        return {
            with_path = function() end
        }
    end
    local sig_slot = {}
    local ok = pcall(gpu_mgmt.listen_device_obj_property_change, gpu_mgmt, bus, 
                    sig_slot, nil, resource_obj)
    match_rule.signal = c_signal
    lu.assertEquals(ok, true)
    lu.assertEquals(sig_slot[1], 'sig')
    lu.assertEquals(resource_obj.PowerWatts, 100)
    lu.assertEquals(resource_obj.PowerBrakeSet, 1)
    lu.assertEquals(resource_obj.ExternalPowerSufficient, 0)
end

function TestGpuMgmtObj:test_synchronize_property()
    local resource_obj = {}
    local bus = {
        call = function(obj, service)
            if service == 'bmc.kepler.maca' then
                return {
                    test_service = {
                        'bmc.dev.Gpu.Power'
                    }
                }
            end
            if service == 'test_service' then
                return {
                    PowerWatts = 0
                }
            end 
        end
    }
    local c_register_interface = mdb.register_interface
    mdb.register_interface = function()
        return true
    end
    local c_get_object = mdb.get_object
    mdb.get_object = function()
        return {
            get_property = function()
                return 0, 100
            end
        }
    end
    local ok = pcall(gpu_mgmt.synchronize_property, gpu_mgmt, bus, nil, resource_obj)
    mdb.register_interface = c_register_interface
    mdb.get_object = c_get_object
    lu.assertEquals(ok, true)
    lu.assertEquals(resource_obj.PowerWatts, 100)
end

function TestGpuMgmtObj:test_sync_dev_prop_to_resource_obj()
    local resource_obj = {}
    local interface = 'bmc.dev.PCIeDevice'
    local prop = 'VendorId'
    local value = '1'
    pcall(gpu_mgmt.sync_dev_prop_to_resource_obj, gpu_mgmt, resource_obj, interface, prop, value)
    prop = 'DeviceId'
    value = '2'
    pcall(gpu_mgmt.sync_dev_prop_to_resource_obj, gpu_mgmt, resource_obj, interface, prop, value)
    prop = 'SubSystemVendorId'
    value = '3'
    pcall(gpu_mgmt.sync_dev_prop_to_resource_obj, gpu_mgmt, resource_obj, interface, prop, value)
    prop = 'SubSystemDeviceId'
    value = '4'
    pcall(gpu_mgmt.sync_dev_prop_to_resource_obj, gpu_mgmt, resource_obj, interface, prop, value)
    prop = 'Slot'
    value = 5
    pcall(gpu_mgmt.sync_dev_prop_to_resource_obj, gpu_mgmt, resource_obj, interface, prop, value)
    lu.assertEquals(resource_obj.VendorID, 1)
    lu.assertEquals(resource_obj.DeviceID, 2)
    lu.assertEquals(resource_obj.SubVendorID, 3)
    lu.assertEquals(resource_obj.SubDeviceID, 4)
    lu.assertEquals(resource_obj.Slot, '5')
end

function TestGpuMgmtObj:test_create_resource_obj()
    local bus = {
        call = function()
            return {
                {
                    'bmc.kepler.maca',
                    'bmc.kepler.general_hardware'
                }
            }
        end
    }
    local c_register_interface = mdb.register_interface
    mdb.register_interface = function()
        return true
    end
    local c_get_object = mdb.get_object
    mdb.get_object = function()
        return {
            get_property = function()
                return 0, 'GPU_1'
            end,
        }
    end
    local obj = {}
    local c_app = gpu_mgmt.app
    gpu_mgmt.app = {
        CreateGPU = function(self, num, obj_name, cb)
            cb(obj)
            return true
        end
    }
    local ok, _, object_position = pcall(gpu_mgmt.create_resource_obj, gpu_mgmt, bus)
    mdb.register_interface = c_register_interface
    mdb.get_object = c_get_object
    gpu_mgmt.app = c_app
    lu.assertEquals(ok, true)
    lu.assertEquals(obj.ObjectName, 'GPU_1')
    lu.assertEquals(object_position, '1')
end

function TestGpuMgmtObj:test_on_del_device_obj()
    local del_signal_bak = comm_fun.set_interface_del_signal
    gpu_mgmt.objects = {}
    comm_fun.set_interface_del_signal = function(_, _, _, _, cb)
        cb('device_path')
    end
    gpu_mgmt:on_del_device_obj()
    gpu_mgmt.objects = {
        device_path = {
            ObjectIdentifier = {1,2,3,4},
            ObjectName = 'ObjectName'
        }
    }
    gpu_mgmt:on_del_device_obj()
    lu.assertEquals(#gpu_mgmt.objects['device_path'], 0)
    comm_fun.set_interface_del_signal = del_signal_bak
end
