blob: 9ba054a9be00e8b78abcad6f9bd85351ca1b702e [file] [log] [blame]
// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "missive/util/shared_queue.h"
#include <vector>
#include <base/callback_helpers.h>
#include <base/sequenced_task_runner.h>
#include <base/synchronization/waitable_event.h>
#include <base/task/task_traits.h>
#include <base/task/thread_pool.h>
#include <base/test/task_environment.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "missive/util/status.h"
#include "missive/util/statusor.h"
namespace reporting {
namespace {
class QueueTester {
public:
explicit QueueTester(scoped_refptr<SharedQueue<int>> queue)
: queue_(queue),
sequenced_task_runner_(base::ThreadPool::CreateSequencedTaskRunner({})),
completed_(base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED),
pop_result_(Status(error::FAILED_PRECONDITION, "Pop hasn't run yet")) {}
~QueueTester() = default;
void Push(int value) { queue_->Push(value, base::DoNothing()); }
void Pop() {
sequenced_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&QueueTester::PopInternal, base::Unretained(this)));
}
void Swap() {
queue_->Swap(base::queue<int>(),
base::BindOnce(&QueueTester::OnSwap, base::Unretained(this)));
}
void PushPop(int value) {
queue_->Push(value, base::BindOnce(&QueueTester::OnPushPopComplete,
base::Unretained(this)));
}
void Wait() {
completed_.Wait();
completed_.Reset();
}
StatusOr<int> pop_result() { return pop_result_; }
base::queue<int>* swap_result() { return &swap_result_; }
private:
void OnPushPopComplete() { Pop(); }
void PopInternal() {
queue_->Pop(
base::BindOnce(&QueueTester::OnPopComplete, base::Unretained(this)));
}
void OnPopComplete(StatusOr<int> pop_result) {
pop_result_ = pop_result;
Signal();
}
void OnSwap(base::queue<int> swap_result) {
swap_result_ = swap_result;
Signal();
}
void Signal() { completed_.Signal(); }
scoped_refptr<SharedQueue<int>> queue_;
scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner_;
base::WaitableEvent completed_;
StatusOr<int> pop_result_;
base::queue<int> swap_result_;
};
TEST(SharedQueueTest, SuccessfulPushPop) {
base::test::TaskEnvironment task_envrionment{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
const int kExpectedValue = 1234;
auto queue = SharedQueue<int>::Create();
QueueTester queue_tester(queue);
queue_tester.PushPop(kExpectedValue);
queue_tester.Wait();
auto pop_result = queue_tester.pop_result();
ASSERT_OK(pop_result);
EXPECT_EQ(pop_result.ValueOrDie(), kExpectedValue);
}
TEST(SharedQueueTest, PushOrderMaintained) {
base::test::TaskEnvironment task_envrionment{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
std::vector<int> kExpectedValues = {1, 1, 2, 3, 5, 8, 13, 21};
auto queue = SharedQueue<int>::Create();
QueueTester queue_tester(queue);
for (auto value : kExpectedValues) {
queue_tester.Push(value);
}
for (auto value : kExpectedValues) {
queue_tester.Pop();
queue_tester.Wait();
auto pop_result = queue_tester.pop_result();
ASSERT_OK(pop_result);
EXPECT_EQ(pop_result.ValueOrDie(), value);
}
}
TEST(SharedQueueTest, SwapSuccessful) {
base::test::TaskEnvironment task_envrionment{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
std::vector<int> kExpectedValues = {1, 1, 2, 3, 5, 8, 13, 21};
auto queue = SharedQueue<int>::Create();
QueueTester queue_tester(queue);
for (auto value : kExpectedValues) {
queue_tester.Push(value);
}
queue_tester.Swap();
queue_tester.Wait();
auto* swapped_queue = queue_tester.swap_result();
for (auto value : kExpectedValues) {
EXPECT_EQ(swapped_queue->front(), value);
swapped_queue->pop();
}
// Test to ensure the SharedQueue is empty.
queue_tester.Pop();
queue_tester.Wait();
auto pop_result = queue_tester.pop_result();
EXPECT_FALSE(pop_result.ok());
EXPECT_EQ(pop_result.status().error_code(), error::OUT_OF_RANGE);
}
} // namespace
} // namespace reporting