-- 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 cq = require 'chain_queue'

TestChainQueue = {}

-- 测试队列push操作
function TestChainQueue:test_push()
    local q = cq.new(function (a, b)
        return a.system_id == b.system_id
    end)

    -- 先模拟操作1-8 host，上电原因为'ChassisControlCommand'
    for i = 1, 8 do
        q:push({system_id = i, op_cause = 'ChassisControlCommand'})
    end
    -- 再次模拟操作3、6 host，上电原因分别为'ResetViaPushButton'，'PowerUpViaPushButton'
    -- 该操作会更新原队列中的操作原因
    q:push({system_id = 3, op_cause = 'ResetViaPushButton'})
    q:push({system_id = 6, op_cause = 'PowerUpViaPushButton'})

    -- 出队1-5 host，检查system_id与原因
    local v = q:pop()
    lu.assertIsTrue(v.system_id == 1 and v.op_cause == 'ChassisControlCommand' and q:get_len() == 7)

    v = q:pop()
    lu.assertIsTrue(v.system_id == 2 and v.op_cause == 'ChassisControlCommand' and q:get_len() == 6)

    v = q:pop()
    lu.assertIsTrue(v.system_id == 3 and v.op_cause == 'ResetViaPushButton' and q:get_len() == 5)

    v = q:pop()
    lu.assertIsTrue(v.system_id == 4 and v.op_cause == 'ChassisControlCommand' and q:get_len() == 4)

    v = q:pop()
    lu.assertIsTrue(v.system_id == 5 and v.op_cause == 'ChassisControlCommand' and q:get_len() == 3)

    -- 再次模拟操作1-8 host，上电原因为'PowerupViaRTC'
    -- 队列中已存在的host，会更新操作原因；不存在的会追加到队尾
    for i = 1, 8 do
        q:push({system_id = i, op_cause = 'PowerupViaRTC'})
    end

    -- 出队，检查原因；当前队列中host分别为6 7 8 1 2 3 4 5
    v = q:pop()
    lu.assertIsTrue(v.system_id == 6 and v.op_cause == 'PowerupViaRTC' and q:get_len() == 7)

    -- 再次入队1、5 host，此时会更新原因
    q:push({system_id = 1, op_cause = 'WatchdogExpiration'})
    q:push({system_id = 5, op_cause = 'Oem'})

    -- 剩余元素出队，并检查原因
    v = q:pop()
    lu.assertIsTrue(v.system_id == 7 and v.op_cause == 'PowerupViaRTC' and q:get_len() == 6)
    v = q:pop()
    lu.assertIsTrue(v.system_id == 8 and v.op_cause == 'PowerupViaRTC' and q:get_len() == 5)
    v = q:pop()
    lu.assertIsTrue(v.system_id == 1 and v.op_cause == 'WatchdogExpiration' and q:get_len() == 4)
    v = q:pop()
    lu.assertIsTrue(v.system_id == 2 and v.op_cause == 'PowerupViaRTC' and q:get_len() == 3)
    v = q:pop()
    lu.assertIsTrue(v.system_id == 3 and v.op_cause == 'PowerupViaRTC' and q:get_len() == 2)
    v = q:pop()
    lu.assertIsTrue(v.system_id == 4 and v.op_cause == 'PowerupViaRTC' and q:get_len() == 1)
    v = q:pop()
    lu.assertIsTrue(v.system_id == 5 and v.op_cause == 'Oem' and q:get_len() == 0)
end

-- 测试队列pop操作
function TestChainQueue:test_pop()
    local q = cq.new(function (a, b)
        return false
    end)

    -- 未插入元素，直接pop
    lu.assertIsTrue(q:pop() == nil)
    lu.assertIsTrue(q:pop() == nil)

    -- 测试先进先出
    local a, b, c = {}, {}, {}
    q:push(a)
    q:push(b)
    q:push(c)
    lu.assertIsTrue(q:pop() == a)
    lu.assertIsTrue(q:pop() == b)
    lu.assertIsTrue(q:pop() == c)
    lu.assertIsTrue(q:pop() == nil)
end

-- 'Unknown', 'ChassisControlCommand', 'ResetViaPushButton', 'PowerUpViaPushButton', 'WatchdogExpiration',
-- 'Oem', 'ACRestoreAlwaysPowerUp', 'ACRestoreKeepPreviousState', 'ResetViaPEF', 'PowerCycleViaPEF',
-- 'SoftReset', 'PowerupViaRTC'

-- 测试队列delete操作
function TestChainQueue:test_delete()
    local q = cq.new(function (a, b)
        return a.system_id == b.system_id
    end)

    -- 测试直接delete
    q:delete({system_id = 1})
    q:delete({system_id = 1})
    q:delete({system_id = 3})

    -- 先模拟操作1-8 host，上电原因为'ChassisControlCommand'
    for i = 1, 8 do
        q:push({system_id = i, op_cause = 'ChassisControlCommand'})
    end
    q:delete({system_id = 1})
    q:delete({system_id = 3})
    q:delete({system_id = 6})
    q:delete({system_id = 7})
    local v = q:pop()
    lu.assertIsTrue(v.system_id == 2 and v.op_cause == 'ChassisControlCommand' and q:get_len() == 3)
    v = q:pop()
    lu.assertIsTrue(v.system_id == 4 and v.op_cause == 'ChassisControlCommand' and q:get_len() == 2)
    v = q:pop()
    lu.assertIsTrue(v.system_id == 5 and v.op_cause == 'ChassisControlCommand' and q:get_len() == 1)
    v = q:pop()
    lu.assertIsTrue(v.system_id == 8 and v.op_cause == 'ChassisControlCommand' and q:get_len() == 0)

    -- 再次入队1、4、5 host
    q:push({system_id = 1, op_cause = 'WatchdogExpiration'})
    q:push({system_id = 4, op_cause = 'Oem'})
    q:push({system_id = 5, op_cause = 'Oem'})
    q:push({system_id = 4, op_cause = 'PowerupViaRTC'})
    q:push({system_id = 5, op_cause = 'PowerupViaRTC'})

    q:delete({system_id = 4})
    q:delete({system_id = 8})
    q:delete({system_id = 7})
    v = q:pop()
    lu.assertIsTrue(v.system_id == 1 and v.op_cause == 'WatchdogExpiration' and q:get_len() == 1)
    v = q:pop()
    lu.assertIsTrue(v.system_id == 5 and v.op_cause == 'PowerupViaRTC' and q:get_len() == 0)
    lu.assertIsTrue(q:pop() == nil)
end