-- 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 c_fan_object = require 'fan_object'
local c_fan_type_object = require 'fan_type_object'
local c_object_manage = require 'mc.orm.object_manage'
local c_tasks = require 'mc.orm.tasks'
local thermal_db = require 'thermal_mgmt.db'
local hook_tasks = require 'test_common.hook_tasks'
local test_utils = require 'test_utils'

TestThermal = {}

function TestThermal:flush()
    c_tasks.get_instance():run_all_task()
    self.database.db:flush()
end

-- 框架收到自发现分发的对象后，在回调 on_add_object 函数前会装载持久化数据回对象
-- 多风扇板场景仅ObjectName能承载唯一性主键，在此时填充主键
c_fan_object.before_add_object = function(object)
    object.FanObjectName = object.ObjectName
end

local fan_obj = {
    FanId = 1,
    Slot = 1,
    Type = 0,
    Model = "32030389-004 8080+",
    Coefficient = 1,
    FanHealth = 0,
    FanEntity = "",
    FrontPresence = 1,
    RearPresence = 1,
    FrontSpeed = 5376,
    RearSpeed = 5120,
    FrontStatus = 0,
    RearStatus = 0,
    FrontRPM = 0,
    RearRPM = 0,
    HardwarePWM = 81,
    PWMPercentage = 0,
    ExpectedPWM = 81,
    FanAlarmLed = 0,
    BOM = "BOM 32030389-004",
    SystemId = 1,
    MaxSupportedPWM = 255,
    IdentifySpeedLevel = 30,
    PartNumber = "32030389-004",
    FrontMaxSpeed = 16500,
    RearMaxSpeed = 16500,
    IsTwins = true,
    FanPosition = 'CLU',
    SpeedStable = true,
    FunctionDesc = "",
    DeviceName = "",
    SetFanPWM = function ()
        return 1
    end,
        GetData = function ()
        
        end,
        GetItems = function ()
            
        end,
        SynDataAcquisitionEnable = function ()
            
        end,
    Position = '010107',
    ObjectName = "Fan",
    ObjectIdentifier = {},
    PowerGood = 1,
    DualConnector = {},
    SingleConnector = {},
    __position = "010107",
    IdentifyStatus = 0
}

local fan_type  = {
    Name = "02314QEB 4056+",
    FanTypeObjectName = "FanType_4056P_010107",
    Index = 1,
    IsDefaultType = true,
    IsTwins = true,
    FrontMaxSpeed = 16500,
    RearMaxSpeed = 16500,
    PartNumber = "32030389-004",
    BOM = "BOM 32030389-004",
    SystemId = 1,
    IdentifyRangeLo = 4207,
    IdentifyRangeHigh = 5692,
    __position = "010107"
}

function TestThermal:setUp()
    self.database = thermal_db(':memory:')

    hook_tasks.hook()
    self.object_manage = c_object_manage.new(self.database)
    self.object_manage.app = self

    local fan_type_obj = test_utils.add_fan_type_obj(self.object_manage, 'FanType_1', fan_type)
    local obj = test_utils.add_fan_obj(self.object_manage, 'Fan_1', fan_obj)
    self.object_manage.mc:before_add_object(c_fan_object.__class_name, obj)
    self.object_manage.mc:add_object(c_fan_object.__class_name, obj, '010107')
    self.object_manage.mc:before_add_object(c_fan_type_object.__class_name, fan_type_obj)
    self.object_manage.mc:add_object(c_fan_type_object.__class_name, fan_type_obj, '010107')
    self.object_manage.mc:prepare_ok()
    self:flush()
end

function TestThermal:tearDown()
    c_object_manage.destroy()
    self.database.db:close()
    hook_tasks.unhook()
end

