blob: f06a1e9fb1add59c6fe03a50bbbc52760dd188b4 [file] [log] [blame]
// 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 "chrome/browser/chromeos/android_sms/fcm_connection_establisher.h"
#include <utility>
#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/chromeos/android_sms/android_sms_urls.h"
#include "content/public/test/fake_service_worker_context.h"
#include "content/public/test/test_browser_thread_bundle.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 chromeos {
namespace android_sms {
class FcmConnectionEstablisherTest : public testing::Test {
protected:
FcmConnectionEstablisherTest()
: thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
~FcmConnectionEstablisherTest() override = default;
void VerifyTransferrableMessage(
const char* expected,
const content::FakeServiceWorkerContext::
StartServiceWorkerAndDispatchMessageArgs& call_args) {
base::string16 message_string;
blink::DecodeStringMessage(
std::get<blink::TransferableMessage>(call_args).owned_encoded_message,
&message_string);
EXPECT_EQ(base::UTF8ToUTF16(expected), message_string);
}
private:
content::TestBrowserThreadBundle thread_bundle_;
DISALLOW_COPY_AND_ASSIGN(FcmConnectionEstablisherTest);
};
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,
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,
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,
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,
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::Sample>(
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,
message_dispatch_calls[0]);
}
} // namespace android_sms
} // namespace chromeos