| // Copyright 2018 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ash/android_sms/fcm_connection_establisher.h" |
| |
| #include <utility> |
| #include <variant> |
| |
| #include "base/run_loop.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "base/timer/mock_timer.h" |
| #include "chrome/browser/ash/android_sms/android_sms_urls.h" |
| #include "content/public/test/browser_task_environment.h" |
| #include "content/public/test/fake_service_worker_context.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/blink/public/common/messaging/string_message_codec.h" |
| #include "third_party/blink/public/common/messaging/transferable_message.h" |
| |
| namespace ash { |
| namespace android_sms { |
| |
| class FcmConnectionEstablisherTest : public testing::Test { |
| public: |
| FcmConnectionEstablisherTest(const FcmConnectionEstablisherTest&) = delete; |
| FcmConnectionEstablisherTest& operator=(const FcmConnectionEstablisherTest&) = |
| delete; |
| |
| protected: |
| FcmConnectionEstablisherTest() |
| : task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP) {} |
| ~FcmConnectionEstablisherTest() override = default; |
| |
| void VerifyTransferrableMessage(const char* expected, |
| blink::TransferableMessage message) { |
| auto payload = blink::DecodeToWebMessagePayload(std::move(message)); |
| EXPECT_EQ(base::UTF8ToUTF16(expected), |
| std::get<std::u16string>(payload.value())); |
| } |
| |
| private: |
| content::BrowserTaskEnvironment task_environment_; |
| }; |
| |
| TEST_F(FcmConnectionEstablisherTest, TestEstablishConnection) { |
| auto mock_retry_timer = std::make_unique<base::MockOneShotTimer>(); |
| base::MockOneShotTimer* mock_retry_timer_ptr = mock_retry_timer.get(); |
| base::HistogramTester histogram_tester; |
| |
| content::FakeServiceWorkerContext fake_service_worker_context; |
| FcmConnectionEstablisher fcm_connection_establisher( |
| std::move(mock_retry_timer)); |
| auto& message_dispatch_calls = |
| fake_service_worker_context |
| .start_service_worker_and_dispatch_message_calls(); |
| |
| // Verify that message is dispatch to service worker. |
| fcm_connection_establisher.EstablishConnection( |
| GetAndroidMessagesURL(), |
| ConnectionEstablisher::ConnectionMode::kStartConnection, |
| &fake_service_worker_context); |
| base::RunLoop().RunUntilIdle(); |
| ASSERT_EQ(1u, message_dispatch_calls.size()); |
| EXPECT_EQ(GetAndroidMessagesURL(), std::get<GURL>(message_dispatch_calls[0])); |
| VerifyTransferrableMessage(FcmConnectionEstablisher::kStartFcmMessage, |
| std::move(std::get<blink::TransferableMessage>( |
| message_dispatch_calls[0]))); |
| |
| // Return success to result callback and verify that no retries are attempted |
| // and success histogram is recorded. |
| std::move(std::get<content::ServiceWorkerContext::ResultCallback>( |
| message_dispatch_calls[0])) |
| .Run(true /* status */); |
| ASSERT_EQ(1u, message_dispatch_calls.size()); |
| EXPECT_FALSE(mock_retry_timer_ptr->IsRunning()); |
| histogram_tester.ExpectBucketCount( |
| "AndroidSms.FcmMessageDispatchSuccess", |
| FcmConnectionEstablisher::MessageType::kStart, 1); |
| |
| // Verify that when multiple requests are sent only the first one is |
| // dispatched while the others are queued. |
| fcm_connection_establisher.EstablishConnection( |
| GetAndroidMessagesURL(), |
| ConnectionEstablisher::ConnectionMode::kStartConnection, |
| &fake_service_worker_context); |
| fcm_connection_establisher.EstablishConnection( |
| GetAndroidMessagesURL(), |
| ConnectionEstablisher::ConnectionMode::kResumeExistingConnection, |
| &fake_service_worker_context); |
| base::RunLoop().RunUntilIdle(); |
| ASSERT_EQ(2u, message_dispatch_calls.size()); |
| VerifyTransferrableMessage(FcmConnectionEstablisher::kStartFcmMessage, |
| std::move(std::get<blink::TransferableMessage>( |
| message_dispatch_calls[1]))); |
| |
| // Verify that if the first request fails then it's retried |
| std::move(std::get<content::ServiceWorkerContext::ResultCallback>( |
| message_dispatch_calls[1])) |
| .Run(false /* status */); |
| ASSERT_EQ(2u, message_dispatch_calls.size()); |
| EXPECT_TRUE(mock_retry_timer_ptr->IsRunning()); |
| // Retry shouldn't count success. |
| histogram_tester.ExpectBucketCount( |
| "AndroidSms.FcmMessageDispatchSuccess", |
| FcmConnectionEstablisher::MessageType::kStart, 1); |
| mock_retry_timer_ptr->Fire(); |
| ASSERT_EQ(3u, message_dispatch_calls.size()); |
| VerifyTransferrableMessage(FcmConnectionEstablisher::kStartFcmMessage, |
| std::move(std::get<blink::TransferableMessage>( |
| message_dispatch_calls[2]))); |
| |
| // Verify that if the first request succeeds then the next message is |
| // dispatched |
| std::move(std::get<content::ServiceWorkerContext::ResultCallback>( |
| message_dispatch_calls[2])) |
| .Run(true /* status */); |
| ASSERT_EQ(4u, message_dispatch_calls.size()); |
| EXPECT_FALSE(mock_retry_timer_ptr->IsRunning()); |
| VerifyTransferrableMessage(FcmConnectionEstablisher::kResumeFcmMessage, |
| std::move(std::get<blink::TransferableMessage>( |
| message_dispatch_calls[3]))); |
| |
| // Complete second request and verify that no more retries are scheduled. |
| std::move(std::get<content::ServiceWorkerContext::ResultCallback>( |
| message_dispatch_calls[3])) |
| .Run(true /* status */); |
| EXPECT_FALSE(mock_retry_timer_ptr->IsRunning()); |
| |
| // Verify that max retries are attempted before abandoning request |
| fcm_connection_establisher.EstablishConnection( |
| GetAndroidMessagesURL(), |
| ConnectionEstablisher::ConnectionMode::kStartConnection, |
| &fake_service_worker_context); |
| base::RunLoop().RunUntilIdle(); |
| |
| int last_retry_bucket_count = histogram_tester.GetBucketCount( |
| "AndroidSms.FcmMessageDispatchRetry", |
| static_cast<base::HistogramBase::Sample32>( |
| FcmConnectionEstablisher::MessageType::kStart)); |
| |
| int retry_count = 0; |
| while (true) { |
| ASSERT_EQ(5u + retry_count, message_dispatch_calls.size()); |
| std::move(std::get<content::ServiceWorkerContext::ResultCallback>( |
| message_dispatch_calls[4 + retry_count])) |
| .Run(false /* status */); |
| if (mock_retry_timer_ptr->IsRunning()) { |
| mock_retry_timer_ptr->Fire(); |
| retry_count++; |
| } else { |
| break; |
| } |
| } |
| |
| EXPECT_EQ(FcmConnectionEstablisher::kMaxRetryCount, retry_count); |
| histogram_tester.ExpectBucketCount( |
| "AndroidSms.FcmMessageDispatchRetry", |
| FcmConnectionEstablisher::MessageType::kStart, |
| retry_count + last_retry_bucket_count); |
| histogram_tester.ExpectBucketCount( |
| "AndroidSms.FcmMessageDispatchFailure", |
| FcmConnectionEstablisher::MessageType::kStart, 1); |
| } |
| |
| TEST_F(FcmConnectionEstablisherTest, TestTearDownConnection) { |
| content::FakeServiceWorkerContext fake_service_worker_context; |
| FcmConnectionEstablisher fcm_connection_establisher( |
| std::make_unique<base::MockOneShotTimer>()); |
| auto& message_dispatch_calls = |
| fake_service_worker_context |
| .start_service_worker_and_dispatch_message_calls(); |
| |
| // Verify that message is dispatch to service worker. |
| fcm_connection_establisher.TearDownConnection(GetAndroidMessagesURL(), |
| &fake_service_worker_context); |
| base::RunLoop().RunUntilIdle(); |
| ASSERT_EQ(1u, message_dispatch_calls.size()); |
| EXPECT_EQ(GetAndroidMessagesURL(), std::get<GURL>(message_dispatch_calls[0])); |
| VerifyTransferrableMessage(FcmConnectionEstablisher::kStopFcmMessage, |
| std::move(std::get<blink::TransferableMessage>( |
| message_dispatch_calls[0]))); |
| } |
| |
| } // namespace android_sms |
| } // namespace ash |