| // 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 |