| // Copyright 2018 The Chromium 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 "content/browser/renderer_host/frame_token_message_queue.h" |
| |
| #include <vector> |
| |
| #include "base/bind.h" |
| #include "base/macros.h" |
| #include "ipc/ipc_message.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace content { |
| |
| namespace { |
| |
| // Test verision of FrameTokenMessageQueue::Client which tracks the number of |
| // calls to client methods, and the associated input parameters. |
| class TestFrameTokenMessageQueueClient : public FrameTokenMessageQueue::Client { |
| public: |
| TestFrameTokenMessageQueueClient() {} |
| ~TestFrameTokenMessageQueueClient() {} |
| |
| // Resets all method counters. |
| void Reset(); |
| |
| // All subsequent IPC::Messages received in OnProcessSwapMessage will be |
| // marked as having a dispatch error. |
| void SetErrorOnMessageProcess(); |
| |
| // FrameTokenMessageQueue::Client: |
| void OnInvalidFrameToken(uint32_t frame_token) override; |
| void OnMessageDispatchError(const IPC::Message& message) override; |
| void OnProcessSwapMessage(const IPC::Message& message) override; |
| |
| bool invalid_frame_token_called() const { |
| return invalid_frame_token_called_; |
| } |
| uint32_t invalid_frame_token() const { return invalid_frame_token_; } |
| int on_message_dispatch_error_count() const { |
| return on_message_dispatch_error_count_; |
| } |
| int on_process_swap_message_count() const { |
| return on_process_swap_message_count_; |
| } |
| |
| private: |
| // If true the each IPC::Message received will be marked as having a dispatch |
| // error. |
| bool set_error_on_process_ = false; |
| bool invalid_frame_token_called_ = false; |
| uint32_t invalid_frame_token_ = 0u; |
| int on_message_dispatch_error_count_ = 0; |
| int on_process_swap_message_count_ = 0; |
| DISALLOW_COPY_AND_ASSIGN(TestFrameTokenMessageQueueClient); |
| }; |
| |
| void TestFrameTokenMessageQueueClient::Reset() { |
| invalid_frame_token_called_ = false; |
| invalid_frame_token_ = 0u; |
| on_message_dispatch_error_count_ = 0; |
| on_process_swap_message_count_ = 0; |
| } |
| |
| void TestFrameTokenMessageQueueClient::SetErrorOnMessageProcess() { |
| set_error_on_process_ = true; |
| } |
| |
| void TestFrameTokenMessageQueueClient::OnInvalidFrameToken( |
| uint32_t frame_token) { |
| invalid_frame_token_called_ = true; |
| invalid_frame_token_ = frame_token; |
| } |
| |
| void TestFrameTokenMessageQueueClient::OnMessageDispatchError( |
| const IPC::Message& message) { |
| ++on_message_dispatch_error_count_; |
| } |
| |
| void TestFrameTokenMessageQueueClient::OnProcessSwapMessage( |
| const IPC::Message& message) { |
| if (set_error_on_process_) |
| message.set_dispatch_error(); |
| ++on_process_swap_message_count_; |
| } |
| |
| // Test class which provides FrameTokenCallback() to be used as a closure when |
| // enqueueing non-IPC callbacks. This only tracks if the callback was called. |
| class TestNonIPCMessageEnqueuer { |
| public: |
| TestNonIPCMessageEnqueuer() {} |
| ~TestNonIPCMessageEnqueuer() {} |
| |
| void FrameTokenCallback(); |
| |
| bool frame_token_callback_called() const { |
| return frame_token_callback_called_; |
| } |
| |
| private: |
| bool frame_token_callback_called_ = false; |
| DISALLOW_COPY_AND_ASSIGN(TestNonIPCMessageEnqueuer); |
| }; |
| |
| void TestNonIPCMessageEnqueuer::FrameTokenCallback() { |
| frame_token_callback_called_ = true; |
| } |
| |
| } // namespace |
| |
| class FrameTokenMessageQueueTest : public testing::Test { |
| public: |
| FrameTokenMessageQueueTest(); |
| ~FrameTokenMessageQueueTest() override {} |
| |
| TestFrameTokenMessageQueueClient* test_client() { return &test_client_; } |
| TestNonIPCMessageEnqueuer* test_non_ipc_enqueuer() { |
| return &test_non_ipc_enqueuer_; |
| } |
| FrameTokenMessageQueue* frame_token_message_queue() { |
| return &frame_token_message_queue_; |
| } |
| |
| private: |
| TestFrameTokenMessageQueueClient test_client_; |
| TestNonIPCMessageEnqueuer test_non_ipc_enqueuer_; |
| FrameTokenMessageQueue frame_token_message_queue_; |
| DISALLOW_COPY_AND_ASSIGN(FrameTokenMessageQueueTest); |
| }; |
| |
| FrameTokenMessageQueueTest::FrameTokenMessageQueueTest() |
| : frame_token_message_queue_(&test_client_) {} |
| |
| // Tests that if a valid IPC::Message is enqueued, that it is processed when its |
| // matching frame token arrives. |
| TEST_F(FrameTokenMessageQueueTest, OnlyIPCMessageCorrectFrameToken) { |
| FrameTokenMessageQueue* queue = frame_token_message_queue(); |
| TestFrameTokenMessageQueueClient* client = test_client(); |
| ASSERT_EQ(0u, queue->size()); |
| |
| const uint32_t frame_token = 42; |
| IPC::Message msg(0, 1, IPC::Message::PRIORITY_NORMAL); |
| std::vector<IPC::Message> messages; |
| messages.push_back(msg); |
| |
| // Adding to the queue with a new frame token should not cause processing. |
| queue->OnFrameSwapMessagesReceived(frame_token, std::move(messages)); |
| EXPECT_EQ(1u, queue->size()); |
| EXPECT_EQ(0, client->on_process_swap_message_count()); |
| |
| queue->DidProcessFrame(frame_token); |
| EXPECT_EQ(0u, queue->size()); |
| EXPECT_FALSE(client->invalid_frame_token_called()); |
| EXPECT_EQ(1, client->on_process_swap_message_count()); |
| EXPECT_EQ(0, client->on_message_dispatch_error_count()); |
| } |
| |
| // Tests that if a valid IPC::Message is enqueued after its frame token has |
| // arrived that it is processed immediately. |
| TEST_F(FrameTokenMessageQueueTest, EnqueueAfterFrameTokenProcesses) { |
| FrameTokenMessageQueue* queue = frame_token_message_queue(); |
| TestFrameTokenMessageQueueClient* client = test_client(); |
| ASSERT_EQ(0u, queue->size()); |
| |
| const uint32_t frame_token = 42; |
| IPC::Message msg(0, 1, IPC::Message::PRIORITY_NORMAL); |
| std::vector<IPC::Message> messages; |
| messages.push_back(msg); |
| |
| queue->DidProcessFrame(frame_token); |
| EXPECT_EQ(0u, queue->size()); |
| EXPECT_FALSE(client->invalid_frame_token_called()); |
| EXPECT_EQ(0, client->on_process_swap_message_count()); |
| EXPECT_EQ(0, client->on_message_dispatch_error_count()); |
| |
| // Enqueuing after frame token arrival should immediately process. |
| queue->OnFrameSwapMessagesReceived(frame_token, std::move(messages)); |
| EXPECT_EQ(0u, queue->size()); |
| EXPECT_FALSE(client->invalid_frame_token_called()); |
| EXPECT_EQ(1, client->on_process_swap_message_count()); |
| EXPECT_EQ(0, client->on_message_dispatch_error_count()); |
| } |
| |
| // Tests that if a valid IPC::Message is enqueued and that subsequently a |
| // non-IPC callback is enqueued, that both get called once the frame token |
| // arrives. |
| TEST_F(FrameTokenMessageQueueTest, EnqueueBothIPCMessageAndNonIPCCallback) { |
| FrameTokenMessageQueue* queue = frame_token_message_queue(); |
| TestFrameTokenMessageQueueClient* client = test_client(); |
| TestNonIPCMessageEnqueuer* enqueuer = test_non_ipc_enqueuer(); |
| ASSERT_EQ(0u, queue->size()); |
| |
| const uint32_t frame_token = 42; |
| IPC::Message msg(0, 1, IPC::Message::PRIORITY_NORMAL); |
| std::vector<IPC::Message> messages; |
| messages.push_back(msg); |
| |
| // Adding to the queue with a new frame token should not cause processing. |
| queue->OnFrameSwapMessagesReceived(frame_token, std::move(messages)); |
| EXPECT_EQ(1u, queue->size()); |
| EXPECT_EQ(0, client->on_process_swap_message_count()); |
| |
| queue->EnqueueOrRunFrameTokenCallback( |
| frame_token, |
| base::BindOnce(&TestNonIPCMessageEnqueuer::FrameTokenCallback, |
| base::Unretained(enqueuer))); |
| EXPECT_FALSE(enqueuer->frame_token_callback_called()); |
| EXPECT_FALSE(client->invalid_frame_token_called()); |
| |
| queue->DidProcessFrame(frame_token); |
| EXPECT_EQ(0u, queue->size()); |
| EXPECT_FALSE(client->invalid_frame_token_called()); |
| EXPECT_EQ(1, client->on_process_swap_message_count()); |
| EXPECT_EQ(0, client->on_message_dispatch_error_count()); |
| EXPECT_TRUE(enqueuer->frame_token_callback_called()); |
| } |
| |
| // Tests that if a valid non-IPC callback is enqueued before an IPC::Message, |
| // that both get called once the frame token arrives. |
| TEST_F(FrameTokenMessageQueueTest, EnqueueNonIPCCallbackFirst) { |
| FrameTokenMessageQueue* queue = frame_token_message_queue(); |
| TestFrameTokenMessageQueueClient* client = test_client(); |
| TestNonIPCMessageEnqueuer* enqueuer = test_non_ipc_enqueuer(); |
| ASSERT_EQ(0u, queue->size()); |
| |
| const uint32_t frame_token = 42; |
| IPC::Message msg(0, 1, IPC::Message::PRIORITY_NORMAL); |
| std::vector<IPC::Message> messages; |
| messages.push_back(msg); |
| |
| queue->EnqueueOrRunFrameTokenCallback( |
| frame_token, |
| base::BindOnce(&TestNonIPCMessageEnqueuer::FrameTokenCallback, |
| base::Unretained(enqueuer))); |
| EXPECT_FALSE(enqueuer->frame_token_callback_called()); |
| EXPECT_EQ(0, client->on_process_swap_message_count()); |
| |
| // We should be able to enqueue even though it is for the same frame token. |
| queue->OnFrameSwapMessagesReceived(frame_token, std::move(messages)); |
| EXPECT_EQ(2u, queue->size()); |
| EXPECT_EQ(0, client->on_process_swap_message_count()); |
| EXPECT_FALSE(client->invalid_frame_token_called()); |
| |
| queue->DidProcessFrame(frame_token); |
| EXPECT_EQ(0u, queue->size()); |
| EXPECT_FALSE(client->invalid_frame_token_called()); |
| EXPECT_EQ(1, client->on_process_swap_message_count()); |
| EXPECT_EQ(0, client->on_message_dispatch_error_count()); |
| EXPECT_TRUE(enqueuer->frame_token_callback_called()); |
| } |
| |
| // Tests that if we only have a non-IPC callback enqueued that it is called once |
| // the frame token arrive. |
| TEST_F(FrameTokenMessageQueueTest, EnqueueOnlyNonIPC) { |
| FrameTokenMessageQueue* queue = frame_token_message_queue(); |
| TestFrameTokenMessageQueueClient* client = test_client(); |
| TestNonIPCMessageEnqueuer* enqueuer = test_non_ipc_enqueuer(); |
| ASSERT_EQ(0u, queue->size()); |
| |
| const uint32_t frame_token = 42; |
| queue->EnqueueOrRunFrameTokenCallback( |
| frame_token, |
| base::BindOnce(&TestNonIPCMessageEnqueuer::FrameTokenCallback, |
| base::Unretained(enqueuer))); |
| EXPECT_FALSE(enqueuer->frame_token_callback_called()); |
| EXPECT_EQ(0, client->on_process_swap_message_count()); |
| EXPECT_EQ(1u, queue->size()); |
| |
| queue->DidProcessFrame(frame_token); |
| EXPECT_EQ(0u, queue->size()); |
| EXPECT_FALSE(client->invalid_frame_token_called()); |
| EXPECT_EQ(0, client->on_process_swap_message_count()); |
| EXPECT_EQ(0, client->on_message_dispatch_error_count()); |
| EXPECT_TRUE(enqueuer->frame_token_callback_called()); |
| } |
| |
| // Tests that if we have messages enqueued, and receive a frame token that is |
| // larger, that we still process the messages. |
| TEST_F(FrameTokenMessageQueueTest, MessagesWhereFrameTokenSkipped) { |
| FrameTokenMessageQueue* queue = frame_token_message_queue(); |
| TestFrameTokenMessageQueueClient* client = test_client(); |
| TestNonIPCMessageEnqueuer* enqueuer = test_non_ipc_enqueuer(); |
| ASSERT_EQ(0u, queue->size()); |
| |
| const uint32_t frame_token = 42; |
| IPC::Message msg(0, 1, IPC::Message::PRIORITY_NORMAL); |
| std::vector<IPC::Message> messages; |
| messages.push_back(msg); |
| |
| queue->EnqueueOrRunFrameTokenCallback( |
| frame_token, |
| base::BindOnce(&TestNonIPCMessageEnqueuer::FrameTokenCallback, |
| base::Unretained(enqueuer))); |
| EXPECT_FALSE(enqueuer->frame_token_callback_called()); |
| EXPECT_EQ(0, client->on_process_swap_message_count()); |
| |
| // We should be able to enqueue even though it is for the same frame token. |
| queue->OnFrameSwapMessagesReceived(frame_token, std::move(messages)); |
| EXPECT_EQ(2u, queue->size()); |
| EXPECT_EQ(0, client->on_process_swap_message_count()); |
| EXPECT_FALSE(client->invalid_frame_token_called()); |
| |
| const uint32_t larger_frame_token = 1337; |
| queue->DidProcessFrame(larger_frame_token); |
| EXPECT_EQ(0u, queue->size()); |
| EXPECT_FALSE(client->invalid_frame_token_called()); |
| EXPECT_EQ(1, client->on_process_swap_message_count()); |
| EXPECT_EQ(0, client->on_message_dispatch_error_count()); |
| EXPECT_TRUE(enqueuer->frame_token_callback_called()); |
| } |
| |
| // Verifies that if there are multiple IPC::Messages that they are all |
| // processed. |
| TEST_F(FrameTokenMessageQueueTest, MultipleIPCMessages) { |
| FrameTokenMessageQueue* queue = frame_token_message_queue(); |
| TestFrameTokenMessageQueueClient* client = test_client(); |
| ASSERT_EQ(0u, queue->size()); |
| |
| const uint32_t frame_token = 42; |
| IPC::Message msg1(0, 1, IPC::Message::PRIORITY_NORMAL); |
| IPC::Message msg2(1, 2, IPC::Message::PRIORITY_LOW); |
| std::vector<IPC::Message> messages; |
| messages.push_back(msg1); |
| messages.push_back(msg2); |
| |
| // Adding to the queue with a new frame token should not cause processing. |
| queue->OnFrameSwapMessagesReceived(frame_token, std::move(messages)); |
| // All IPCs are enqueued as one. |
| EXPECT_EQ(1u, queue->size()); |
| EXPECT_EQ(0, client->on_process_swap_message_count()); |
| |
| queue->DidProcessFrame(frame_token); |
| EXPECT_EQ(0u, queue->size()); |
| EXPECT_FALSE(client->invalid_frame_token_called()); |
| EXPECT_EQ(2, client->on_process_swap_message_count()); |
| EXPECT_EQ(0, client->on_message_dispatch_error_count()); |
| } |
| |
| // Verifies that if there are multiple non-IPC messages enqueued that they are |
| // all called. |
| TEST_F(FrameTokenMessageQueueTest, MultipleNonIPCMessages) { |
| FrameTokenMessageQueue* queue = frame_token_message_queue(); |
| TestFrameTokenMessageQueueClient* client = test_client(); |
| TestNonIPCMessageEnqueuer* enqueuer = test_non_ipc_enqueuer(); |
| ASSERT_EQ(0u, queue->size()); |
| |
| const uint32_t frame_token = 42; |
| queue->EnqueueOrRunFrameTokenCallback( |
| frame_token, |
| base::BindOnce(&TestNonIPCMessageEnqueuer::FrameTokenCallback, |
| base::Unretained(enqueuer))); |
| EXPECT_FALSE(enqueuer->frame_token_callback_called()); |
| EXPECT_EQ(1u, queue->size()); |
| |
| // Create a second callback |
| TestNonIPCMessageEnqueuer second_enqueuer; |
| queue->EnqueueOrRunFrameTokenCallback( |
| frame_token, |
| base::BindOnce(&TestNonIPCMessageEnqueuer::FrameTokenCallback, |
| base::Unretained(&second_enqueuer))); |
| EXPECT_FALSE(second_enqueuer.frame_token_callback_called()); |
| EXPECT_EQ(2u, queue->size()); |
| |
| queue->DidProcessFrame(frame_token); |
| EXPECT_EQ(0u, queue->size()); |
| EXPECT_FALSE(client->invalid_frame_token_called()); |
| EXPECT_TRUE(enqueuer->frame_token_callback_called()); |
| EXPECT_TRUE(second_enqueuer.frame_token_callback_called()); |
| } |
| |
| // Tests that if a non-IPC callback is enqueued, after its frame token as been |
| // received, that it is immediately processed. |
| TEST_F(FrameTokenMessageQueueTest, EnqueuedAfterFrameTokenImmediatelyRuns) { |
| FrameTokenMessageQueue* queue = frame_token_message_queue(); |
| TestFrameTokenMessageQueueClient* client = test_client(); |
| TestNonIPCMessageEnqueuer* enqueuer = test_non_ipc_enqueuer(); |
| ASSERT_EQ(0u, queue->size()); |
| |
| const uint32_t frame_token = 42; |
| queue->DidProcessFrame(frame_token); |
| EXPECT_EQ(0u, queue->size()); |
| EXPECT_FALSE(client->invalid_frame_token_called()); |
| EXPECT_FALSE(enqueuer->frame_token_callback_called()); |
| |
| queue->EnqueueOrRunFrameTokenCallback( |
| frame_token, |
| base::BindOnce(&TestNonIPCMessageEnqueuer::FrameTokenCallback, |
| base::Unretained(enqueuer))); |
| EXPECT_EQ(0u, queue->size()); |
| EXPECT_FALSE(client->invalid_frame_token_called()); |
| EXPECT_TRUE(enqueuer->frame_token_callback_called()); |
| } |
| |
| // Tests that if IPC::Messages are enqueued for different frame tokens, that |
| // we only process the messages associated with the arriving token, and keep the |
| // others enqueued. |
| TEST_F(FrameTokenMessageQueueTest, DifferentFrameTokensEnqueuedIPC) { |
| FrameTokenMessageQueue* queue = frame_token_message_queue(); |
| TestFrameTokenMessageQueueClient* client = test_client(); |
| ASSERT_EQ(0u, queue->size()); |
| |
| const uint32_t frame_token_1 = 42; |
| IPC::Message msg1(0, 1, IPC::Message::PRIORITY_NORMAL); |
| std::vector<IPC::Message> messages_1; |
| messages_1.push_back(msg1); |
| |
| queue->OnFrameSwapMessagesReceived(frame_token_1, std::move(messages_1)); |
| EXPECT_EQ(1u, queue->size()); |
| EXPECT_EQ(0, client->on_process_swap_message_count()); |
| |
| const uint32_t frame_token_2 = 1337; |
| IPC::Message msg2(1, 2, IPC::Message::PRIORITY_LOW); |
| std::vector<IPC::Message> messages_2; |
| messages_2.push_back(msg2); |
| |
| queue->OnFrameSwapMessagesReceived(frame_token_2, std::move(messages_2)); |
| // With no frame token yet the second set of IPC::Messages should be enqueud |
| // separately. |
| EXPECT_EQ(2u, queue->size()); |
| EXPECT_EQ(0, client->on_process_swap_message_count()); |
| |
| // We should only process the first IPC::Message. |
| queue->DidProcessFrame(frame_token_1); |
| EXPECT_EQ(1u, queue->size()); |
| EXPECT_FALSE(client->invalid_frame_token_called()); |
| EXPECT_EQ(1, client->on_process_swap_message_count()); |
| EXPECT_EQ(0, client->on_message_dispatch_error_count()); |
| |
| // Clear the counts from the first token. |
| client->Reset(); |
| |
| // The second IPC::Message should be processed. |
| queue->DidProcessFrame(frame_token_2); |
| EXPECT_EQ(0u, queue->size()); |
| EXPECT_FALSE(client->invalid_frame_token_called()); |
| EXPECT_EQ(1, client->on_process_swap_message_count()); |
| EXPECT_EQ(0, client->on_message_dispatch_error_count()); |
| } |
| |
| // Test that if non-IPC callbacks are enqueued for different frame tokens, that |
| // we only process the messages associated with the arriving token, and keep the |
| // others enqueued. |
| TEST_F(FrameTokenMessageQueueTest, DifferentFrameTokensEnqueuedNonIPC) { |
| FrameTokenMessageQueue* queue = frame_token_message_queue(); |
| TestFrameTokenMessageQueueClient* client = test_client(); |
| TestNonIPCMessageEnqueuer* enqueuer = test_non_ipc_enqueuer(); |
| ASSERT_EQ(0u, queue->size()); |
| |
| const uint32_t frame_token_1 = 42; |
| queue->EnqueueOrRunFrameTokenCallback( |
| frame_token_1, |
| base::BindOnce(&TestNonIPCMessageEnqueuer::FrameTokenCallback, |
| base::Unretained(enqueuer))); |
| EXPECT_FALSE(enqueuer->frame_token_callback_called()); |
| EXPECT_EQ(1u, queue->size()); |
| |
| // Create a second callback |
| const uint32_t frame_token_2 = 1337; |
| TestNonIPCMessageEnqueuer second_enqueuer; |
| queue->EnqueueOrRunFrameTokenCallback( |
| frame_token_2, |
| base::BindOnce(&TestNonIPCMessageEnqueuer::FrameTokenCallback, |
| base::Unretained(&second_enqueuer))); |
| EXPECT_FALSE(second_enqueuer.frame_token_callback_called()); |
| EXPECT_EQ(2u, queue->size()); |
| |
| queue->DidProcessFrame(frame_token_1); |
| EXPECT_EQ(1u, queue->size()); |
| EXPECT_FALSE(client->invalid_frame_token_called()); |
| EXPECT_TRUE(enqueuer->frame_token_callback_called()); |
| EXPECT_FALSE(second_enqueuer.frame_token_callback_called()); |
| |
| queue->DidProcessFrame(frame_token_2); |
| EXPECT_TRUE(second_enqueuer.frame_token_callback_called()); |
| } |
| |
| // An empty frame token is considered invalid, so this tests that attempting to |
| // enqueue for that is rejected. |
| TEST_F(FrameTokenMessageQueueTest, EmptyTokenForIPCMessageIsRejected) { |
| FrameTokenMessageQueue* queue = frame_token_message_queue(); |
| TestFrameTokenMessageQueueClient* client = test_client(); |
| ASSERT_EQ(0u, queue->size()); |
| |
| const uint32_t invalid_frame_token = 0; |
| IPC::Message msg(0, 1, IPC::Message::PRIORITY_NORMAL); |
| std::vector<IPC::Message> messages; |
| messages.push_back(msg); |
| |
| // Adding to the queue with a new frame token should not cause processing. |
| queue->OnFrameSwapMessagesReceived(invalid_frame_token, std::move(messages)); |
| EXPECT_EQ(0u, queue->size()); |
| EXPECT_TRUE(client->invalid_frame_token_called()); |
| EXPECT_EQ(invalid_frame_token, client->invalid_frame_token()); |
| EXPECT_EQ(0, client->on_process_swap_message_count()); |
| } |
| |
| // Tests that when adding an IPC::Message for an earlier frame token, that it is |
| // enqueued. |
| TEST_F(FrameTokenMessageQueueTest, EarlierTokenForIPCMessageIsNotRejected) { |
| FrameTokenMessageQueue* queue = frame_token_message_queue(); |
| TestFrameTokenMessageQueueClient* client = test_client(); |
| ASSERT_EQ(0u, queue->size()); |
| |
| const uint32_t valid_frame_token = 42; |
| IPC::Message msg1(0, 1, IPC::Message::PRIORITY_NORMAL); |
| std::vector<IPC::Message> messages_1; |
| messages_1.push_back(msg1); |
| |
| // Adding to the queue with a new frame token should not cause processing. |
| queue->OnFrameSwapMessagesReceived(valid_frame_token, std::move(messages_1)); |
| EXPECT_EQ(1u, queue->size()); |
| EXPECT_EQ(0, client->on_process_swap_message_count()); |
| |
| const uint32_t earlier_frame_token = 1; |
| IPC::Message msg2(1, 2, IPC::Message::PRIORITY_NORMAL); |
| std::vector<IPC::Message> messages_2; |
| messages_2.push_back(msg1); |
| |
| // Adding an earlier frame token should be enqueued. |
| queue->OnFrameSwapMessagesReceived(earlier_frame_token, |
| std::move(messages_2)); |
| EXPECT_EQ(2u, queue->size()); |
| EXPECT_FALSE(client->invalid_frame_token_called()); |
| EXPECT_EQ(0, client->on_process_swap_message_count()); |
| } |
| |
| // Tests that if DidProcessFrame is called with an invalid token, that it is |
| // rejected, and that no callbacks are processed. |
| TEST_F(FrameTokenMessageQueueTest, InvalidDidProcessFrameTokenNotProcessed) { |
| FrameTokenMessageQueue* queue = frame_token_message_queue(); |
| TestFrameTokenMessageQueueClient* client = test_client(); |
| TestNonIPCMessageEnqueuer* enqueuer = test_non_ipc_enqueuer(); |
| ASSERT_EQ(0u, queue->size()); |
| |
| const uint32_t frame_token = 42; |
| IPC::Message msg(0, 1, IPC::Message::PRIORITY_NORMAL); |
| std::vector<IPC::Message> messages; |
| messages.push_back(msg); |
| |
| queue->OnFrameSwapMessagesReceived(frame_token, std::move(messages)); |
| EXPECT_EQ(1u, queue->size()); |
| EXPECT_EQ(0, client->on_process_swap_message_count()); |
| |
| queue->EnqueueOrRunFrameTokenCallback( |
| frame_token, |
| base::BindOnce(&TestNonIPCMessageEnqueuer::FrameTokenCallback, |
| base::Unretained(enqueuer))); |
| EXPECT_FALSE(enqueuer->frame_token_callback_called()); |
| EXPECT_FALSE(client->invalid_frame_token_called()); |
| |
| // Empty token should be invalid even with no process frames processed. |
| const uint32_t invalid_frame_token = 0; |
| queue->DidProcessFrame(invalid_frame_token); |
| EXPECT_EQ(2u, queue->size()); |
| EXPECT_TRUE(client->invalid_frame_token_called()); |
| EXPECT_EQ(invalid_frame_token, client->invalid_frame_token()); |
| EXPECT_EQ(0, client->on_process_swap_message_count()); |
| EXPECT_EQ(0, client->on_message_dispatch_error_count()); |
| EXPECT_FALSE(enqueuer->frame_token_callback_called()); |
| } |
| |
| // Test that if DidProcessFrame is called with an earlier frame token, that it |
| // is rejected, and that no callbacks are processed. |
| TEST_F(FrameTokenMessageQueueTest, EarlierTokenForDidProcessFrameRejected) { |
| FrameTokenMessageQueue* queue = frame_token_message_queue(); |
| TestFrameTokenMessageQueueClient* client = test_client(); |
| TestNonIPCMessageEnqueuer* enqueuer = test_non_ipc_enqueuer(); |
| ASSERT_EQ(0u, queue->size()); |
| |
| // Settings a low value frame token will not block enqueueing. |
| const uint32_t earlier_frame_token = 42; |
| queue->DidProcessFrame(earlier_frame_token); |
| |
| const uint32_t frame_token = 1337; |
| IPC::Message msg(0, 1, IPC::Message::PRIORITY_NORMAL); |
| std::vector<IPC::Message> messages; |
| messages.push_back(msg); |
| |
| queue->OnFrameSwapMessagesReceived(frame_token, std::move(messages)); |
| EXPECT_EQ(1u, queue->size()); |
| EXPECT_EQ(0, client->on_process_swap_message_count()); |
| |
| queue->EnqueueOrRunFrameTokenCallback( |
| frame_token, |
| base::BindOnce(&TestNonIPCMessageEnqueuer::FrameTokenCallback, |
| base::Unretained(enqueuer))); |
| EXPECT_FALSE(enqueuer->frame_token_callback_called()); |
| EXPECT_FALSE(client->invalid_frame_token_called()); |
| |
| // Using a frame token that is earlier than the last received should be |
| // rejected. |
| const uint32_t invalid_frame_token = earlier_frame_token - 1; |
| queue->DidProcessFrame(invalid_frame_token); |
| EXPECT_EQ(2u, queue->size()); |
| EXPECT_TRUE(client->invalid_frame_token_called()); |
| EXPECT_EQ(invalid_frame_token, client->invalid_frame_token()); |
| EXPECT_EQ(0, client->on_process_swap_message_count()); |
| EXPECT_EQ(0, client->on_message_dispatch_error_count()); |
| EXPECT_FALSE(enqueuer->frame_token_callback_called()); |
| } |
| |
| // Tests that if an IPC::Message has a dispatch error that the client is |
| // notified. |
| TEST_F(FrameTokenMessageQueueTest, DispatchError) { |
| FrameTokenMessageQueue* queue = frame_token_message_queue(); |
| TestFrameTokenMessageQueueClient* client = test_client(); |
| ASSERT_EQ(0u, queue->size()); |
| |
| const uint32_t frame_token = 42; |
| IPC::Message msg(0, 1, IPC::Message::PRIORITY_NORMAL); |
| std::vector<IPC::Message> messages; |
| messages.push_back(msg); |
| |
| queue->OnFrameSwapMessagesReceived(frame_token, std::move(messages)); |
| EXPECT_EQ(1u, queue->size()); |
| EXPECT_EQ(0, client->on_process_swap_message_count()); |
| |
| // Dispatch error should be notified during processing. |
| client->SetErrorOnMessageProcess(); |
| queue->DidProcessFrame(frame_token); |
| EXPECT_EQ(0u, queue->size()); |
| EXPECT_FALSE(client->invalid_frame_token_called()); |
| EXPECT_EQ(1, client->on_process_swap_message_count()); |
| EXPECT_EQ(1, client->on_message_dispatch_error_count()); |
| } |
| |
| // Tests that if we have already enqueued a callback for a frame token, that if |
| // a request for an earlier frame token arrives, that it is still enqueued. Then |
| // once the large frame token arrives, both are processed. |
| TEST_F(FrameTokenMessageQueueTest, OutOfOrderFrameTokensEnqueue) { |
| FrameTokenMessageQueue* queue = frame_token_message_queue(); |
| TestFrameTokenMessageQueueClient* client = test_client(); |
| TestNonIPCMessageEnqueuer* enqueuer = test_non_ipc_enqueuer(); |
| ASSERT_EQ(0u, queue->size()); |
| |
| const uint32_t larger_frame_token = 1337; |
| queue->EnqueueOrRunFrameTokenCallback( |
| larger_frame_token, |
| base::BindOnce(&TestNonIPCMessageEnqueuer::FrameTokenCallback, |
| base::Unretained(enqueuer))); |
| EXPECT_EQ(1u, queue->size()); |
| EXPECT_FALSE(enqueuer->frame_token_callback_called()); |
| EXPECT_FALSE(client->invalid_frame_token_called()); |
| |
| const uint32_t smaller_frame_token = 42; |
| IPC::Message msg(0, 1, IPC::Message::PRIORITY_NORMAL); |
| std::vector<IPC::Message> messages; |
| messages.push_back(msg); |
| |
| // Enqueuing for a smaller token, which has not yet arrived, should still |
| // enqueue. |
| queue->OnFrameSwapMessagesReceived(smaller_frame_token, std::move(messages)); |
| EXPECT_EQ(2u, queue->size()); |
| EXPECT_EQ(0, client->on_process_swap_message_count()); |
| |
| // Process both with the larger frame token arriving. |
| queue->DidProcessFrame(larger_frame_token); |
| EXPECT_EQ(0u, queue->size()); |
| EXPECT_FALSE(client->invalid_frame_token_called()); |
| EXPECT_EQ(1, client->on_process_swap_message_count()); |
| EXPECT_EQ(0, client->on_message_dispatch_error_count()); |
| EXPECT_TRUE(enqueuer->frame_token_callback_called()); |
| } |
| |
| } // namespace content |