-- 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 error_engine = require('error_engine')

local RFERR_INSUFFICIENT_PRIVILEGE = 403
local MFI_STAT_WRONG_STATE = 0x32

local err_ld_map = {
    [RFERR_INSUFFICIENT_PRIVILEGE] = 'PropertyModificationNeedPrivilege',
    [error_engine.SML_ERR_CODE_E.SML_ERR_CTRL_STATUS_INVALID] = 'CurrentStatusNotSupportOperation',
    [error_engine.SML_ERR_CODE_E.SML_ERR_CTRL_INIT_NOT_COMPLETED] = 'CurrentStatusNotSupportOperation',
    [error_engine.SML_ERR_CODE_E.SML_ERR_I2C_READ_WRITE_FAILED] = 'CurrentStatusNotSupportOperation',
    [error_engine.SML_ERR_CODE_E.SML_ERR_CTRL_SET_PROP_UPLEVEL_FUNC_DISABLED] = 'CurrentStatusNotSupportOperation',
    [error_engine.SML_ERR_CODE_E.SML_ERR_CTRL_OPERATION_NOT_SUPPORT] = 'RAIDControllerNotSupported',
    [error_engine.SML_ERR_CODE_E.SML_ERR_LD_INIT_IN_PROGRESS] = 'LDInitInProgress',
    [error_engine.SM_CODE_E.SM_CODE_LD_NAME_EXCEED_MAX_LEN] = 'InvalidVolumeName',
    [error_engine.SML_ERR_CODE_E.SML_ERR_CTRL_BBU_STATUS_ABNORMAL] = 'PropertyModificationNotSupportedByBBUStatus',
    [error_engine.SML_ERR_CODE_E.SML_ERR_CTRL_NO_EDITABLE_LD] = 'CurrentStatusNotSupportOperation',
    [error_engine.SML_ERR_CODE_E.SML_ERR_LD_SIZE_SHRINK_NOT_ALLOWED] = 'VolumeShrinkNotAllowed',
    [error_engine.SML_ERR_CODE_E.SML_ERR_LD_STATE_UNSUPPORTED_TO_SET] = 'OperationFailed',
    [error_engine.SML_ERR_CODE_E.SML_ERR_CONFIG_INVALID_PARAM_RAID_LEVEL] = 'RaidControllerLevelInvalid',
    -- [error_engine.SML_ERR_CODE_E.SML_ERR_CONFIG_INVALID_PARAM_ARRAY_ID] = ('RaidControllerArrayIdInvalid'),
    [error_engine.SML_ERR_CODE_E.SML_ERR_CONFIG_INVALID_PD_NON_SDD_FOR_CACHECADE] = 'NonSSDExist',
    [error_engine.SML_ERR_CODE_E.SML_ERR_CONFIG_ASSOCIATED_LD_SIZE_OUT_OF_RANGE] = 'AssociatedVolumeCapacityOutRange',
    [error_engine.SM_CODE_E.SM_CODE_INVALID_SPAN_DEPTH] = 'NumberOfSpansInvalid',
    [error_engine.SML_ERR_CODE_E.SML_ERR_CONFIG_INVALID_PARAM_CAPACITY_TOO_SMALL] = 'VolumeCapacityOutRange',
    [error_engine.SML_ERR_CODE_E.SML_ERR_CONFIG_INVALID_PARAM_CAPACITY_TOO_LARGE] = 'VolumeCapacityOutRange',
    [error_engine.SML_ERR_CODE_E.SML_ERR_CONFIG_OPERATION_NOT_SUPPORT] = 'OperationNotSupported',
    [error_engine.SM_CODE_E.SM_CODE_NOT_SUPPORT_IN_PRESENT_STATE] = 'CurrentStatusNotSupport',
    [error_engine.SML_ERR_CODE_E.SML_ERR_CONFIG_INVALID_PD_IN_USE] = 'DriveStatusNotSupported',
    [error_engine.SML_ERR_CODE_E.SML_ERR_CONFIG_INVALID_PD_OTHER_ERROR] = 'DriveStatusNotSupported',
    [error_engine.SM_CODE_E.SM_CODE_OPERATION_IN_PROGRESS] = 'OperationInProcess',
    [error_engine.SML_ERR_CODE_E.SML_ERR_CONFIG_INVALID_PD_NON_SUPPORTED] = 'DriveStatusNotSupported',
    [error_engine.SM_CODE_E.SM_CODE_INVALID_PD_ID] = 'PhysicalDiskIdInvalid',
    [error_engine.SM_CODE_E.SM_CODE_INVALID_PD_COUNT] = 'PhysicalDiskIdCountError',
    [error_engine.SM_CODE_E.SM_CODE_INVALID_RAID_LEVEL] = 'RaidControllerLevelInvalid',
    [error_engine.SM_CODE_E.SM_CODE_CAPACITY_OUT_OF_RANGE] = 'VolumeCapacityOutRange',
    [error_engine.SM_CODE_E.SM_CODE_STRIP_SIZE_OUT_OF_RANGE] = 'StripeSizeError',
    [error_engine.SM_CODE_E.SM_CODE_READ_POLCIY_OUT_OF_RANGE] = 'InvalidValue',
    [error_engine.SM_CODE_E.SM_CODE_WRITE_POLICY_OUT_OF_RANGE] = 'InvalidValue',
    [error_engine.SM_CODE_E.SM_CODE_IO_POLICY_OUT_OF_RANGE] = 'InvalidValue',
    [error_engine.SML_ERR_CODE_E.SML_ERR_CONFIG_ARRAY_NO_AVAILABLE_SPACE] = 'ArraySpaceNoFree',
    [error_engine.SM_CODE_E.SM_CODE_PARA_DATA_ILLEGAL] = 'PropertyValueNotInList',
}

