/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/executors/task_queue/PriorityUnboundedBlockingQueue.h>
#include <vector>
#include <folly/container/Enumerate.h>
#include <folly/portability/GTest.h>
#include <folly/synchronization/Baton.h>
using namespace folly;
class PriorityUnboundedBlockingQueueTest : public testing::Test {};
TEST_F(PriorityUnboundedBlockingQueueTest, push_pop) {
PriorityUnboundedBlockingQueue<int> q(3);
q.add(42);
EXPECT_EQ(42, q.take());
}
TEST_F(PriorityUnboundedBlockingQueueTest, multiple_push_pop) {
PriorityUnboundedBlockingQueue<int> q(3);
q.add(42);
q.add(77);
EXPECT_EQ(42, q.take());
EXPECT_EQ(77, q.take());
}
TEST_F(PriorityUnboundedBlockingQueueTest, size) {
PriorityUnboundedBlockingQueue<int> q(3);
EXPECT_EQ(0, q.size());
q.add(42);
EXPECT_EQ(1, q.size());
q.take();
EXPECT_EQ(0, q.size());
}
TEST_F(PriorityUnboundedBlockingQueueTest, concurrent_push_pop) {
PriorityUnboundedBlockingQueue<int> q(3);
Baton<> b1, b2;
std::thread t([&] {
b1.post();
EXPECT_EQ(42, q.take());
EXPECT_EQ(0, q.size());
b2.post();
});
b1.wait();
q.add(42);
b2.wait();
EXPECT_EQ(0, q.size());
t.join();
}
TEST_F(PriorityUnboundedBlockingQueueTest, priority_order) {
PriorityUnboundedBlockingQueue<int> q(3);
EXPECT_EQ(0, q.size());
q.addWithPriority(27, 0);
q.addWithPriority(42, 1);
q.addWithPriority(55, 0);
q.addWithPriority(12, -1);
EXPECT_EQ(4, q.size());
EXPECT_EQ(42, q.take());
EXPECT_EQ(27, q.take());
EXPECT_EQ(55, q.take());
EXPECT_EQ(12, q.take());
EXPECT_EQ(0, q.size());
}
// Since PriorityUnboundedBlockingQueue implements folly::BlockingQueue<T>,
// addWithPriority method has to accept priority as int_8. This means invalid
// values for priority (such as negative or very large numbers) might get
// passed. Verify this behavior.
TEST_F(PriorityUnboundedBlockingQueueTest, invalid_priorities) {
PriorityUnboundedBlockingQueue<int> q(2);
q.addWithPriority(1, -1); // expected to be converted to the lowest priority
q.addWithPriority(2, 50); // expected to be converted to the highest priority
EXPECT_EQ(q.take(), 2);
EXPECT_EQ(q.take(), 1);
}
TEST_F(PriorityUnboundedBlockingQueueTest, invalid_priorities_edge) {
PriorityUnboundedBlockingQueue<int> q(2);
q.addWithPriority(1, Executor::LO_PRI);
q.addWithPriority(2, Executor::HI_PRI);
EXPECT_EQ(q.take(), 2);
EXPECT_EQ(q.take(), 1);
}