-- 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 json = require 'cjson'
local test_data = require 'test_bma.bma_data'
local def = require 'common_def'
local hook_tasks = require 'hook_tasks'
local drive_collection = require 'drive.drive_collection'
local object_manager = require 'object_manager'
local c_handler_drives =  require 'bma.handles.handler_pass_through_drive'
local bus_monitor_service = require 'bus_monitor_service'
local test_common = require 'test_common.utils'
local sml = require 'sml'

Test_Bma_Eth = {}

local function create_drive(self)
    local drive_info = { HddBackplaneStartSlot = 0, Presence = 1, RelativeSlot = 1, ObjectName = 'Drive1' }
    self.object_manager.mc:add_object('Drive', drive_info)
    self.bus_monitor_service.on_os_state_changed:emit(true)
    local drive = self.drive_collection:get_drive(drive_info.Name)

    return drive_info, drive
end

function Test_Bma_Eth:setup()
    self.bus = test_common.dbus_launch('../.dbus', nil, true)
    self.drive_collection = drive_collection.new()
    self.object_manager = object_manager.new(self.bus)

    local smart_data = json.decode(test_data.DriveDataFromBma)
    self.bus_monitor_service = bus_monitor_service.new(self.bus)
    self.c_handler_drives = c_handler_drives.new()

    self.drive_url = smart_data['@odata.id']
end

function Test_Bma_Eth:test_handler_pass_through_drive_object()
    local _, drive = create_drive(self)

    local data = json.decode(test_data.DriveDataFromBma)
    local huawei = data.Oem.Huawei

    c_handler_drives = self.c_handler_drives

    local ret = pcall(c_handler_drives.update_drive_info, c_handler_drives, drive, data)
    lu.assertEquals(ret, true)
    lu.assertEquals(drive.PredictedMediaLifeLeftPercent, 99)
    lu.assertEquals(drive.estimated_remaining_lifespan_info.media_type, data.MediaType)
    lu.assertEquals(drive.estimated_remaining_lifespan_info.manufacturer, data.Manufacturer)
    lu.assertEquals(drive.estimated_remaining_lifespan_info.serial_number, data.SerialNumber)
    lu.assertEquals(drive.estimated_remaining_lifespan_info.protocol, def.DRIVE_PROTOCOL.SATA)
    lu.assertEquals(drive.estimated_remaining_lifespan_info.remn_wearout, 99)
    lu.assertEquals(drive.estimated_remaining_lifespan_info.power_on_hours, huawei.PowerOnHours)
    lu.assertEquals(drive.write_amplification_info.vendor_nand_write, 38218688)
    lu.assertEquals(drive.write_amplification_info.vendor_host_write, 34015972)
    lu.assertEquals(drive.write_amplification_info.update_support_flag, 1)
    lu.assertEquals(drive.write_amplification_info.vendor_valid_flag, 1)
    lu.assertEquals(drive.write_amplification_info.first_start_flag, 1)
    lu.assertEquals(drive.Revision, huawei.FirmwareVersion)
    lu.assertEquals(drive.TemperatureCelsius, huawei.Temperature)
    lu.assertEquals(drive.PowerOnHours, huawei.PowerOnHours)
    lu.assertEquals(drive.PowerState, huawei.PowerState)
    lu.assertEquals(drive.Manufacturer, data.Manufacturer)
    lu.assertEquals(drive.Model, data.Model)
    lu.assertEquals(drive.SerialNumber, data.SerialNumber)
    lu.assertEquals(drive.FirmwareStatus, 13)
end

