-- 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 skynet = require 'skynet'
local log = require 'mc.logging'
local mdb = require 'mc.mdb'
local file_sec = require 'utils.file'
local ctx = require 'mc.context'
local lu = require 'luaunit'
local mc_context = require 'mc.context'
local base_msg = require 'messages.base'
local custom_msg = require 'messages.custom'

require 'skynet.manager'
require 'power_mgmt.json_types.OnePower'
require 'power_mgmt.json_types.OnePowerMetrics'
require 'power_mgmt.json_types.Temperatures'

POWER_PATH = '/bmc/kepler/Systems/1/PowerMgmt/'
POWER_INTF = 'bmc.kepler.Systems.PowerMgmt.OnePower'
POWER_INTF_METRICS = 'bmc.kepler.Systems.PowerMgmt.OnePower.Metrics'
POWER_INTF_TEMPERATURES = 'bmc.kepler.Systems.PowerMgmt.OnePower.Temperatures'
POWER_INTF_STATUS = 'bmc.kepler.Systems.PowerMgmt.OnePower.Status'
POWER_INTF_BLK_BOX = 'bmc.kepler.Debug.BlackBox'

local test_power_mgmt_rpc = {}

-- test_case1：电源主用模式，设置电源模式为备用成功；
--             电源备用模式，设置电源模式为主用成功

local function test_set_power_work_mode_to_enabled(onepower_obj)
    local ok, rsp = onepower_obj.pcall:SetPowerWorkMode_PACKED(ctx.new(), 0)
    -- 设置成功，返回结果：0
    lu.assertTrue(ok)
    lu.assertEquals(rsp.CmdResult, 0)
    skynet.sleep(2000)
    lu.assertEquals(onepower_obj['WorkMode'], 'Enabled')
end

local function test_set_power_work_mode_to_stand_by_spare(onepower_obj)
    -- 设置单个电源Slot:1, 备用工作模式：1
    local ok, rsp = onepower_obj.pcall:SetPowerWorkMode_PACKED(ctx.new(), 1)
    -- 设置成功，返回结果：0
    lu.assertTrue(ok)
    lu.assertEquals(rsp.CmdResult, 0)
    skynet.sleep(2000)
    lu.assertEquals(onepower_obj['WorkMode'], 'StandbySpare')
end

local function test_set_power_work_mode_case1(bus)
    log:notice('================ test set power work mode case1 start ================')
    local object_name = 'OnePower_0_010109'
    local ok, onepower_obj, rsp
    ok, onepower_obj = pcall(
        mdb.get_object, bus, POWER_PATH .. object_name, POWER_INTF
    )
    lu.assertTrue(ok, true)
    lu.assertEquals(onepower_obj['Manufacturer'], 'HUAWEI')
    lu.assertEquals(onepower_obj['Model'], 'PAC900S12-B2')
    lu.assertEquals(onepower_obj['PartNumber'], '02312XWK')
    lu.assertEquals(onepower_obj['WorkMode'], 'Enabled')
    lu.assertEquals(onepower_obj['Protocol'], 'pmbus')
    lu.assertEquals(onepower_obj['SerialNumber'], '2102312XWK10N8112866')
    -- 1. 电源主用模式，设置电源模式为备用
    test_set_power_work_mode_to_stand_by_spare(onepower_obj)
    -- 2. 电源主用模式，设置电源模式为主用
    test_set_power_work_mode_to_enabled(onepower_obj)
    log:notice('================ test set power work mode case1 end ================')