local err_ctrl_map = {
    [error_engine.SM_CODE_E.SM_CODE_NOT_SUPPORT_IN_PRESENT_STATE] = 'ModifyfailedWithRAIDCardState',
    [error_engine.SML_ERR_CODE_E.SML_ERR_CTRL_STATUS_INVALID] = 'ModifyfailedWithRAIDCardState',
    [error_engine.SML_ERR_CODE_E.SML_ERR_LD_PROPERTY_SET_NOT_ALLOWED] = 'ModifyfailedWithCachecade',
    [error_engine.SML_ERR_CODE_E.SML_ERR_LD_OPERATION_NOT_SUPPORT] = 'ModifyfailedWithRaidControllerNotSupport',
    [error_engine.SM_CODE_E.SM_CODE_PARA_DATA_ILLEGAL] = 'PropertyValueNotInList',
    [error_engine.SML_ERR_CODE_E.SML_ERR_LD_NO_SSCD_OR_INVALID_NUM_OF_SSCD] = 'NoCachecadeVolume',
    [error_engine.SML_ERR_CODE_E.SML_ERR_LD_PROPERTY_SET_ONLY_DEFAULT_ALLOWED] = 'ModifyfailedWithSSD',
    [error_engine.SML_ERR_CODE_E.SML_ERR_LD_SET_CACHING_ENABLE_FOR_LD_WITH_SSD] = 'ModifyfailedWithSSD',
    [error_engine.SM_CODE_E.SM_CODE_LD_NAME_INVALID_ASCII] = 'InvalidVolumeName',
    [error_engine.SML_ERR_CODE_E.SML_ERR_REBOOT_REQUIRED] = 'RAIDControllerSetSuccessfully',
    [error_engine.SML_ERR_CODE_E.SML_ERR_CONFIG_PRESENT_ERROR] = 'ConfigurationExist',
    [error_engine.SML_ERR_CODE_E.SML_ERR_CTRL_BBU_STATUS_ABNORMAL] = 'PropertyModificationNotSupportedByBBUStatus',
    [error_engine.SML_ERR_CODE_E.SML_ERR_CTRL_NO_EDITABLE_LD] = 'CurrentStatusNotSupportOperation',
    [error_engine.SML_ERR_CODE_E.SML_ERR_CTRL_RCP_NOT_IN_RANGE] = 'ModifyfailedWithRCPNotInRange',
    [error_engine.SM_CODE_E.SM_CODE_UPGRADE_IN_PROGRESS] = 'UpgradingErr',
    [error_engine.SM_CODE_E.SM_CODE_NO_SPACE] = 'InsufficientMemoryErr',
    [error_engine.SM_CODE_E.SM_CODE_OPERATION_IN_PROGRESS] = 'OperationInProcess',
}