function TestThermal:test_ctor_init()
    local obj = c_fan_object.collection:find({
        FanId = 1
    })
    lu.assertEquals(obj.change_times, 0)
    lu.assertEquals(obj.last_pwm, 0)
    lu.assertEquals(obj.default_model, false)
    lu.assertEquals(obj.last_present, false)
    lu.assertEquals(obj.model_source, 0)
    lu.assertEquals(obj.fan_model, false)
    lu.assertEquals(obj.mcu_upgrading, false)
    lu.assertEquals(obj.start_flag, false)
    lu.assertEquals(obj.fan_board, false)
    lu.assertEquals(obj.standbyfan, false)
    lu.assertEquals(obj.dual_connector, false)
    lu.assertEquals(obj.single_connector, false)
    lu.assertEquals(obj.persist_fan_id, 1)
    lu.assertEquals(obj.ExpectedPWM, 81)
end

function TestThermal:test_get_or_set_status_error()
    local obj = c_fan_object.collection:find({
        FanId = 1
    })
    lu.assertEquals(obj:get_status_error('front'), 0)
    lu.assertEquals(obj:get_status_error('rear'), 0)
    lu.assertEquals(obj.FrontStatus, 0)
    lu.assertEquals(obj.RearStatus, 0)

    obj:set_status_error('front', 1)
    lu.assertEquals(obj:get_status_error('front'), 1)
    lu.assertEquals(obj.FrontStatus, 2)

    obj:set_status_error('rear', -1)
    lu.assertEquals(obj:get_status_error('rear'), -1)
    lu.assertEquals(obj.RearStatus, 0)
end

function TestThermal:test_is_present()
    local obj = c_fan_object.collection:find({
        FanId = 1
    })
    lu.assertEquals(obj:is_present(), true)
end

function TestThermal:test_is_independence()
    local obj = c_fan_object.collection:find({
        FanId = 1
    })
    lu.assertEquals(obj:is_independence(), false)

    obj.FrontPresence = 0
    lu.assertEquals(obj:is_independence(), true)
end

function TestThermal:test_set_expected_pwm()
    local obj = c_fan_object.collection:find({
        FanId = 1
    })
    obj:set_expected_pwm(100.99)
    lu.assertEquals(obj.ExpectedPWM, 100)
end

function TestThermal:test_get_max_supported_pwm()
    local obj = c_fan_object.collection:find({
        FanId = 1
    })
    lu.assertEquals(obj:get_max_supported_pwm(), 255)

    obj.MaxSupportedPWM = 0
    lu.assertEquals(obj:get_max_supported_pwm(), 1000)

    obj.MaxSupportedPWM = nil
    lu.assertEquals(obj:get_max_supported_pwm(), 1000)
end

function TestThermal:test_get_or_set_error_count()
    local obj = c_fan_object.collection:find({
        FanId = 1
    })
    lu.assertEquals(obj:get_error_count('front'), 0)
    lu.assertEquals(obj:get_error_count('rear'), 0)

    obj:set_error_count('front', 1)
    lu.assertEquals(obj:get_error_count('front'), 1)

    obj:set_error_count('rear', -1)
    lu.assertEquals(obj:get_error_count('rear'), -1)
end

function TestThermal:test_change_times_add_once()
    local obj = c_fan_object.collection:find({
        FanId = 1
    })
    lu.assertEquals(obj.change_times, 0)
    obj:change_times_add_once()
    lu.assertEquals(obj.change_times, 1)
end

function TestThermal:test_is_identified()
    local obj = c_fan_object.collection:find({
        FanId = 1
    })
    obj.IdentifyStatus = 0
    lu.assertEquals(obj:is_identified(), false)

    obj.IdentifyStatus = 2
    lu.assertEquals(obj:is_identified(), true)
end