end
-- test_case2：电源深度休眠模式，设置电源备用成功
--             电源深度休眠模式，设置电源主用成功
local function test_set_power_work_mode_case2(bus)
    log:notice('================ test set power work mode case2 start ================')
    local object_name = 'OnePower_0_010109'
    local ok, onepower_obj, rsp, status_obj
    ok, onepower_obj = pcall(
        mdb.get_object, bus, POWER_PATH .. object_name, POWER_INTF
    )
    lu.assertTrue(ok, true)
    lu.assertEquals(onepower_obj['Manufacturer'], 'HUAWEI')
    lu.assertEquals(onepower_obj['Model'], 'PAC900S12-B2')
    lu.assertEquals(onepower_obj['PartNumber'], '02312XWK')
    lu.assertEquals(onepower_obj['WorkMode'], 'Enabled')
    lu.assertEquals(onepower_obj['Protocol'], 'pmbus')
    lu.assertEquals(onepower_obj['SerialNumber'], '2102312XWK10N8112866')
    -- 1. 设置电源为休眠模式，设置电源备用
    ok, status_obj = pcall(
        mdb.get_object, bus, POWER_PATH .. 'OnePower_0_010109', POWER_INTF_STATUS
    )
    lu.assertTrue(ok, true)
    lu.assertEquals(status_obj['SleepMode'], 'Normal')
    ok, rsp = status_obj.pcall:SetSleepMode(ctx.new(), 'DeepSleep')
    lu.assertTrue(ok)
    lu.assertEquals(rsp, 0)
    skynet.sleep(500)
    lu.assertEquals(status_obj['SleepMode'], 'DeepSleep')
    -- 深度休眠下显示StandbySpare
    lu.assertEquals(onepower_obj['WorkMode'], 'StandbySpare')
    -- 设置电源为备用
    test_set_power_work_mode_to_stand_by_spare(onepower_obj)
    lu.assertEquals(status_obj['SleepMode'], 'Normal')
    -- 2. 设置电源为休眠模式，再设置电源主用
    ok, rsp = status_obj.pcall:SetSleepMode(ctx.new(), 'DeepSleep')
    lu.assertTrue(ok)
    lu.assertEquals(rsp, 0)
    skynet.sleep(500)
    lu.assertEquals(status_obj['SleepMode'], 'DeepSleep')
    -- 深度休眠下显示StandbySpare
    lu.assertEquals(onepower_obj['WorkMode'], 'StandbySpare')
    -- 设置电源为主用
    test_set_power_work_mode_to_enabled(onepower_obj)
    lu.assertEquals(status_obj['SleepMode'], 'Normal')
    log:notice('================ test set power work mode case2 end ================')
end

-- test_case3:设置电源深度休眠：
--            电源备用模式，设置电源深度休眠成功
--            电源主用模式，设置电源深度休眠成功
local function test_set_sleep_mode_case(bus)
    log:notice('================ test set sleep mode case start ================')
    local object_name = 'OnePower_0_010109'
    local ok, onepower_obj, rsp, status_obj
    ok, onepower_obj = pcall(
        mdb.get_object, bus, POWER_PATH .. object_name, POWER_INTF
    )
    lu.assertTrue(ok, true)
    lu.assertEquals(onepower_obj['Manufacturer'], 'HUAWEI')
    lu.assertEquals(onepower_obj['Model'], 'PAC900S12-B2')
    lu.assertEquals(onepower_obj['PartNumber'], '02312XWK')
    lu.assertEquals(onepower_obj['WorkMode'], 'Enabled')
    lu.assertEquals(onepower_obj['Protocol'], 'pmbus')
    lu.assertEquals(onepower_obj['SerialNumber'], '2102312XWK10N8112866')
    -- 1. 电源备用模式，设置电源休眠模式
    test_set_power_work_mode_to_enabled(onepower_obj)
    ok, status_obj = pcall(
        mdb.get_object, bus, POWER_PATH .. 'OnePower_0_010109', POWER_INTF_STATUS
    )
    lu.assertTrue(ok, true)
    ok, rsp = status_obj.pcall:SetSleepMode(ctx.new(), 'DeepSleep')
    lu.assertTrue(ok)
    lu.assertEquals(rsp, 0)
    skynet.sleep(500)
    lu.assertEquals(status_obj['SleepMode'], 'DeepSleep')
    -- 深度休眠下显示StandbySpare
    lu.assertEquals(onepower_obj['WorkMode'], 'StandbySpare')
    -- 2. 电源主用模式，设置电源深度休眠
    test_set_power_work_mode_to_enabled(onepower_obj)
    ok, rsp = status_obj.pcall:SetSleepMode(ctx.new(), 'DeepSleep')
    lu.assertTrue(ok)
    lu.assertEquals(rsp, 0)
    skynet.sleep(500)
    lu.assertEquals(status_obj['SleepMode'], 'DeepSleep')
    -- 深度休眠下显示StandbySpare
    lu.assertEquals(onepower_obj['WorkMode'], 'StandbySpare')
    -- 恢复主用模式，取消深度休眠
    test_set_power_work_mode_to_enabled(onepower_obj)
    lu.assertEquals(status_obj['SleepMode'], 'Normal')
    log:notice('================ test set sleep mode case end ================')
end

local function test_set_sleep_mode_case_1(bus)
    log:notice('================ test set sleep mode case 1 start ================')
    local ok, rsp, status_obj
    ok, status_obj = pcall(
        mdb.get_object, bus, POWER_PATH .. 'OnePower_0_010109', POWER_INTF_STATUS
    )
    lu.assertEquals(ok, true)
    -- 设置电源深度休眠模式为Normal和DeepSleep外的值
    ok, rsp = status_obj.pcall:SetSleepMode(ctx.new(), 'XXX')
    lu.assertEquals(ok, false)
    lu.assertEquals(rsp.name, custom_msg.PropertyValueOutOfRangeMessage.Name)
end

