1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/chromeos/android_sms/fcm_connection_establisher.h"
6
7 #include <utility>
8
9 #include "base/run_loop.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/test/metrics/histogram_tester.h"
12 #include "base/timer/mock_timer.h"
13 #include "chrome/browser/chromeos/android_sms/android_sms_urls.h"
14 #include "content/public/test/browser_task_environment.h"
15 #include "content/public/test/fake_service_worker_context.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "third_party/blink/public/common/messaging/string_message_codec.h"
18 #include "third_party/blink/public/common/messaging/transferable_message.h"
19
20 namespace chromeos {
21
22 namespace android_sms {
23
24 class FcmConnectionEstablisherTest : public testing::Test {
25 protected:
FcmConnectionEstablisherTest()26 FcmConnectionEstablisherTest()
27 : task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP) {}
28 ~FcmConnectionEstablisherTest() override = default;
29
VerifyTransferrableMessage(const char * expected,const content::FakeServiceWorkerContext::StartServiceWorkerAndDispatchMessageArgs & call_args)30 void VerifyTransferrableMessage(
31 const char* expected,
32 const content::FakeServiceWorkerContext::
33 StartServiceWorkerAndDispatchMessageArgs& call_args) {
34 base::string16 message_string;
35 blink::DecodeStringMessage(
36 std::get<blink::TransferableMessage>(call_args).owned_encoded_message,
37 &message_string);
38 EXPECT_EQ(base::UTF8ToUTF16(expected), message_string);
39 }
40
41 private:
42 content::BrowserTaskEnvironment task_environment_;
43 DISALLOW_COPY_AND_ASSIGN(FcmConnectionEstablisherTest);
44 };
45
TEST_F(FcmConnectionEstablisherTest,TestEstablishConnection)46 TEST_F(FcmConnectionEstablisherTest, TestEstablishConnection) {
47 auto mock_retry_timer = std::make_unique<base::MockOneShotTimer>();
48 base::MockOneShotTimer* mock_retry_timer_ptr = mock_retry_timer.get();
49 base::HistogramTester histogram_tester;
50
51 content::FakeServiceWorkerContext fake_service_worker_context;
52 FcmConnectionEstablisher fcm_connection_establisher(
53 std::move(mock_retry_timer));
54 auto& message_dispatch_calls =
55 fake_service_worker_context
56 .start_service_worker_and_dispatch_message_calls();
57
58 // Verify that message is dispatch to service worker.
59 fcm_connection_establisher.EstablishConnection(
60 GetAndroidMessagesURL(),
61 ConnectionEstablisher::ConnectionMode::kStartConnection,
62 &fake_service_worker_context);
63 base::RunLoop().RunUntilIdle();
64 ASSERT_EQ(1u, message_dispatch_calls.size());
65 EXPECT_EQ(GetAndroidMessagesURL(), std::get<GURL>(message_dispatch_calls[0]));
66 VerifyTransferrableMessage(FcmConnectionEstablisher::kStartFcmMessage,
67 message_dispatch_calls[0]);
68
69 // Return success to result callback and verify that no retries are attempted
70 // and success histogram is recorded.
71 std::move(std::get<content::ServiceWorkerContext::ResultCallback>(
72 message_dispatch_calls[0]))
73 .Run(true /* status */);
74 ASSERT_EQ(1u, message_dispatch_calls.size());
75 EXPECT_FALSE(mock_retry_timer_ptr->IsRunning());
76 histogram_tester.ExpectBucketCount(
77 "AndroidSms.FcmMessageDispatchSuccess",
78 FcmConnectionEstablisher::MessageType::kStart, 1);
79
80 // Verify that when multiple requests are sent only the first one is
81 // dispatched while the others are queued.
82 fcm_connection_establisher.EstablishConnection(
83 GetAndroidMessagesURL(),
84 ConnectionEstablisher::ConnectionMode::kStartConnection,
85 &fake_service_worker_context);
86 fcm_connection_establisher.EstablishConnection(
87 GetAndroidMessagesURL(),
88 ConnectionEstablisher::ConnectionMode::kResumeExistingConnection,
89 &fake_service_worker_context);
90 base::RunLoop().RunUntilIdle();
91 ASSERT_EQ(2u, message_dispatch_calls.size());
92 VerifyTransferrableMessage(FcmConnectionEstablisher::kStartFcmMessage,
93 message_dispatch_calls[1]);
94
95 // Verify that if the first request fails then it's retried
96 std::move(std::get<content::ServiceWorkerContext::ResultCallback>(
97 message_dispatch_calls[1]))
98 .Run(false /* status */);
99 ASSERT_EQ(2u, message_dispatch_calls.size());
100 EXPECT_TRUE(mock_retry_timer_ptr->IsRunning());
101 // Retry shouldn't count success.
102 histogram_tester.ExpectBucketCount(
103 "AndroidSms.FcmMessageDispatchSuccess",
104 FcmConnectionEstablisher::MessageType::kStart, 1);
105 mock_retry_timer_ptr->Fire();
106 ASSERT_EQ(3u, message_dispatch_calls.size());
107 VerifyTransferrableMessage(FcmConnectionEstablisher::kStartFcmMessage,
108 message_dispatch_calls[2]);
109
110 // Verify that if the first request succeeds then the next message is
111 // dispatched
112 std::move(std::get<content::ServiceWorkerContext::ResultCallback>(
113 message_dispatch_calls[2]))
114 .Run(true /* status */);
115 ASSERT_EQ(4u, message_dispatch_calls.size());
116 EXPECT_FALSE(mock_retry_timer_ptr->IsRunning());
117 VerifyTransferrableMessage(FcmConnectionEstablisher::kResumeFcmMessage,
118 message_dispatch_calls[3]);
119
120 // Complete second request and verify that no more retries are scheduled.
121 std::move(std::get<content::ServiceWorkerContext::ResultCallback>(
122 message_dispatch_calls[3]))
123 .Run(true /* status */);
124 EXPECT_FALSE(mock_retry_timer_ptr->IsRunning());
125
126 // Verify that max retries are attempted before abandoning request
127 fcm_connection_establisher.EstablishConnection(
128 GetAndroidMessagesURL(),
129 ConnectionEstablisher::ConnectionMode::kStartConnection,
130 &fake_service_worker_context);
131 base::RunLoop().RunUntilIdle();
132
133 int last_retry_bucket_count = histogram_tester.GetBucketCount(
134 "AndroidSms.FcmMessageDispatchRetry",
135 static_cast<base::HistogramBase::Sample>(
136 FcmConnectionEstablisher::MessageType::kStart));
137
138 int retry_count = 0;
139 while (true) {
140 ASSERT_EQ(5u + retry_count, message_dispatch_calls.size());
141 std::move(std::get<content::ServiceWorkerContext::ResultCallback>(
142 message_dispatch_calls[4 + retry_count]))
143 .Run(false /* status */);
144 if (mock_retry_timer_ptr->IsRunning()) {
145 mock_retry_timer_ptr->Fire();
146 retry_count++;
147 } else {
148 break;
149 }
150 }
151
152 EXPECT_EQ(FcmConnectionEstablisher::kMaxRetryCount, retry_count);
153 histogram_tester.ExpectBucketCount(
154 "AndroidSms.FcmMessageDispatchRetry",
155 FcmConnectionEstablisher::MessageType::kStart,
156 retry_count + last_retry_bucket_count);
157 histogram_tester.ExpectBucketCount(
158 "AndroidSms.FcmMessageDispatchFailure",
159 FcmConnectionEstablisher::MessageType::kStart, 1);
160 }
161
TEST_F(FcmConnectionEstablisherTest,TestTearDownConnection)162 TEST_F(FcmConnectionEstablisherTest, TestTearDownConnection) {
163 content::FakeServiceWorkerContext fake_service_worker_context;
164 FcmConnectionEstablisher fcm_connection_establisher(
165 std::make_unique<base::MockOneShotTimer>());
166 auto& message_dispatch_calls =
167 fake_service_worker_context
168 .start_service_worker_and_dispatch_message_calls();
169
170 // Verify that message is dispatch to service worker.
171 fcm_connection_establisher.TearDownConnection(GetAndroidMessagesURL(),
172 &fake_service_worker_context);
173 base::RunLoop().RunUntilIdle();
174 ASSERT_EQ(1u, message_dispatch_calls.size());
175 EXPECT_EQ(GetAndroidMessagesURL(), std::get<GURL>(message_dispatch_calls[0]));
176 VerifyTransferrableMessage(FcmConnectionEstablisher::kStopFcmMessage,
177 message_dispatch_calls[0]);
178 }
179
180 } // namespace android_sms
181
182 } // namespace chromeos
183