-- 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 test_common = require 'test_common.utils'
local sd_bus = require 'sd_bus'
local log = require 'mc.logging'
local utils = require 'mc.utils'
local ctx = require 'mc.context'
local test_ipmi = require 'test_ipmi'
local dft_test = require 'test_dft'
local test_csr_distribute = require 'test_csr_distribute'
local test_customize = require 'test_customize'
local test_configuration = require 'test_configuration'
local test_fruid = require 'test_fru_id_mgmt'
local test_sn = require 'test_sn'
require 'frudata.client'
require 'skynet.manager'
require 'frudata.json_types.Overview'
require 'frudata.json_types.Accessor'
require 'frudata.json_types.Manufacture'
require 'frudata.json_types.Frudata'
require 'frudata.json_types.Chassis'
require 'frudata.json_types.Board'
require 'frudata.json_types.Product'
require 'frudata.json_types.System'

log:setLevel(log.INFO)

-- 准备测试专用路径
local function prepare_test_data()
    log:info('- prepare test data')
    local test_data_dir = skynet.getenv('TEST_DATA_DIR')
    os.execute('mkdir -p ' .. test_data_dir)

    local dir_list = {
        'apps/frudata/mds', 'apps/hwdiscovery/mds', 'apps/hwproxy/mds', 'sr', 'data', 'usr/lib64', 'apps/ipmi_core/mds',
            'apps/mctpd/mds', 'apps/event/mds'}
    for _, path in pairs(dir_list) do
        os.execute('mkdir -p ' .. test_data_dir .. '/' .. path)
    end

    -- libsoc_adapter_it.so中路径固定使用test/integration
    os.execute('mkdir -p test/integration/.test_temp_data/data')
    os.execute('cp' .. ' -r ' .. 'test/integration/test_data/mockdata' .. ' ' .. test_data_dir .. 'data')
    utils.copy_file('temp/usr/lib64/mock/libsoc_adapter_it.so',
        test_data_dir .. '/usr/lib64/libsoc_adapter.so')

    utils.copy_file('test/integration/test_data/sr/root.sr', test_data_dir .. '/sr/root.sr')
    utils.copy_file('test/integration/test_data/sr/14100513_Frudata_01.sr',
        test_data_dir .. '/sr/14100513_Frudata_01.sr')
    utils.copy_file('mds/schema.json', test_data_dir .. '/apps/frudata/mds/schema.json')
    utils.copy_file('mds/service.json', test_data_dir .. '/apps/frudata/mds/service.json')

    utils.copy_file('temp/opt/bmc/apps/hwdiscovery/mds/schema.json',
        test_data_dir .. '/apps/hwdiscovery/mds/schema.json')
    utils.copy_file('temp/opt/bmc/apps/hwproxy/mds/schema.json',
        test_data_dir .. '/apps/hwproxy/mds/schema.json')
    utils.copy_file('temp/opt/bmc/apps/ipmi_core/mds/schema.json',
        test_data_dir .. '/apps/ipmi_core/mds/schema.json')
    utils.copy_file('temp/opt/bmc/apps/mctpd/mds/schema.json',
        test_data_dir .. '/apps/mctpd/mds/schema.json')
    utils.copy_file('temp/opt/bmc/apps/event/mds/schema.json',
        test_data_dir .. '/apps/event/mds/schema.json')
    utils.copy_file('test/integration/test_data/event_def.json', test_data_dir .. '/event_def.json')
    -- 持久化文件打桩
    local src = os.getenv('ROOT_DIR') .. '/test_data/apps/persistence/mmcblk0p8'
    local dst = test_data_dir .. '/mmcblk0p8'
    utils.copy_file(src, dst)
end

-- 删除测试专用路径
local function clear_test_data(exit_test)
    log:info('- clear test data')
    local cwd = utils.realpath('.')
    local test_data_dir = cwd .. '/' .. skynet.getenv('TEST_DATA_DIR')
    if exit_test then
        skynet.timeout(0, function()
            skynet.sleep(1000)
            skynet.abort()
            utils.remove_file(test_data_dir)
        end)
    else
        utils.remove_file(test_data_dir)
        utils.remove_file('test/integration/.test_temp_data')
    end
end

local function search_file(str_file)
    for line in io.lines(str_file) do
        if string.find(line, 'Product Part Number', 1, true) then
            return true
        end
    end
    return false
end

local function test_on_dump(bus)
    log:info('== test dump start ...')
    -- 回调函数不支持代理对象访问，这地方直接使用busctl访问方式进行测试
    local service = 'bmc.kepler.frudata'
    local path = '/bmc/kepler/frudata/MicroComponent'
    local intf = 'bmc.kepler.MicroComponent.Debug'
    local dump = '/tmp'
    local c = ctx.new('IT', 'Admin', '127.0.0.1')
    bus:call(service, path, intf, 'Dump', 'a{ss}s', c, dump)
    local file = io.open(dump .. '/fruinfo.txt', 'r')
    assert(file)
    assert(search_file(dump .. '/fruinfo.txt'), "Product Part Number Write Failed")
    file:close()
end

local function test_frudata(bus)
    log:info('================ test frudata start ================')
    test_csr_distribute:version_init(bus)
    skynet.sleep(2000)
    test_csr_distribute:csr_obj(bus)
    dft_test:dft_rpc_method_test(bus)
    test_ipmi:test_ipmi(bus)
    test_customize:test_customize(bus)
    test_configuration:test_configuration(bus)
    test_fruid:test_fru_id_mgmt()
    test_sn:test_sn(bus)
    test_on_dump(bus)
    skynet.call('frudata', 'lua', 'exit')
    log:info('================ test frudata complete ================')
end

skynet.start(function()
    clear_test_data() -- 防止之前数据残留
    prepare_test_data()
    test_common.dbus_launch()
    local bus = sd_bus.open_user(true)
    skynet.uniqueservice('sd_bus')
    skynet.uniqueservice('persistence/service/main')
    skynet.uniqueservice('maca/service/main')
    skynet.uniqueservice('ipmi_core/service/main')
    skynet.uniqueservice('mctpd/service/main')
    skynet.uniqueservice('mock_service/mock_firmware_mgmt')
    skynet.uniqueservice('hwproxy/service/main')
    skynet.uniqueservice('event/service/main')
    skynet.uniqueservice('hwdiscovery/service/main')
    skynet.uniqueservice('main')
    skynet.fork(function()
        local ok, err = pcall(test_frudata, bus)
        clear_test_data(true)
        if not ok then
            error(err)
        end
    end)
end)