function TestThermal:test_update_fan_info()
    local obj = c_fan_object.collection:find({
        FanId = 1
    })
    local fan_type = {
        get_fan_type_name = function ()
            return  "02314QEB 4056+"
        end,
        get_type_part_num = function ()
            return  "02314QEB"
        end,
        get_type_bom_id = function ()
            return  "BOM 32030300-005"
        end,
        get_is_twins = function ()
            return  true
        end,
        get_front_max_speed = function ()
            return  23000
        end,
        get_rear_max_speed = function ()
            return  22760
        end,
    }

    obj:update_fan_info(fan_type)
    lu.assertEquals(obj.Model, "02314QEB 4056+")
    lu.assertEquals(obj.PartNumber, "02314QEB")
    lu.assertEquals(obj.BOM, "BOM 32030300-005")
    lu.assertEquals(obj.IsTwins, true)
    lu.assertEquals(obj.FrontMaxSpeed, 23000)
    lu.assertEquals(obj.RearMaxSpeed, 22760)
end

function TestThermal:test_set_mismatch()
    local obj = c_fan_object.collection:find({
        FanId = 1
    })
    obj.IdentifyStatus = 2
    obj:set_mismatch()
    lu.assertEquals(obj.status_error.front_error, 8)
    lu.assertEquals(obj.status_error.rear_error, 8)
end

function TestThermal:test_clear_mismatch()
    local obj = c_fan_object.collection:find({
        FanId = 1
    })
    obj.IdentifyStatus = 2
    obj:clear_mismatch()
    lu.assertEquals(obj.status_error.front_error, 0)
    lu.assertEquals(obj.status_error.rear_error, 0)
end

function TestThermal:test_recover_info_from_db()
    local obj = c_fan_object.collection:find({
        FanId = 1
    })
    local db_obj = {
        Type = 1,
        Model = "32030389-004 8080+",
        PartNumber = "32030389-004",
        BOM = "BOM 32030389-004",
        IsTwins = true,
        FrontMaxSpeed = 16500,
        RearMaxSpeed = 16500
    }
    obj:recover_info_from_db(db_obj)
    lu.assertEquals(obj.Type, 1)
    lu.assertEquals(obj.Model, "32030389-004 8080+")
    lu.assertEquals(obj.PartNumber, "32030389-004")
    lu.assertEquals(obj.BOM, "BOM 32030389-004")
    lu.assertEquals(obj.IsTwins, true)
    lu.assertEquals(obj.FrontMaxSpeed, 16500)
    lu.assertEquals(obj.RearMaxSpeed, 16500)
    lu.assertEquals(obj.model_source, 1)
end

function TestThermal:test_clear_fan_info()
    local obj = c_fan_object.collection:find({
        FanId = 1
    })
    obj:clear_fan_info()
    lu.assertEquals(obj.status_record.front_error_count, 0)
    lu.assertEquals(obj.status_record.rear_error_count, 0)
    lu.assertEquals(obj.change_times, 0)
    lu.assertEquals(obj.FrontRPM, 0)
    lu.assertEquals(obj.RearRPM, 0)
    lu.assertEquals(obj.FrontStatus, 0)
    lu.assertEquals(obj.RearStatus, 0)
    lu.assertEquals(obj.Model, '')
    lu.assertEquals(obj.PartNumber, '')
    lu.assertEquals(obj.SpeedStable, false)
    lu.assertEquals(obj.default_model, false)
    lu.assertEquals(obj.last_present, true)
    lu.assertEquals(obj.IdentifyStatus, 0)
    lu.assertEquals(obj.status_error.front_error, 0)
    lu.assertEquals(obj.status_error.rear_error, 0)
    lu.assertEquals(obj.model_source, 0)
end

function TestThermal:test_clear_fan_status()
    local obj = c_fan_object.collection:find({
        FanId = 1
    })
    obj:clear_fan_status()
    lu.assertEquals(obj.status_error.front_error, 0)
    lu.assertEquals(obj.status_error.rear_error, 0)
end

function TestThermal:test_check_speed_change_for_status()
    local obj = c_fan_object.collection:find({
        FanId = 1
    })
    obj.change_times = 0
    obj.ExpectedPWM = 81
    obj.last_pwm = 60
    for _ = 1, 5 do
        obj:check_speed_change_for_status()
    end
    lu.assertEquals(obj.change_times, 5)
end