-- 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 log = require 'mc.logging'
local hdk_cmd = require 'npu.hdk_cmd'
local ipmi = require 'ipmi'
local comp_code = ipmi.types.Cc
local c_object_manage = require 'mc.orm.object_manage'
local bs = require 'mc.bitstring'
local network_port = require 'device.class.network_port'
local optical_module = require 'device.class.optical_module'
local fructl = require 'infrastructure.fructl'
local log_collection = require 'device.class.log_collector'
local vos = require 'utils.vos'
local utils = require 'mc.utils'
local lu = require 'luaunit'
local file_sec = require "utils.file"

local HEARTBEAT_LOSS<const> = 0xc3

Testlog = {}

local op_runtime_info_rsp = bs.new([[<<
    error_code:1/unit:8,
    opcode:2/little-unit:8,
    total_length:4/little-unit:8,
    length:4/little-unit:8,
    cmd_version:1/unit:8,

    # support_info 有7个字节,每个bit代表接下来结构体中对应顺序的属性是否支持
    runtime_supported:1,
    poweron_time_supported:1,
    poweron_count_supported:1,
    power_status_supported:1,
    odsp_temp_supported:1,
    odsp_high_heat_time_supported:1,
    laser_run_time_supported:1,
    laser_temp_supported:1,
    laser_core_temp_supported:1,
    reserved:47,

    runtime:4/little-unit:8,
    poweron_time:4/little-unit:8,
    poweron_count:2/little-unit:8,
    power_status:2/little-unit:8,
    odsp_temp:2/little-unit:8,
    odsp_high_heat_time:4/little-unit:8,
    laser_run_time:4/little-unit:8,
    laser_temp:2/little-unit:8,
    laser_core_temp:2/little-unit:8,
    tail/string
>>]])

local op_base_rsp = bs.new([[<<
    head:3/unit:8,
    total_length:4/little-unit:8,
    length:4/little-unit:8,
    vendor_name:32/string,
    serial_number:32/string,
    part_number:32/string,
    manufacture_date:32/string,
    transceiver_type:1/little-unit:8,
    tail/binary
    >>]])

local mock_resp = {
    error_code = 0,
    opcode = 0,
    total_length = 0,
    length = 0,
    cmd_version = 0,
    runtime_supported = 1,
    poweron_time_supported = 1,
    poweron_count_supported = 1,
    power_status_supported = 1,
    odsp_temp_supported = 1,
    odsp_high_heat_time_supported = 1,
    laser_run_time_supported = 1,
    laser_temp_supported = 1,
    laser_core_temp_supported = 1,
    reserved = 1,
    runtime = 4,
    poweron_time = 4,
    poweron_count = 2,
    power_status = 2,
    odsp_temp = 2,
    odsp_high_heat_time = 4,
    laser_run_time = 4,
    laser_temp = 2,
    laser_core_temp = 0,
    tail =""
}

local mock_resp_op_base_rsp = {
    head = 0,
    total_length= 0,
    length = 0,
    vendor_name = "",
    serial_number = "",
    part_number = "",
    manufacture_date = "",
    transceiver_type = 0,
    tail = ""
}

local get_instance = c_object_manage.get_instance
local getLevel = log.getLevel
local request = ipmi.request
local is_npu_heartbeat_loss = network_port.is_npu_heartbeat_loss
local get_npu_cdr_temp_from_imu = hdk_cmd.get_npu_cdr_temp_from_imu
local is_first_get_info_from_imu = optical_module.is_first_get_info_from_imu
local is_npu_heartbeat_loss_optical = optical_module.is_npu_heartbeat_loss
local check_info_from_imu = optical_module.check_info_from_imu
local reset_npu_om = optical_module.reset_npu_om
local get_power_status = fructl.get_power_status
local init_npu_optical_module_info = optical_module.init_npu_optical_module_info
local get_optical_thresholds = hdk_cmd.get_optical_thresholds
local sfp_read_eeprom_offset = optical_module.sfp_read_eeprom_offset

local data = op_runtime_info_rsp:pack(mock_resp)
local data_op_base = op_base_rsp:pack(mock_resp_op_base_rsp)

function Testlog:setUp()
    self.original_getLevel = log.getLevel
    self.ipmi = ipmi
    c_object_manage.get_instance = function ()
        return {
            bus = 1
        }
    end
    log.getLevel = function ()
        return log.DEBUG
    end
    ipmi.request = function (...)
        return comp_code.Success, data
    end
    hdk_cmd.get_npu_cdr_temp_from_imu = function ()
        error()
    end
end