function Test_Bma_Eth:test_bma_reset()
    local _, drive = create_drive(self)
    local data = json.decode(test_data.DriveDataFromBma)
    c_handler_drives = self.c_handler_drives
    local ret = pcall(c_handler_drives.update_drive_info, c_handler_drives, drive, data)
    lu.assertEquals(ret, true)
    ret = pcall(c_handler_drives.reset_drive, c_handler_drives, drive)
    lu.assertEquals(ret, true)

    lu.assertEquals(drive.PredictedMediaLifeLeftPercent, def.INVALID_U8)
    lu.assertEquals(drive.estimated_remaining_lifespan_info.drive_name, '')
    lu.assertEquals(drive.estimated_remaining_lifespan_info.media_type, '')
    lu.assertEquals(drive.estimated_remaining_lifespan_info.manufacturer, '')
    lu.assertEquals(drive.estimated_remaining_lifespan_info.serial_number, '')
    lu.assertEquals(drive.estimated_remaining_lifespan_info.protocol, def.INVALID_U8)
    lu.assertEquals(drive.estimated_remaining_lifespan_info.ref_controller_id, def.INVALID_U8)
    lu.assertEquals(drive.estimated_remaining_lifespan_info.remn_wearout, def.INVALID_U8)
    lu.assertEquals(drive.estimated_remaining_lifespan_info.power_on_hours, def.INVALID_U32)
    lu.assertEquals(drive.write_amplification_info.vendor_nand_write, def.STORAGE_INFO_INVALID_DWORD)
    lu.assertEquals(drive.write_amplification_info.vendor_host_write, def.STORAGE_INFO_INVALID_DWORD)
    lu.assertEquals(drive.write_amplification_info.update_support_flag, 0)
    lu.assertEquals(drive.write_amplification_info.vendor_valid_flag, 0)
    lu.assertEquals(drive.write_amplification_info.first_start_flag, 1)
    lu.assertEquals(drive.est_lifespan_last_up_time, 0)
end

function Test_Bma_Eth:test_dump_write_amp()
    local _, drive = create_drive(self)
    local data = json.decode(test_data.DriveDataFromBma)

    c_handler_drives = self.c_handler_drives

    local ret = pcall(c_handler_drives.start_dump_task, c_handler_drives, drive, data)
    lu.assertEquals(ret, true)
    lu.assertEquals(drive.write_amplification_info.first_start_flag, 1)
    lu.assertEquals(drive.write_amplification_info.last_nand_written, def.STORAGE_INFO_INVALID_DWORD)
    lu.assertEquals(drive.write_amplification_info.last_host_written, def.STORAGE_INFO_INVALID_DWORD)
    lu.assertEquals(drive.write_amplification_info.last_serial_number, 'N/A')

    ret = pcall(c_handler_drives.stop_dump_task, c_handler_drives, drive)
    lu.assertEquals(ret, true)

    data.HuaweiDefinedSMARTSupported = true
    ret = pcall(c_handler_drives.start_dump_task, c_handler_drives, drive, data)
    lu.assertEquals(ret, true)

    drive.SerialNumber = 'KS98Q6490I0108S6D'
    ret = pcall(drive.record_write_amp_log, drive)
    lu.assertEquals(ret, true)
end

function Test_Bma_Eth:test_update_drive_info()
    local _, drive = create_drive(self)
    local data = json.decode(test_data.DriveDataFromBma)
    local attribute_item_list = data.SmartDetails.AttributeItemList

    c_handler_drives = self.c_handler_drives

    local ok, ret = pcall(c_handler_drives.get_written_info, c_handler_drives, 300, attribute_item_list)
    lu.assertEquals(ok, true)
    lu.assertEquals(ret, def.STORAGE_INFO_INVALID_DWORD)

    drive.Protocol = def.DRIVE_PROTOCOL.SAS
    local sas_smart_info = {
        SmartDetails = {
            SSMediaUsedEnduranceIndicator = 1
        }
    }
    ok, ret = pcall(c_handler_drives.get_pd_wearout_info, c_handler_drives, drive, sas_smart_info.SmartDetails)
    lu.assertEquals(ok, true)
    lu.assertEquals(ret, 99)

    ret = pcall(c_handler_drives.get_pd_wearout_info, c_handler_drives, drive, sas_smart_info.SmartDetails)
    lu.assertEquals(ret, true)

    drive.Protocol = def.DRIVE_PROTOCOL.FC
    ret = pcall(c_handler_drives.get_pd_wearout_info, c_handler_drives, drive, data.SmartDetails)
    lu.assertEquals(ret, true)
    lu.assertEquals(drive.PredictedMediaLifeLeftPercent, def.INVALID_U8)

    drive.Manufacturer = 'ATA'
    ret = pcall(c_handler_drives.check_manufacture_statisfied_top3, c_handler_drives, drive)
    lu.assertEquals(ret, true)

    ret = pcall(c_handler_drives.check_collect_est_lifespan_time, c_handler_drives, drive)
    lu.assertEquals(ret, true)

    data.HuaweiDefinedSMARTSupported = true
    ret = pcall(c_handler_drives.check_collect_est_lifespan_time, c_handler_drives, drive, data)
    lu.assertEquals(ret, true)
end

function Test_Bma_Eth:tearDown()
    drive_collection.destroy()
    object_manager.destroy()
    bus_monitor_service.destroy()
    hook_tasks.unhook()
end