local err_drive_map = {
    [error_engine.SM_CODE_E.SM_CODE_NOT_SUPPORT_IN_PRESENT_STATE] = 'PropertyNotSupportedModificationByCurrentStatus',
    [error_engine.SM_CODE_E.SM_CODE_BUSY] = 'LocatedFailedByPDRebuilding',
    [error_engine.SML_ERR_CODE_E.SML_ERR_LD_PROPERTY_SET_NOT_ALLOWED] = 'ModifyfailedWithCachecade',
    [error_engine.SML_ERR_CODE_E.SML_ERR_LD_OPERATION_NOT_SUPPORT] = 'ModifyfailedWithRaidControllerNotSupport',
    [error_engine.SM_CODE_E.SM_CODE_PARA_DATA_ILLEGAL] = 'PropertyValueNotInList',
    [error_engine.SML_ERR_CODE_E.SML_ERR_LD_NO_SSCD_OR_INVALID_NUM_OF_SSCD] = 'NoCachecadeVolume',
    [error_engine.SML_ERR_CODE_E.SML_ERR_LD_PROPERTY_SET_ONLY_DEFAULT_ALLOWED] = 'ModifyfailedWithSSD',
    [error_engine.SML_ERR_CODE_E.SML_ERR_LD_SET_CACHING_ENABLE_FOR_LD_WITH_SSD] = 'ModifyfailedWithSSD',
    [error_engine.SM_CODE_E.SM_CODE_LD_NAME_INVALID_ASCII] = 'InvalidVolumeName',
    [error_engine.SML_ERR_CODE_E.SML_ERR_PD_MAKESPARE_NOT_ALLOWED] = 'PropertyModificationNotSupportedByPDStatus',
    [error_engine.SML_ERR_CODE_E.SML_ERR_PD_SPARE_FOR_RAID0_LD] = 'PropertyModificationFailedByRAIDlevelNotSupported',
    [MFI_STAT_WRONG_STATE] = 'PropertyModificationNotSupportedByPDStatus',
    [error_engine.SML_ERR_CODE_E.SML_ERR_PD_SPARE_SDD_HDD_MIXED] = 'PropertyModificationFailedByMediaTypeConflict',
    [error_engine.SML_ERR_CODE_E.SML_ERR_CONFIG_ASSOCIATED_LD_SIZE_OUT_OF_RANGE] = 'AssociatedVolumeCapacityOutRange',
    [error_engine.SM_CODE_E.SM_CODE_OPERATION_IN_PROGRESS] = 'OperationInProcess',
}

TestErrorEngine = {}

function TestErrorEngine:setupClass() end

function TestErrorEngine:teardownClass() end

function TestErrorEngine.test_controller_error_engine_proc()
    local ok, ret
    for err_code, message_name in pairs(err_ctrl_map) do
        ok, ret = pcall(error_engine.raise_controller_error, err_code, message_name, 'prop_value')
        lu.assertEquals(ok, false)
    end
end

function TestErrorEngine.test_drive_error_engine_proc()
    local ok, ret
    for err_code, message_name in pairs(err_drive_map) do
        ok, ret = pcall(error_engine.raise_controller_error, err_code, message_name, 'prop_value')
        lu.assertEquals(ok, false)
    end
end

function TestErrorEngine.test_volume_error_engine_proc()
    local ok, ret
    for err_code, message_name in pairs(err_ld_map) do
        ok, ret = pcall(error_engine.raise_controller_error, err_code, message_name, 'prop_value')
        lu.assertEquals(ok, false)
    end
end

function TestErrorEngine.test_raise_error_unknown_code()
    local ok = pcall(error_engine.raise_controller_error, nil, 0xFFFF)
    lu.assertEquals(ok, false)
end