function Testlog:teardown()
    c_object_manage.get_instance = get_instance
    log.getLevel = getLevel
    ipmi.request = request
    network_port.is_npu_heartbeat_loss = is_npu_heartbeat_loss
    hdk_cmd.get_npu_cdr_temp_from_imu = get_npu_cdr_temp_from_imu
    optical_module.is_first_get_info_from_imu = is_first_get_info_from_imu
    optical_module.is_npu_heartbeat_loss = is_npu_heartbeat_loss_optical
    optical_module.check_info_from_imu = check_info_from_imu
    optical_module.reset_npu_om = reset_npu_om
    fructl.get_power_status = get_power_status
    optical_module.init_npu_optical_module_info = init_npu_optical_module_info
    hdk_cmd.get_optical_thresholds = get_optical_thresholds
    optical_module.sfp_read_eeprom_offset = sfp_read_eeprom_offset
end


function Testlog:test_get_op_runtime_info()
    hdk_cmd.get_op_runtime_info(1)
    ipmi.request = function (...)
        return comp_code.DataNotAvailable, data
    end
    hdk_cmd.get_op_runtime_info(2)
end

function Testlog:test_get_op_alarm_info()
    hdk_cmd.get_op_alarm_info(1)
    ipmi.request = function (...)
        return comp_code.DataNotAvailable, data
    end
    hdk_cmd.get_op_alarm_info(2)
end

function Testlog:test_heartbeat_check()
    ipmi.request = function (...)
        return HEARTBEAT_LOSS
    end
    hdk_cmd.heartbeat_check(1)
end

function Testlog:test_get_op_base_info()
    ipmi.request = function (...)
        return comp_code.Success, data_op_base
    end
    hdk_cmd.mock_get_op_base_info(1)
end

function Testlog:test_get_npu_cdr_temp_from_imu()
    local fun = fructl.get_power_status
    fructl.get_power_status = function ()
        return 'ON'
    end
    local c_get_parent = network_port.get_parent
    network_port.get_parent = function()
        return {
            Model = ''
        }
    end
    network_port.is_npu_heartbeat_loss = true
    network_port.get_npu_cdr_temp_from_imu(network_port)
    network_port.is_npu_heartbeat_loss = false
    network_port.get_npu_cdr_temp_from_imu(network_port)
    fructl.get_power_status = fun
    network_port.get_parent = c_get_parent
end

local parent = {
    PowerOn = 2
}
function Testlog:test_check_info_from_imu()
    optical_module.is_npu_heartbeat_loss = false
    optical_module.check_info_from_imu(optical_module,1, parent)
    parent = {
        PowerOn = 1
    }
    fructl.get_power_status = function ()
        return 'ON'
    end
    optical_module.is_npu_heartbeat_loss = true
    optical_module.check_info_from_imu(optical_module,1, parent)
    optical_module.init_npu_optical_module_info = function ()
        error()
    end
    optical_module.is_npu_heartbeat_loss = false
    optical_module.check_info_from_imu(optical_module,1, parent)
end

function Testlog:test_check_update_thresholds()
    hdk_cmd.get_optical_thresholds = function ()
        error()
    end
    local c_get_parent = optical_module.get_parent
    optical_module.get_parent = function()
        return {
            get_parent = function()
                return {Model = ''}
            end
        }
    end
    optical_module:check_update_thresholds()
    optical_module.get_parent = c_get_parent
end

function Testlog:test_get_optical_module_asset()
    local offset = {
        offset = 1,
        length = 1
    }
    optical_module.sfp_read_eeprom_offset = function ()
        return false, false
    end
    optical_module.get_optical_module_asset(optical_module, offset)
end

function Testlog:test_get_optical_module_diagnostic()
    local offset = {
        offset = 1,
        length = 1
    }
    optical_module.sfp_read_eeprom_offset = function ()
        return false, false
    end
    optical_module.get_optical_module_diagnostic(optical_module, offset)
end

function Testlog:test_get_op_status_info()
    ipmi.request = function (...)
        return comp_code.DataNotAvailable
    end
    hdk_cmd.mock_get_op_status_info(1)
end

function Testlog:test_network_adapter_collect_optical_static_info_log()
    local check_func = file_sec.check_realpath_before_open_s
    log_collection.dump_string_to_log("/var/log/optical_module", "optical_module_static_info", "aaa")
    lu.assertEquals(vos.get_file_accessible('/var/log/optical_module/optical_module_static_info'), true)
    utils.remove_file("/var/log/optical_module")
    file_sec.check_realpath_before_open_s = function (...)
        return false
    end
    log_collection.dump_string_to_log("/var/log/optical_module", "optical_module_static_info", "aaa")
    lu.assertEquals(vos.get_file_accessible('/var/log/optical_module/optical_module_static_info'), true)
    file_sec.check_realpath_before_open_s = check_func
    local open_func = file_sec.open_s
    file_sec.open_s = function (...)
        return false
    end
    log_collection.dump_string_to_log("/var/log/optical_module", "optical_module_static_info", "aaa")
    lu.assertEquals(vos.get_file_accessible('/var/log/optical_module/optical_module_static_info'), true)
    file_sec.open_s = open_func
end
