1 // Copyright 2015 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/ui/webui/sync_internals_message_handler.h"
6
7 #include <memory>
8 #include <utility>
9
10 #include "base/bind.h"
11 #include "base/command_line.h"
12 #include "chrome/browser/sync/profile_sync_service_factory.h"
13 #include "chrome/browser/sync/user_event_service_factory.h"
14 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
15 #include "chrome/test/base/testing_profile.h"
16 #include "components/sync/driver/about_sync_util.h"
17 #include "components/sync/driver/fake_sync_service.h"
18 #include "components/sync/driver/sync_service.h"
19 #include "components/sync/js/js_test_util.h"
20 #include "components/sync_user_events/fake_user_event_service.h"
21 #include "content/public/browser/site_instance.h"
22 #include "content/public/browser/web_contents.h"
23 #include "content/public/test/test_web_ui.h"
24
25 using base::DictionaryValue;
26 using base::ListValue;
27 using base::Value;
28 using sync_pb::UserEventSpecifics;
29 using syncer::FakeUserEventService;
30 using syncer::SyncService;
31 using syncer::SyncServiceObserver;
32 using syncer::TypeDebugInfoObserver;
33
34 namespace {
35
36 class TestableSyncInternalsMessageHandler : public SyncInternalsMessageHandler {
37 public:
TestableSyncInternalsMessageHandler(content::WebUI * web_ui,AboutSyncDataDelegate about_sync_data_delegate)38 TestableSyncInternalsMessageHandler(
39 content::WebUI* web_ui,
40 AboutSyncDataDelegate about_sync_data_delegate)
41 : SyncInternalsMessageHandler(std::move(about_sync_data_delegate)) {
42 set_web_ui(web_ui);
43 }
44 };
45
46 class TestSyncService : public syncer::FakeSyncService {
47 public:
AddObserver(SyncServiceObserver * observer)48 void AddObserver(SyncServiceObserver* observer) override {
49 ++add_observer_count_;
50 }
51
RemoveObserver(SyncServiceObserver * observer)52 void RemoveObserver(SyncServiceObserver* observer) override {
53 ++remove_observer_count_;
54 }
55
AddTypeDebugInfoObserver(TypeDebugInfoObserver * observer)56 void AddTypeDebugInfoObserver(TypeDebugInfoObserver* observer) override {
57 ++add_type_debug_info_observer_count_;
58 }
59
RemoveTypeDebugInfoObserver(TypeDebugInfoObserver * observer)60 void RemoveTypeDebugInfoObserver(TypeDebugInfoObserver* observer) override {
61 ++remove_type_debug_info_observer_count_;
62 }
63
GetJsController()64 base::WeakPtr<syncer::JsController> GetJsController() override {
65 return js_controller_.AsWeakPtr();
66 }
67
GetAllNodesForDebugging(base::OnceCallback<void (std::unique_ptr<base::ListValue>)> callback)68 void GetAllNodesForDebugging(
69 base::OnceCallback<void(std::unique_ptr<base::ListValue>)> callback)
70 override {
71 get_all_nodes_callback_ = std::move(callback);
72 }
73
add_observer_count() const74 int add_observer_count() const { return add_observer_count_; }
remove_observer_count() const75 int remove_observer_count() const { return remove_observer_count_; }
add_type_debug_info_observer_count() const76 int add_type_debug_info_observer_count() const {
77 return add_type_debug_info_observer_count_;
78 }
remove_type_debug_info_observer_count() const79 int remove_type_debug_info_observer_count() const {
80 return remove_type_debug_info_observer_count_;
81 }
82 base::OnceCallback<void(std::unique_ptr<base::ListValue>)>
get_all_nodes_callback()83 get_all_nodes_callback() {
84 return std::move(get_all_nodes_callback_);
85 }
86
87 private:
88 int add_observer_count_ = 0;
89 int remove_observer_count_ = 0;
90 int add_type_debug_info_observer_count_ = 0;
91 int remove_type_debug_info_observer_count_ = 0;
92 syncer::MockJsController js_controller_;
93 base::OnceCallback<void(std::unique_ptr<base::ListValue>)>
94 get_all_nodes_callback_;
95 };
96
BuildTestSyncService(content::BrowserContext * context)97 static std::unique_ptr<KeyedService> BuildTestSyncService(
98 content::BrowserContext* context) {
99 return std::make_unique<TestSyncService>();
100 }
101
BuildFakeUserEventService(content::BrowserContext * context)102 static std::unique_ptr<KeyedService> BuildFakeUserEventService(
103 content::BrowserContext* context) {
104 return std::make_unique<FakeUserEventService>();
105 }
106
107 class SyncInternalsMessageHandlerTest : public ChromeRenderViewHostTestHarness {
108 protected:
109 SyncInternalsMessageHandlerTest() = default;
110 ~SyncInternalsMessageHandlerTest() override = default;
111
SetUp()112 void SetUp() override {
113 ChromeRenderViewHostTestHarness::SetUp();
114
115 web_ui_.set_web_contents(web_contents());
116 test_sync_service_ = static_cast<TestSyncService*>(
117 ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
118 profile(), base::BindRepeating(&BuildTestSyncService)));
119 fake_user_event_service_ = static_cast<FakeUserEventService*>(
120 browser_sync::UserEventServiceFactory::GetInstance()
121 ->SetTestingFactoryAndUse(
122 profile(), base::BindRepeating(&BuildFakeUserEventService)));
123 handler_ = std::make_unique<TestableSyncInternalsMessageHandler>(
124 &web_ui_,
125 base::BindRepeating(
126 &SyncInternalsMessageHandlerTest::ConstructAboutInformation,
127 base::Unretained(this)));
128 }
129
TearDown()130 void TearDown() override {
131 // Destroy |handler_| before |web_contents()|.
132 handler_ = nullptr;
133 ChromeRenderViewHostTestHarness::TearDown();
134 }
135
ConstructAboutInformation(SyncService * service,version_info::Channel channel)136 std::unique_ptr<DictionaryValue> ConstructAboutInformation(
137 SyncService* service,
138 version_info::Channel channel) {
139 ++about_sync_data_delegate_call_count_;
140 last_delegate_sync_service_ = service;
141 auto dictionary = std::make_unique<DictionaryValue>();
142 dictionary->SetString("fake_key", "fake_value");
143 return dictionary;
144 }
145
ValidateAboutInfoCall()146 void ValidateAboutInfoCall() {
147 const auto& data_vector = web_ui_.call_data();
148 ASSERT_FALSE(data_vector.empty());
149 EXPECT_EQ(1u, data_vector.size());
150
151 const content::TestWebUI::CallData& call_data = *data_vector[0];
152
153 EXPECT_EQ(syncer::sync_ui_util::kDispatchEvent, call_data.function_name());
154
155 const Value* arg1 = call_data.arg1();
156 ASSERT_TRUE(arg1);
157 std::string event_type;
158 EXPECT_TRUE(arg1->GetAsString(&event_type));
159 EXPECT_EQ(syncer::sync_ui_util::kOnAboutInfoUpdated, event_type);
160
161 const Value* arg2 = call_data.arg2();
162 ASSERT_TRUE(arg2);
163
164 const DictionaryValue* root_dictionary = nullptr;
165 ASSERT_TRUE(arg2->GetAsDictionary(&root_dictionary));
166
167 std::string fake_value;
168 EXPECT_TRUE(root_dictionary->GetString("fake_key", &fake_value));
169 EXPECT_EQ("fake_value", fake_value);
170 }
171
ValidateEmptyAboutInfoCall()172 void ValidateEmptyAboutInfoCall() {
173 EXPECT_TRUE(web_ui_.call_data().empty());
174 }
175
test_sync_service()176 TestSyncService* test_sync_service() { return test_sync_service_; }
177
fake_user_event_service()178 FakeUserEventService* fake_user_event_service() {
179 return fake_user_event_service_;
180 }
181
handler()182 TestableSyncInternalsMessageHandler* handler() { return handler_.get(); }
183
CallCountWithName(const std::string & function_name)184 int CallCountWithName(const std::string& function_name) {
185 int count = 0;
186 for (const auto& call_data : web_ui_.call_data()) {
187 if (call_data->function_name() == function_name) {
188 count++;
189 }
190 }
191 return count;
192 }
193
about_sync_data_delegate_call_count() const194 int about_sync_data_delegate_call_count() const {
195 return about_sync_data_delegate_call_count_;
196 }
197
last_delegate_sync_service() const198 const SyncService* last_delegate_sync_service() const {
199 return last_delegate_sync_service_;
200 }
201
ResetHandler()202 void ResetHandler() { handler_.reset(); }
203
204 private:
205 content::TestWebUI web_ui_;
206 TestSyncService* test_sync_service_;
207 FakeUserEventService* fake_user_event_service_;
208 std::unique_ptr<TestableSyncInternalsMessageHandler> handler_;
209 int about_sync_data_delegate_call_count_ = 0;
210 SyncService* last_delegate_sync_service_ = nullptr;
211
212 DISALLOW_COPY_AND_ASSIGN(SyncInternalsMessageHandlerTest);
213 };
214
TEST_F(SyncInternalsMessageHandlerTest,AddRemoveObservers)215 TEST_F(SyncInternalsMessageHandlerTest, AddRemoveObservers) {
216 ListValue empty_list;
217
218 EXPECT_EQ(0, test_sync_service()->add_observer_count());
219 handler()->HandleRegisterForEvents(&empty_list);
220 EXPECT_EQ(1, test_sync_service()->add_observer_count());
221
222 EXPECT_EQ(0, test_sync_service()->add_type_debug_info_observer_count());
223 handler()->HandleRegisterForPerTypeCounters(&empty_list);
224 EXPECT_EQ(1, test_sync_service()->add_type_debug_info_observer_count());
225
226 EXPECT_EQ(0, test_sync_service()->remove_observer_count());
227 EXPECT_EQ(0, test_sync_service()->remove_type_debug_info_observer_count());
228 ResetHandler();
229 EXPECT_EQ(1, test_sync_service()->remove_observer_count());
230 EXPECT_EQ(1, test_sync_service()->remove_type_debug_info_observer_count());
231
232 // Add calls should never have increased since the initial subscription.
233 EXPECT_EQ(1, test_sync_service()->add_observer_count());
234 EXPECT_EQ(1, test_sync_service()->add_type_debug_info_observer_count());
235 }
236
TEST_F(SyncInternalsMessageHandlerTest,AddRemoveObserversDisallowJavascript)237 TEST_F(SyncInternalsMessageHandlerTest, AddRemoveObserversDisallowJavascript) {
238 ListValue empty_list;
239
240 EXPECT_EQ(0, test_sync_service()->add_observer_count());
241 handler()->HandleRegisterForEvents(&empty_list);
242 EXPECT_EQ(1, test_sync_service()->add_observer_count());
243
244 EXPECT_EQ(0, test_sync_service()->add_type_debug_info_observer_count());
245 handler()->HandleRegisterForPerTypeCounters(&empty_list);
246 EXPECT_EQ(1, test_sync_service()->add_type_debug_info_observer_count());
247
248 EXPECT_EQ(0, test_sync_service()->remove_observer_count());
249 EXPECT_EQ(0, test_sync_service()->remove_type_debug_info_observer_count());
250 handler()->DisallowJavascript();
251 EXPECT_EQ(1, test_sync_service()->remove_observer_count());
252 EXPECT_EQ(1, test_sync_service()->remove_type_debug_info_observer_count());
253
254 // Deregistration should not repeat, no counts should increase.
255 ResetHandler();
256 EXPECT_EQ(1, test_sync_service()->add_observer_count());
257 EXPECT_EQ(1, test_sync_service()->add_type_debug_info_observer_count());
258 EXPECT_EQ(1, test_sync_service()->remove_observer_count());
259 EXPECT_EQ(1, test_sync_service()->remove_type_debug_info_observer_count());
260 }
261
TEST_F(SyncInternalsMessageHandlerTest,AddRemoveObserversSyncDisabled)262 TEST_F(SyncInternalsMessageHandlerTest, AddRemoveObserversSyncDisabled) {
263 // Simulate completely disabling sync by flag or other mechanism.
264 ProfileSyncServiceFactory::GetInstance()->SetTestingFactory(
265 profile(), BrowserContextKeyedServiceFactory::TestingFactory());
266
267 ListValue empty_list;
268 handler()->HandleRegisterForEvents(&empty_list);
269 handler()->HandleRegisterForPerTypeCounters(&empty_list);
270 handler()->DisallowJavascript();
271 // Cannot verify observer methods on sync services were not called, because
272 // there is no sync service. Rather, we're just making sure the handler hasn't
273 // performed any invalid operations when the sync service is missing.
274 }
275
TEST_F(SyncInternalsMessageHandlerTest,RepeatedHandleRegisterForPerTypeCounters)276 TEST_F(SyncInternalsMessageHandlerTest,
277 RepeatedHandleRegisterForPerTypeCounters) {
278 ListValue empty_list;
279 handler()->HandleRegisterForPerTypeCounters(&empty_list);
280 EXPECT_EQ(1, test_sync_service()->add_type_debug_info_observer_count());
281 EXPECT_EQ(0, test_sync_service()->remove_type_debug_info_observer_count());
282
283 handler()->HandleRegisterForPerTypeCounters(&empty_list);
284 EXPECT_EQ(2, test_sync_service()->add_type_debug_info_observer_count());
285 EXPECT_EQ(1, test_sync_service()->remove_type_debug_info_observer_count());
286
287 handler()->HandleRegisterForPerTypeCounters(&empty_list);
288 EXPECT_EQ(3, test_sync_service()->add_type_debug_info_observer_count());
289 EXPECT_EQ(2, test_sync_service()->remove_type_debug_info_observer_count());
290
291 ResetHandler();
292 EXPECT_EQ(3, test_sync_service()->add_type_debug_info_observer_count());
293 EXPECT_EQ(3, test_sync_service()->remove_type_debug_info_observer_count());
294 }
295
TEST_F(SyncInternalsMessageHandlerTest,HandleGetAllNodes)296 TEST_F(SyncInternalsMessageHandlerTest, HandleGetAllNodes) {
297 ListValue args;
298 args.AppendInteger(0);
299 handler()->HandleGetAllNodes(&args);
300 test_sync_service()->get_all_nodes_callback().Run(
301 std::make_unique<ListValue>());
302 EXPECT_EQ(1, CallCountWithName(syncer::sync_ui_util::kGetAllNodesCallback));
303
304 handler()->HandleGetAllNodes(&args);
305 // This breaks the weak ref the callback is hanging onto. Which results in
306 // the call count not incrementing.
307 handler()->DisallowJavascript();
308 test_sync_service()->get_all_nodes_callback().Run(
309 std::make_unique<ListValue>());
310 EXPECT_EQ(1, CallCountWithName(syncer::sync_ui_util::kGetAllNodesCallback));
311
312 handler()->HandleGetAllNodes(&args);
313 test_sync_service()->get_all_nodes_callback().Run(
314 std::make_unique<ListValue>());
315 EXPECT_EQ(2, CallCountWithName(syncer::sync_ui_util::kGetAllNodesCallback));
316 }
317
TEST_F(SyncInternalsMessageHandlerTest,SendAboutInfo)318 TEST_F(SyncInternalsMessageHandlerTest, SendAboutInfo) {
319 handler()->AllowJavascriptForTesting();
320 handler()->OnStateChanged(nullptr);
321 EXPECT_EQ(1, about_sync_data_delegate_call_count());
322 EXPECT_NE(nullptr, last_delegate_sync_service());
323 ValidateAboutInfoCall();
324 }
325
TEST_F(SyncInternalsMessageHandlerTest,SendAboutInfoSyncDisabled)326 TEST_F(SyncInternalsMessageHandlerTest, SendAboutInfoSyncDisabled) {
327 // Simulate completely disabling sync by flag or other mechanism.
328 ProfileSyncServiceFactory::GetInstance()->SetTestingFactory(
329 profile(), BrowserContextKeyedServiceFactory::TestingFactory());
330
331 handler()->AllowJavascriptForTesting();
332 handler()->OnStateChanged(nullptr);
333 EXPECT_EQ(1, about_sync_data_delegate_call_count());
334 EXPECT_EQ(nullptr, last_delegate_sync_service());
335 ValidateAboutInfoCall();
336 }
337
TEST_F(SyncInternalsMessageHandlerTest,WriteUserEvent)338 TEST_F(SyncInternalsMessageHandlerTest, WriteUserEvent) {
339 ListValue args;
340 args.AppendString("1000000000000000000");
341 args.AppendString("-1");
342 handler()->HandleWriteUserEvent(&args);
343
344 ASSERT_EQ(1u, fake_user_event_service()->GetRecordedUserEvents().size());
345 const UserEventSpecifics& event =
346 *fake_user_event_service()->GetRecordedUserEvents().begin();
347 EXPECT_EQ(UserEventSpecifics::kTestEvent, event.event_case());
348 EXPECT_EQ(1000000000000000000, event.event_time_usec());
349 EXPECT_EQ(-1, event.navigation_id());
350 }
351
TEST_F(SyncInternalsMessageHandlerTest,WriteUserEventBadParse)352 TEST_F(SyncInternalsMessageHandlerTest, WriteUserEventBadParse) {
353 ListValue args;
354 args.AppendString("123abc");
355 args.AppendString("abcdefghijklmnopqrstuvwxyz");
356 handler()->HandleWriteUserEvent(&args);
357
358 ASSERT_EQ(1u, fake_user_event_service()->GetRecordedUserEvents().size());
359 const UserEventSpecifics& event =
360 *fake_user_event_service()->GetRecordedUserEvents().begin();
361 EXPECT_EQ(UserEventSpecifics::kTestEvent, event.event_case());
362 EXPECT_EQ(0, event.event_time_usec());
363 EXPECT_EQ(0, event.navigation_id());
364 }
365
TEST_F(SyncInternalsMessageHandlerTest,WriteUserEventBlank)366 TEST_F(SyncInternalsMessageHandlerTest, WriteUserEventBlank) {
367 ListValue args;
368 args.AppendString("");
369 args.AppendString("");
370 handler()->HandleWriteUserEvent(&args);
371
372 ASSERT_EQ(1u, fake_user_event_service()->GetRecordedUserEvents().size());
373 const UserEventSpecifics& event =
374 *fake_user_event_service()->GetRecordedUserEvents().begin();
375 EXPECT_EQ(UserEventSpecifics::kTestEvent, event.event_case());
376 EXPECT_TRUE(event.has_event_time_usec());
377 EXPECT_EQ(0, event.event_time_usec());
378 // Should not have a navigation_id because that means something different to
379 // the UserEvents logic.
380 EXPECT_FALSE(event.has_navigation_id());
381 }
382
TEST_F(SyncInternalsMessageHandlerTest,WriteUserEventZero)383 TEST_F(SyncInternalsMessageHandlerTest, WriteUserEventZero) {
384 ListValue args;
385 args.AppendString("0");
386 args.AppendString("0");
387 handler()->HandleWriteUserEvent(&args);
388
389 ASSERT_EQ(1u, fake_user_event_service()->GetRecordedUserEvents().size());
390 const UserEventSpecifics& event =
391 *fake_user_event_service()->GetRecordedUserEvents().begin();
392 EXPECT_EQ(UserEventSpecifics::kTestEvent, event.event_case());
393 EXPECT_TRUE(event.has_event_time_usec());
394 EXPECT_EQ(0, event.event_time_usec());
395 // Should have a navigation_id, even though the value is 0.
396 EXPECT_TRUE(event.has_navigation_id());
397 EXPECT_EQ(0, event.navigation_id());
398 }
399
400 } // namespace
401