local function test_one_power_metrics_case(bus)
    log:notice('================ test one power metrices case start ================')
    local object_name = 'OnePower_0_010109'
    local ok, onepower_obj = pcall(
        mdb.get_object, bus, POWER_PATH .. object_name, POWER_INTF_METRICS
    )
    lu.assertTrue(ok, true)
    lu.assertEquals(onepower_obj['Rate'], 900)
    lu.assertEquals(onepower_obj['InputVoltage'], 229)
    lu.assertEquals(onepower_obj['OutputVoltage'], 12.31)
    lu.assertEquals(onepower_obj['InputCurrentAmps'], 0.61)
    lu.assertEquals(onepower_obj['OutputCurrentAmps'], 10.5)
    lu.assertEquals(onepower_obj['InputPowerWatts'], 140)
    lu.assertEquals(onepower_obj['OutputPowerWatts'], 129)
    lu.assertEquals(onepower_obj['RatedCurrentAmps'], 0)
    lu.assertEquals(onepower_obj['InputFrequencyHz'], 0)
    log:notice('================ test one power metrices case end ================')
end

local function test_one_power_temperatures_case(bus)
    log:notice('================ test one power temperatures case start ================')
    local object_name = 'OnePower_0_010109'
    local ok, onepower_obj = pcall(
        mdb.get_object, bus, POWER_PATH .. object_name, POWER_INTF_TEMPERATURES
    )
    lu.assertTrue(ok, true)
    lu.assertEquals(onepower_obj['EnvTemperatureCelsius'], 34)
    lu.assertEquals(onepower_obj['InletTemperatureCelsius'], 0)
    lu.assertEquals(onepower_obj['InnerTemperatureCelsius'], 0)
    lu.assertEquals(onepower_obj['PrimaryChipTemperatureCelsius'], 51)
    lu.assertEquals(onepower_obj['SecondaryChipTemperatureCelsius'], 58)
    log:notice('================ test one power temperatures case end ================')
end

local function test_set_power_reset(bus)
    local object_name = 'OnePower_0_010109'
    local _, onepower_obj = pcall(
        mdb.get_object, bus, POWER_PATH .. object_name, POWER_INTF
    )
    local ok, _ = pcall(onepower_obj.Reset_PACKED, onepower_obj, ctx.new(), "ForceRestart")
    lu.assertTrue(ok, true)
    lu.assertErrorMsgContains("ResetOperationNotAllowed", function ()
        onepower_obj:Reset_PACKED(ctx.new(), "ForceOff")
    end)
    lu.assertErrorMsgContains("ActionNotSupported", function ()
        onepower_obj:Reset_PACKED(ctx.new(), "On")
    end)
    lu.assertErrorMsgContains("PropertyValueNotInList", function ()
        onepower_obj:Reset_PACKED(ctx.new(), "ForceOn")
    end)
end

local function test_set_psu_alarm_latch(bus)
    local object_name = 'OnePower_0_010109'
    local _, onepower_obj = pcall(
        mdb.get_object, bus, POWER_PATH .. object_name, POWER_INTF_STATUS
    )
    lu.assertErrorMsgContains("ActionNotSupported", function ()
        onepower_obj:SetAlarmLatch_PACKED(ctx.new(), 0)
    end)
    lu.assertErrorMsgContains("ActionNotSupported", function ()
        onepower_obj:SetAlarmLatch_PACKED(ctx.new(), 1)
    end)
    lu.assertErrorMsgContains("PropertyValueNotInList", function ()
        onepower_obj:SetAlarmLatch_PACKED(ctx.new(), 3)
    end)
end

local function test_set_power_supply_channel(bus)
    local object_name = 'OnePower_0_010109'
    local _, onepower_obj = pcall(
        mdb.get_object, bus, POWER_PATH .. object_name, POWER_INTF
    )
    lu.assertErrorMsgContains("ActionNotSupported", function ()
        onepower_obj:SetPowerSupplyCircuit_PACKED(ctx.new(), 0)
    end)
    lu.assertErrorMsgContains("ActionNotSupported", function ()
        onepower_obj:SetPowerSupplyCircuit_PACKED(ctx.new(), 1)
    end)
    lu.assertErrorMsgContains("PropertyValueNotInList", function ()
        onepower_obj:SetPowerSupplyCircuit_PACKED(ctx.new(), 3)
    end)
end

function test_power_mgmt_rpc.main(bus)
    test_set_power_work_mode_case1(bus)
    test_set_power_work_mode_case2(bus)
    test_set_sleep_mode_case(bus)
    test_set_sleep_mode_case_1(bus)
    test_one_power_metrics_case(bus)
    test_one_power_temperatures_case(bus)
    test_set_power_reset(bus)
    test_set_psu_alarm_latch(bus)
    test_set_power_supply_channel(bus)
end

return test_power_mgmt_rpc