function TestErrorEngine.test_raise_error_with_ipmi_ctx()
    local ipmi_ctx = { netfn = 0x30 }
    local ok = pcall(error_engine.raise_controller_error, ipmi_ctx, 0xFFFF)
    lu.assertEquals(ok, false)
end

-- Cover get_controller_error_message (line 161: SML_ERR_PD_CLEAR_IN_PROGRESS)
function TestErrorEngine.test_get_controller_error_message_pd_clear()
    local msg, params = error_engine.get_controller_error_message(
        error_engine.SML_ERR_CODE_E.SML_ERR_PD_CLEAR_IN_PROGRESS,
        'prop_name',
        'prop_val'
    )
    lu.assertEquals(msg, 'DriveStatusNotSupported')
    lu.assertNotNil(params)
end

-- Cover get_drive_error_param (lines 331-348, 353, 356) via raise_drive_error
function TestErrorEngine.test_raise_drive_error_proc()
    local drive_err_codes = {
        error_engine.SML_ERR_CODE_E.SML_ERR_CTRL_OPERATION_NOT_SUPPORT,
        error_engine.SML_ERR_CODE_E.SML_ERR_PD_INVALID_DEVICE_ID,
        error_engine.SM_CODE_E.SM_CODE_BUSY,
        error_engine.SM_CODE_E.SM_CODE_PARA_DATA_ILLEGAL,
        error_engine.SM_CODE_E.SM_CODE_PD_NOT_IDENTIFIED,
        error_engine.SM_CODE_E.SM_CODE_NOT_SUPPORT_IN_PRESENT_STATE,
        error_engine.SM_CODE_E.SM_CODE_GET_PD_LIST_FAILED,
        error_engine.SML_ERR_CODE_E.SML_ERR_PD_MAX_UNCONFIGURED,
        error_engine.SML_ERR_CODE_E.SML_ERR_I2C_READ_WRITE_FAILED,
        error_engine.SML_ERR_CODE_E.SML_ERR_PD_MAKESPARE_NOT_ALLOWED,
        error_engine.SML_ERR_CODE_E.SML_ERR_INVALID_PARAMETER,
        error_engine.SML_ERR_CODE_E.SML_ERR_INVALID_CMD,
        error_engine.SML_ERR_CODE_E.SML_ERR_PD_STATE_UNSUPPORTED_TO_SET,
        error_engine.SML_ERR_CODE_E.SML_ERR_CONFIG_RESOURCE_CONFLICT,
        error_engine.SML_ERR_CODE_E.SML_ERR_PD_SPARE_FOR_RAID0_LD,
        error_engine.SML_ERR_CODE_E.SML_ERR_PD_SPARE_SDD_SAS_SATA_MIXED,
        error_engine.SML_ERR_CODE_E.SML_ERR_PD_SPARE_SDD_HDD_MIXED,
        error_engine.SML_ERR_CODE_E.SML_ERR_PD_OPERATION_NOT_SUPPORT,
        error_engine.SM_CODE_E.SM_CODE_OPERATION_IN_PROGRESS,
    }
    for _, err_code in ipairs(drive_err_codes) do
        local ok = pcall(error_engine.raise_drive_error, nil, err_code, 'prop_name', 'prop_val')
        lu.assertEquals(ok, false)
    end
end

-- Cover raise_drive_error with IPMI ctx (line 437)
function TestErrorEngine.test_raise_drive_error_with_ipmi_ctx()
    local ipmi_ctx = { netfn = 0x30 }
    local ok =
        pcall(error_engine.raise_drive_error, ipmi_ctx, error_engine.SM_CODE_E.SM_CODE_BUSY, 'prop_name', 'prop_val')
    lu.assertEquals(ok, false)
end

-- Cover raise_volume_error with IPMI ctx (line 446)
function TestErrorEngine.test_raise_volume_error_with_ipmi_ctx()
    local ipmi_ctx = { netfn = 0x30 }
    local ok = pcall(
        error_engine.raise_volume_error,
        ipmi_ctx,
        error_engine.SML_ERR_CODE_E.SML_ERR_LD_INVALID_TARGET_ID,
        'prop_name',
        'prop_val'
    )
    lu.assertEquals(ok, false)
end