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