void QueueTest::maxQueueSize() { // Create a queue with a maximum size of 5, and fill it up for (int n = 0; n < 5; ++n) { queue.tryPutMessage(n); } // Calling tryPutMessage() now should fail EXPECT_THROW(queue.tryPutMessage(5), std::overflow_error); EXPECT_FALSE(queue.tryPutMessageNoThrow(5)); int val = 5; EXPECT_FALSE(queue.tryPutMessageNoThrow(std::move(val))); // Pop a message from the queue int result = -1; EXPECT_TRUE(queue.tryConsume(result)); EXPECT_EQ(0, result); // We should be able to write another message now that we popped one off. queue.tryPutMessage(5); // But now we are full again. EXPECT_THROW(queue.tryPutMessage(6), std::overflow_error); // putMessage() should let us exceed the maximum queue.putMessage(6); // Pull another mesage off EXPECT_TRUE(queue.tryConsume(result)); EXPECT_EQ(1, result); // tryPutMessage() should still fail since putMessage() actually put us over // the max. EXPECT_THROW(queue.tryPutMessage(7), std::overflow_error); // Pull another message off and try again EXPECT_TRUE(queue.tryConsume(result)); EXPECT_EQ(2, result); queue.tryPutMessage(7); // Now pull all the remaining messages off EXPECT_TRUE(queue.tryConsume(result)); EXPECT_EQ(3, result); EXPECT_TRUE(queue.tryConsume(result)); EXPECT_EQ(4, result); EXPECT_TRUE(queue.tryConsume(result)); EXPECT_EQ(5, result); EXPECT_TRUE(queue.tryConsume(result)); EXPECT_EQ(6, result); EXPECT_TRUE(queue.tryConsume(result)); EXPECT_EQ(7, result); // There should be no messages left result = -1; EXPECT_TRUE(!queue.tryConsume(result)); EXPECT_EQ(-1, result); }
void QueueTest::maxQueueSize() { // Create a queue with a maximum size of 5, and fill it up for (int n = 0; n < 5; ++n) { queue.tryPutMessage(n); } // Calling tryPutMessage() now should fail BOOST_CHECK_THROW(queue.tryPutMessage(5), TQueueFullException); BOOST_CHECK_EQUAL(queue.tryPutMessageNoThrow(5), false); int val = 5; BOOST_CHECK_EQUAL(queue.tryPutMessageNoThrow(std::move(val)), false); // Pop a message from the queue int result = -1; BOOST_CHECK(queue.tryConsume(result)); BOOST_CHECK_EQUAL(result, 0); // We should be able to write another message now that we popped one off. queue.tryPutMessage(5); // But now we are full again. BOOST_CHECK_THROW(queue.tryPutMessage(6), TQueueFullException); // putMessage() should let us exceed the maximum queue.putMessage(6); // Pull another mesage off BOOST_CHECK(queue.tryConsume(result)); BOOST_CHECK_EQUAL(result, 1); // tryPutMessage() should still fail since putMessage() actually put us over // the max. BOOST_CHECK_THROW(queue.tryPutMessage(7), TQueueFullException); // Pull another message off and try again BOOST_CHECK(queue.tryConsume(result)); BOOST_CHECK_EQUAL(result, 2); queue.tryPutMessage(7); // Now pull all the remaining messages off BOOST_CHECK(queue.tryConsume(result)); BOOST_CHECK_EQUAL(result, 3); BOOST_CHECK(queue.tryConsume(result)); BOOST_CHECK_EQUAL(result, 4); BOOST_CHECK(queue.tryConsume(result)); BOOST_CHECK_EQUAL(result, 5); BOOST_CHECK(queue.tryConsume(result)); BOOST_CHECK_EQUAL(result, 6); BOOST_CHECK(queue.tryConsume(result)); BOOST_CHECK_EQUAL(result, 7); // There should be no messages left result = -1; BOOST_CHECK(!queue.tryConsume(result)); BOOST_CHECK_EQUAL(result, -1); }
TEST(NotificationQueueTest, ConsumeUntilDrainedStress) { for (size_t i = 0; i < 1 << 8; ++i) { // Basic tests: make sure we // - drain all the messages // - ignore any maxReadAtOnce // - can't add messages during draining EventBase eventBase; IntQueue queue; QueueConsumer consumer; consumer.fn = [&](int j) { EXPECT_THROW(queue.tryPutMessage(j), std::runtime_error); EXPECT_FALSE(queue.tryPutMessageNoThrow(j)); EXPECT_THROW(queue.putMessage(j), std::runtime_error); std::vector<int> ints{1, 2, 3}; EXPECT_THROW( queue.putMessages(ints.begin(), ints.end()), std::runtime_error); }; consumer.setMaxReadAtOnce(10); // We should ignore this consumer.startConsuming(&eventBase, &queue); for (int j = 0; j < 20; j++) { queue.putMessage(j); } EXPECT_TRUE(consumer.consumeUntilDrained()); EXPECT_EQ(20, consumer.messages.size()); // Make sure there can only be one drainer at once folly::Baton<> callbackBaton, threadStartBaton; consumer.fn = [&](int /* i */) { callbackBaton.wait(); }; QueueConsumer competingConsumer; competingConsumer.startConsuming(&eventBase, &queue); queue.putMessage(1); atomic<bool> raceA {false}; atomic<bool> raceB {false}; size_t numConsA = 0; size_t numConsB = 0; auto thread = std::thread([&]{ threadStartBaton.post(); raceB = consumer.consumeUntilDrained(&numConsB) && numConsB; }); threadStartBaton.wait(); raceA = competingConsumer.consumeUntilDrained(&numConsA) && numConsA; callbackBaton.post(); thread.join(); EXPECT_FALSE(raceA && raceB); EXPECT_TRUE(raceA || raceB); EXPECT_TRUE(raceA ^ raceB); } }