1 // Copyright (c) 2012 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.
9 #include "base/bind_helpers.h"
10 #include "base/callback.h"
11 #include "base/compiler_specific.h"
12 #include "base/location.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/message_loop.h"
15 #include "base/scoped_temp_dir.h"
16 #include "base/stl_util.h"
17 #include "base/time.h"
18 #include "chrome/browser/sessions/session_types_test_helper.h"
19 #include "chrome/browser/signin/signin_manager.h"
20 #include "chrome/browser/signin/signin_manager_factory.h"
21 #include "chrome/browser/signin/token_service_factory.h"
22 #include "chrome/browser/sync/abstract_profile_sync_service_test.h"
23 #include "chrome/browser/sync/glue/session_change_processor.h"
24 #include "chrome/browser/sync/glue/session_data_type_controller.h"
25 #include "chrome/browser/sync/glue/session_model_associator.h"
26 #include "chrome/browser/sync/glue/sync_backend_host.h"
27 #include "chrome/browser/sync/profile_sync_components_factory_mock.h"
28 #include "chrome/browser/sync/profile_sync_service_factory.h"
29 #include "chrome/browser/sync/profile_sync_test_util.h"
30 #include "chrome/browser/sync/test_profile_sync_service.h"
31 #include "chrome/common/chrome_notification_types.h"
32 #include "chrome/test/base/browser_with_test_window_test.h"
33 #include "chrome/test/base/testing_profile.h"
34 #include "content/public/browser/navigation_entry.h"
35 #include "content/public/browser/notification_observer.h"
36 #include "content/public/browser/notification_registrar.h"
37 #include "content/public/browser/notification_service.h"
38 #include "content/public/test/test_browser_thread.h"
39 #include "google_apis/gaia/gaia_constants.h"
40 #include "googleurl/src/gurl.h"
41 #include "sync/internal_api/public/base/model_type.h"
42 #include "sync/internal_api/public/change_record.h"
43 #include "sync/internal_api/public/read_node.h"
44 #include "sync/internal_api/public/read_transaction.h"
45 #include "sync/internal_api/public/test/test_user_share.h"
46 #include "sync/internal_api/public/write_node.h"
47 #include "sync/internal_api/public/write_transaction.h"
48 #include "sync/protocol/session_specifics.pb.h"
49 #include "sync/protocol/sync.pb.h"
50 #include "testing/gmock/include/gmock/gmock.h"
51 #include "testing/gtest/include/gtest/gtest.h"
52 #include "ui/base/ui_base_types.h"
54 using browser_sync::SessionChangeProcessor
;
55 using browser_sync::SessionDataTypeController
;
56 using browser_sync::SessionModelAssociator
;
57 using browser_sync::SyncBackendHost
;
58 using content::BrowserThread
;
59 using syncer::ChangeRecord
;
61 using testing::Return
;
62 using syncer::TestIdFactory
;
64 namespace browser_sync
{
68 void BuildSessionSpecifics(const std::string
& tag
,
69 sync_pb::SessionSpecifics
* meta
) {
70 meta
->set_session_tag(tag
);
71 sync_pb::SessionHeader
* header
= meta
->mutable_header();
72 header
->set_device_type(sync_pb::SyncEnums_DeviceType_TYPE_LINUX
);
73 header
->set_client_name("name");
76 void AddWindowSpecifics(int window_id
,
77 const std::vector
<int>& tab_list
,
78 sync_pb::SessionSpecifics
* meta
) {
79 sync_pb::SessionHeader
* header
= meta
->mutable_header();
80 sync_pb::SessionWindow
* window
= header
->add_window();
81 window
->set_window_id(window_id
);
82 window
->set_selected_tab_index(0);
83 window
->set_browser_type(sync_pb::SessionWindow_BrowserType_TYPE_TABBED
);
84 for (std::vector
<int>::const_iterator iter
= tab_list
.begin();
85 iter
!= tab_list
.end(); ++iter
) {
86 window
->add_tab(*iter
);
90 void BuildTabSpecifics(const std::string
& tag
, int window_id
, int tab_id
,
91 sync_pb::SessionSpecifics
* tab_base
) {
92 tab_base
->set_session_tag(tag
);
93 sync_pb::SessionTab
* tab
= tab_base
->mutable_tab();
94 tab
->set_tab_id(tab_id
);
95 tab
->set_tab_visual_index(1);
96 tab
->set_current_navigation_index(0);
97 tab
->set_pinned(true);
98 tab
->set_extension_app_id("app_id");
99 sync_pb::TabNavigation
* navigation
= tab
->add_navigation();
100 navigation
->set_virtual_url("http://foo/1");
101 navigation
->set_referrer("referrer");
102 navigation
->set_title("title");
103 navigation
->set_page_transition(sync_pb::SyncEnums_PageTransition_TYPED
);
106 // Verifies number of windows, number of tabs, and basic fields.
107 void VerifySyncedSession(
108 const std::string
& tag
,
109 const std::vector
<std::vector
<SessionID::id_type
> >& windows
,
110 const SyncedSession
& session
) {
111 ASSERT_EQ(tag
, session
.session_tag
);
112 ASSERT_EQ(SyncedSession::TYPE_LINUX
, session
.device_type
);
113 ASSERT_EQ("name", session
.session_name
);
114 ASSERT_EQ(windows
.size(), session
.windows
.size());
116 // We assume the window id's are in increasing order.
118 for (std::vector
<std::vector
<int> >::const_iterator win_iter
=
120 win_iter
!= windows
.end(); ++win_iter
, ++i
) {
121 SessionWindow
* win_ptr
;
122 SyncedSession::SyncedWindowMap::const_iterator map_iter
=
123 session
.windows
.find(i
);
124 if (map_iter
!= session
.windows
.end())
125 win_ptr
= map_iter
->second
;
128 ASSERT_EQ(win_iter
->size(), win_ptr
->tabs
.size());
129 ASSERT_EQ(0, win_ptr
->selected_tab_index
);
130 ASSERT_EQ(1, win_ptr
->type
);
132 for (std::vector
<int>::const_iterator tab_iter
= (*win_iter
).begin();
133 tab_iter
!= (*win_iter
).end(); ++tab_iter
, ++j
) {
134 SessionTab
* tab
= win_ptr
->tabs
[j
];
135 ASSERT_EQ(*tab_iter
, tab
->tab_id
.id());
136 ASSERT_EQ(1U, tab
->navigations
.size());
137 ASSERT_EQ(1, tab
->tab_visual_index
);
138 ASSERT_EQ(0, tab
->current_navigation_index
);
139 ASSERT_TRUE(tab
->pinned
);
140 ASSERT_EQ("app_id", tab
->extension_app_id
);
141 ASSERT_EQ(1U, tab
->navigations
.size());
142 ASSERT_EQ(tab
->navigations
[0].virtual_url(), GURL("http://foo/1"));
143 ASSERT_EQ(SessionTypesTestHelper::GetReferrer(tab
->navigations
[0]).url
,
145 ASSERT_EQ(tab
->navigations
[0].title(), string16(ASCIIToUTF16("title")));
146 ASSERT_EQ(SessionTypesTestHelper::GetTransitionType(tab
->navigations
[0]),
147 content::PAGE_TRANSITION_TYPED
);
154 class ProfileSyncServiceSessionTest
155 : public BrowserWithTestWindowTest
,
156 public content::NotificationObserver
{
158 ProfileSyncServiceSessionTest()
159 : io_thread_(BrowserThread::IO
),
160 window_bounds_(0, 1, 2, 3),
161 notified_of_update_(false),
162 notified_of_refresh_(false) {}
163 ProfileSyncService
* sync_service() { return sync_service_
.get(); }
166 virtual TestingProfile
* CreateProfile() OVERRIDE
{
167 TestingProfile
* profile
= new TestingProfile();
168 // Don't want the profile to create a real ProfileSyncService.
169 ProfileSyncServiceFactory::GetInstance()->SetTestingFactory(profile
,
174 virtual void SetUp() {
175 // BrowserWithTestWindowTest implementation.
176 BrowserWithTestWindowTest::SetUp();
177 io_thread_
.StartIOThread();
178 profile()->CreateRequestContext();
179 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
180 registrar_
.Add(this, chrome::NOTIFICATION_FOREIGN_SESSION_UPDATED
,
181 content::NotificationService::AllSources());
182 registrar_
.Add(this, chrome::NOTIFICATION_SYNC_REFRESH_LOCAL
,
183 content::NotificationService::AllSources());
186 void Observe(int type
,
187 const content::NotificationSource
& source
,
188 const content::NotificationDetails
& details
) {
190 case chrome::NOTIFICATION_FOREIGN_SESSION_UPDATED
:
191 notified_of_update_
= true;
193 case chrome::NOTIFICATION_SYNC_REFRESH_LOCAL
:
194 notified_of_refresh_
= true;
202 virtual void TearDown() {
203 sync_service_
->Shutdown();
204 sync_service_
.reset();
205 profile()->ResetRequestContext();
207 // We need to destroy the profile before shutting down the threads, because
208 // some of the ref counted objects in the profile depend on their
209 // destruction on the io thread.
210 DestroyBrowserAndProfile();
213 // Pump messages posted by the sync core thread (which may end up
214 // posting on the IO thread).
215 MessageLoop::current()->RunAllPending();
217 MessageLoop::current()->RunAllPending();
218 BrowserWithTestWindowTest::TearDown();
221 bool StartSyncService(const base::Closure
& callback
,
222 bool will_fail_association
) {
223 if (sync_service_
.get())
225 SigninManager
* signin
= SigninManagerFactory::GetForProfile(profile());
226 signin
->SetAuthenticatedUsername("test_user");
227 ProfileSyncComponentsFactoryMock
* factory
=
228 new ProfileSyncComponentsFactoryMock();
229 sync_service_
.reset(new TestProfileSyncService(
233 ProfileSyncService::AUTO_START
,
237 // Register the session data type.
238 SessionDataTypeController
*dtc
= new SessionDataTypeController(factory
,
240 sync_service_
.get());
241 sync_service_
->RegisterDataTypeController(dtc
);
244 new SessionModelAssociator(sync_service_
.get(),
245 true /* setup_for_test */);
246 change_processor_
= new SessionChangeProcessor(
247 dtc
, model_associator_
,
248 true /* setup_for_test */);
249 EXPECT_CALL(*factory
, CreateSessionSyncComponents(_
, _
)).
250 WillOnce(Return(ProfileSyncComponentsFactory::SyncComponents(
251 model_associator_
, change_processor_
)));
252 EXPECT_CALL(*factory
, CreateDataTypeManager(_
, _
, _
, _
)).
253 WillOnce(ReturnNewDataTypeManager());
255 TokenServiceFactory::GetForProfile(profile())->IssueAuthTokenForTest(
256 GaiaConstants::kSyncService
, "token");
257 sync_service_
->Initialize();
258 MessageLoop::current()->Run();
262 content::TestBrowserThread io_thread_
;
263 // Path used in testing.
264 ScopedTempDir temp_dir_
;
265 SessionModelAssociator
* model_associator_
;
266 SessionChangeProcessor
* change_processor_
;
267 SessionID window_id_
;
268 scoped_ptr
<TestProfileSyncService
> sync_service_
;
269 const gfx::Rect window_bounds_
;
270 bool notified_of_update_
;
271 bool notified_of_refresh_
;
272 content::NotificationRegistrar registrar_
;
275 class CreateRootHelper
{
277 explicit CreateRootHelper(ProfileSyncServiceSessionTest
* test
)
278 : ALLOW_THIS_IN_INITIALIZER_LIST(callback_(
279 base::Bind(&CreateRootHelper::CreateRootCallback
,
280 base::Unretained(this), test
))),
284 virtual ~CreateRootHelper() {}
286 const base::Closure
& callback() const { return callback_
; }
287 bool success() { return success_
; }
290 void CreateRootCallback(ProfileSyncServiceSessionTest
* test
) {
291 success_
= syncer::TestUserShare::CreateRoot(
292 syncer::SESSIONS
, test
->sync_service()->GetUserShare());
295 base::Closure callback_
;
299 // Test that we can write this machine's session to a node and retrieve it.
300 TEST_F(ProfileSyncServiceSessionTest
, WriteSessionToNode
) {
301 CreateRootHelper
create_root(this);
302 ASSERT_TRUE(StartSyncService(create_root
.callback(), false));
303 ASSERT_TRUE(create_root
.success());
305 // Check that the DataTypeController associated the models.
307 ASSERT_TRUE(model_associator_
->SyncModelHasUserCreatedNodes(&has_nodes
));
308 ASSERT_TRUE(has_nodes
);
309 std::string machine_tag
= model_associator_
->GetCurrentMachineTag();
310 int64 sync_id
= model_associator_
->GetSyncIdFromSessionTag(machine_tag
);
311 ASSERT_NE(syncer::kInvalidId
, sync_id
);
313 // Check that we can get the correct session specifics back from the node.
314 syncer::ReadTransaction
trans(FROM_HERE
, sync_service_
->GetUserShare());
315 syncer::ReadNode
node(&trans
);
316 ASSERT_EQ(syncer::BaseNode::INIT_OK
,
317 node
.InitByClientTagLookup(syncer::SESSIONS
, machine_tag
));
318 const sync_pb::SessionSpecifics
& specifics(node
.GetSessionSpecifics());
319 ASSERT_EQ(machine_tag
, specifics
.session_tag());
320 ASSERT_TRUE(specifics
.has_header());
321 const sync_pb::SessionHeader
& header_s
= specifics
.header();
322 ASSERT_TRUE(header_s
.has_device_type());
323 ASSERT_EQ("TestSessionName", header_s
.client_name());
324 ASSERT_EQ(0, header_s
.window_size());
327 // Test that we can fill this machine's session, write it to a node,
328 // and then retrieve it.
329 // Disabled because this test fails occasionally: http://crbug.com/81104
330 TEST_F(ProfileSyncServiceSessionTest
, DISABLED_WriteFilledSessionToNode
) {
331 CreateRootHelper
create_root(this);
332 ASSERT_TRUE(StartSyncService(create_root
.callback(), false));
333 ASSERT_TRUE(create_root
.success());
335 // Check that the DataTypeController associated the models.
337 ASSERT_TRUE(model_associator_
->SyncModelHasUserCreatedNodes(&has_nodes
));
338 ASSERT_TRUE(has_nodes
);
339 AddTab(browser(), GURL("http://foo/1"));
340 NavigateAndCommitActiveTab(GURL("http://foo/2"));
341 AddTab(browser(), GURL("http://bar/1"));
342 NavigateAndCommitActiveTab(GURL("http://bar/2"));
344 ASSERT_TRUE(model_associator_
->SyncModelHasUserCreatedNodes(&has_nodes
));
345 ASSERT_TRUE(has_nodes
);
346 std::string machine_tag
= model_associator_
->GetCurrentMachineTag();
347 int64 sync_id
= model_associator_
->GetSyncIdFromSessionTag(machine_tag
);
348 ASSERT_NE(syncer::kInvalidId
, sync_id
);
350 // Check that this machine's data is not included in the foreign windows.
351 std::vector
<const SyncedSession
*> foreign_sessions
;
352 ASSERT_FALSE(model_associator_
->GetAllForeignSessions(&foreign_sessions
));
353 ASSERT_EQ(foreign_sessions
.size(), 0U);
355 // Get the tabs for this machine from the node and check that they were
357 SessionModelAssociator::TabLinksMap tab_map
= model_associator_
->tab_map_
;
358 ASSERT_EQ(2U, tab_map
.size());
359 // Tabs are ordered by sessionid in tab_map, so should be able to traverse
360 // the tree based on order of tabs created
361 SessionModelAssociator::TabLinksMap::iterator iter
= tab_map
.begin();
362 ASSERT_EQ(2, iter
->second
->tab()->GetEntryCount());
363 ASSERT_EQ(GURL("http://foo/1"), iter
->second
->tab()->
364 GetEntryAtIndex(0)->GetVirtualURL());
365 ASSERT_EQ(GURL("http://foo/2"), iter
->second
->tab()->
366 GetEntryAtIndex(1)->GetVirtualURL());
368 ASSERT_EQ(2, iter
->second
->tab()->GetEntryCount());
369 ASSERT_EQ(GURL("http://bar/1"), iter
->second
->tab()->
370 GetEntryAtIndex(0)->GetVirtualURL());
371 ASSERT_EQ(GURL("http://bar/2"), iter
->second
->tab()->
372 GetEntryAtIndex(1)->GetVirtualURL());
375 // Test that we fail on a failed model association.
376 TEST_F(ProfileSyncServiceSessionTest
, FailModelAssociation
) {
377 ASSERT_TRUE(StartSyncService(base::Closure(), true));
378 ASSERT_TRUE(sync_service_
->HasUnrecoverableError());
381 // Write a foreign session to a node, and then retrieve it.
382 TEST_F(ProfileSyncServiceSessionTest
, WriteForeignSessionToNode
) {
383 CreateRootHelper
create_root(this);
384 ASSERT_TRUE(StartSyncService(create_root
.callback(), false));
385 ASSERT_TRUE(create_root
.success());
387 // Check that the DataTypeController associated the models.
389 ASSERT_TRUE(model_associator_
->SyncModelHasUserCreatedNodes(&has_nodes
));
390 ASSERT_TRUE(has_nodes
);
392 // Fill an instance of session specifics with a foreign session's data.
393 std::string tag
= "tag1";
394 sync_pb::SessionSpecifics meta
;
395 BuildSessionSpecifics(tag
, &meta
);
396 SessionID::id_type tab_nums1
[] = {5, 10, 13, 17};
397 std::vector
<SessionID::id_type
> tab_list1(
398 tab_nums1
, tab_nums1
+ arraysize(tab_nums1
));
399 AddWindowSpecifics(0, tab_list1
, &meta
);
400 std::vector
<sync_pb::SessionSpecifics
> tabs1
;
401 tabs1
.resize(tab_list1
.size());
402 for (size_t i
= 0; i
< tab_list1
.size(); ++i
) {
403 BuildTabSpecifics(tag
, 0, tab_list1
[i
], &tabs1
[i
]);
406 // Update associator with the session's meta node containing one window.
407 model_associator_
->AssociateForeignSpecifics(meta
, base::Time());
408 // Add tabs for the window.
409 for (std::vector
<sync_pb::SessionSpecifics
>::iterator iter
= tabs1
.begin();
410 iter
!= tabs1
.end(); ++iter
) {
411 model_associator_
->AssociateForeignSpecifics(*iter
, base::Time());
414 // Check that the foreign session was associated and retrieve the data.
415 std::vector
<const SyncedSession
*> foreign_sessions
;
416 ASSERT_TRUE(model_associator_
->GetAllForeignSessions(&foreign_sessions
));
417 ASSERT_EQ(1U, foreign_sessions
.size());
418 std::vector
<std::vector
<SessionID::id_type
> > session_reference
;
419 session_reference
.push_back(tab_list1
);
420 VerifySyncedSession(tag
, session_reference
, *(foreign_sessions
[0]));
423 // Write a foreign session with one window to a node. Sync, then add a window.
424 // Sync, then add a third window. Close the two windows.
425 TEST_F(ProfileSyncServiceSessionTest
, WriteForeignSessionToNodeThreeWindows
) {
426 CreateRootHelper
create_root(this);
427 ASSERT_TRUE(StartSyncService(create_root
.callback(), false));
428 ASSERT_TRUE(create_root
.success());
430 // Build a foreign session with one window and four tabs.
431 std::string tag
= "tag1";
432 sync_pb::SessionSpecifics meta
;
433 BuildSessionSpecifics(tag
, &meta
);
434 SessionID::id_type tab_nums1
[] = {5, 10, 13, 17};
435 std::vector
<SessionID::id_type
> tab_list1(
436 tab_nums1
, tab_nums1
+ arraysize(tab_nums1
));
437 AddWindowSpecifics(0, tab_list1
, &meta
);
438 std::vector
<sync_pb::SessionSpecifics
> tabs1
;
439 tabs1
.resize(tab_list1
.size());
440 for (size_t i
= 0; i
< tab_list1
.size(); ++i
) {
441 BuildTabSpecifics(tag
, 0, tab_list1
[i
], &tabs1
[i
]);
443 // Update associator with the session's meta node containing one window.
444 model_associator_
->AssociateForeignSpecifics(meta
, base::Time());
445 // Add tabs for first window.
446 for (std::vector
<sync_pb::SessionSpecifics
>::iterator iter
= tabs1
.begin();
447 iter
!= tabs1
.end(); ++iter
) {
448 model_associator_
->AssociateForeignSpecifics(*iter
, base::Time());
451 // Verify first window
452 std::vector
<const SyncedSession
*> foreign_sessions
;
453 ASSERT_TRUE(model_associator_
->GetAllForeignSessions(&foreign_sessions
));
454 std::vector
<std::vector
<SessionID::id_type
> > session_reference
;
455 session_reference
.push_back(tab_list1
);
456 VerifySyncedSession(tag
, session_reference
, *(foreign_sessions
[0]));
458 // Add a second window.
459 SessionID::id_type tab_nums2
[] = {7, 15, 18, 20};
460 std::vector
<SessionID::id_type
> tab_list2(
461 tab_nums2
, tab_nums2
+ arraysize(tab_nums2
));
462 AddWindowSpecifics(1, tab_list2
, &meta
);
463 std::vector
<sync_pb::SessionSpecifics
> tabs2
;
464 tabs2
.resize(tab_list2
.size());
465 for (size_t i
= 0; i
< tab_list2
.size(); ++i
) {
466 BuildTabSpecifics(tag
, 0, tab_list2
[i
], &tabs2
[i
]);
468 // Update associator with the session's meta node containing two windows.
469 model_associator_
->AssociateForeignSpecifics(meta
, base::Time());
470 // Add tabs for second window.
471 for (std::vector
<sync_pb::SessionSpecifics
>::iterator iter
= tabs2
.begin();
472 iter
!= tabs2
.end(); ++iter
) {
473 model_associator_
->AssociateForeignSpecifics(*iter
, base::Time());
476 // Verify the two windows.
477 foreign_sessions
.clear();
478 ASSERT_TRUE(model_associator_
->GetAllForeignSessions(&foreign_sessions
));
479 ASSERT_EQ(1U, foreign_sessions
.size());
480 session_reference
.push_back(tab_list2
);
481 VerifySyncedSession(tag
, session_reference
, *(foreign_sessions
[0]));
483 // Add a third window.
484 SessionID::id_type tab_nums3
[] = {8, 16, 19, 21};
485 std::vector
<SessionID::id_type
> tab_list3(
486 tab_nums3
, tab_nums3
+ arraysize(tab_nums3
));
487 AddWindowSpecifics(2, tab_list3
, &meta
);
488 std::vector
<sync_pb::SessionSpecifics
> tabs3
;
489 tabs3
.resize(tab_list3
.size());
490 for (size_t i
= 0; i
< tab_list3
.size(); ++i
) {
491 BuildTabSpecifics(tag
, 0, tab_list3
[i
], &tabs3
[i
]);
493 // Update associator with the session's meta node containing three windows.
494 model_associator_
->AssociateForeignSpecifics(meta
, base::Time());
495 // Add tabs for third window.
496 for (std::vector
<sync_pb::SessionSpecifics
>::iterator iter
= tabs3
.begin();
497 iter
!= tabs3
.end(); ++iter
) {
498 model_associator_
->AssociateForeignSpecifics(*iter
, base::Time());
501 // Verify the three windows
502 foreign_sessions
.clear();
503 ASSERT_TRUE(model_associator_
->GetAllForeignSessions(&foreign_sessions
));
504 ASSERT_EQ(1U, foreign_sessions
.size());
505 session_reference
.push_back(tab_list3
);
506 VerifySyncedSession(tag
, session_reference
, *(foreign_sessions
[0]));
508 // Close third window (by clearing and then not adding it back).
509 meta
.mutable_header()->clear_window();
510 AddWindowSpecifics(0, tab_list1
, &meta
);
511 AddWindowSpecifics(1, tab_list2
, &meta
);
512 // Update associator with just the meta node, now containing only two windows.
513 model_associator_
->AssociateForeignSpecifics(meta
, base::Time());
515 // Verify first two windows are still there.
516 foreign_sessions
.clear();
517 ASSERT_TRUE(model_associator_
->GetAllForeignSessions(&foreign_sessions
));
518 ASSERT_EQ(1U, foreign_sessions
.size());
519 session_reference
.pop_back(); // Pop off the data for the third window.
520 VerifySyncedSession(tag
, session_reference
, *(foreign_sessions
[0]));
522 // Close second window (by clearing and then not adding it back).
523 meta
.mutable_header()->clear_window();
524 AddWindowSpecifics(0, tab_list1
, &meta
);
525 // Update associator with just the meta node, now containing only one windows.
526 model_associator_
->AssociateForeignSpecifics(meta
, base::Time());
528 // Verify first window is still there.
529 foreign_sessions
.clear();
530 ASSERT_TRUE(model_associator_
->GetAllForeignSessions(&foreign_sessions
));
531 ASSERT_EQ(1U, foreign_sessions
.size());
532 session_reference
.pop_back(); // Pop off the data for the second window.
533 VerifySyncedSession(tag
, session_reference
, *(foreign_sessions
[0]));
536 // Write a foreign session to a node, with the tabs arriving first, and then
538 TEST_F(ProfileSyncServiceSessionTest
, WriteForeignSessionToNodeTabsFirst
) {
539 CreateRootHelper
create_root(this);
540 ASSERT_TRUE(StartSyncService(create_root
.callback(), false));
541 ASSERT_TRUE(create_root
.success());
543 // Fill an instance of session specifics with a foreign session's data.
544 std::string tag
= "tag1";
545 sync_pb::SessionSpecifics meta
;
546 BuildSessionSpecifics(tag
, &meta
);
547 SessionID::id_type tab_nums1
[] = {5, 10, 13, 17};
548 std::vector
<SessionID::id_type
> tab_list1(
549 tab_nums1
, tab_nums1
+ arraysize(tab_nums1
));
550 AddWindowSpecifics(0, tab_list1
, &meta
);
551 std::vector
<sync_pb::SessionSpecifics
> tabs1
;
552 tabs1
.resize(tab_list1
.size());
553 for (size_t i
= 0; i
< tab_list1
.size(); ++i
) {
554 BuildTabSpecifics(tag
, 0, tab_list1
[i
], &tabs1
[i
]);
557 // Add tabs for first window.
558 for (std::vector
<sync_pb::SessionSpecifics
>::iterator iter
= tabs1
.begin();
559 iter
!= tabs1
.end(); ++iter
) {
560 model_associator_
->AssociateForeignSpecifics(*iter
, base::Time());
562 // Update associator with the session's meta node containing one window.
563 model_associator_
->AssociateForeignSpecifics(meta
, base::Time());
565 // Check that the foreign session was associated and retrieve the data.
566 std::vector
<const SyncedSession
*> foreign_sessions
;
567 ASSERT_TRUE(model_associator_
->GetAllForeignSessions(&foreign_sessions
));
568 ASSERT_EQ(1U, foreign_sessions
.size());
569 std::vector
<std::vector
<SessionID::id_type
> > session_reference
;
570 session_reference
.push_back(tab_list1
);
571 VerifySyncedSession(tag
, session_reference
, *(foreign_sessions
[0]));
574 // Write a foreign session to a node with some tabs that never arrive.
575 TEST_F(ProfileSyncServiceSessionTest
, WriteForeignSessionToNodeMissingTabs
) {
576 CreateRootHelper
create_root(this);
577 ASSERT_TRUE(StartSyncService(create_root
.callback(), false));
578 ASSERT_TRUE(create_root
.success());
580 // Fill an instance of session specifics with a foreign session's data.
581 std::string tag
= "tag1";
582 sync_pb::SessionSpecifics meta
;
583 BuildSessionSpecifics(tag
, &meta
);
584 SessionID::id_type tab_nums1
[] = {5, 10, 13, 17};
585 std::vector
<SessionID::id_type
> tab_list1(
586 tab_nums1
, tab_nums1
+ arraysize(tab_nums1
));
587 AddWindowSpecifics(0, tab_list1
, &meta
);
588 std::vector
<sync_pb::SessionSpecifics
> tabs1
;
589 tabs1
.resize(tab_list1
.size()); // First window has all the tabs
590 for (size_t i
= 0; i
< tab_list1
.size(); ++i
) {
591 BuildTabSpecifics(tag
, 0, tab_list1
[i
], &tabs1
[i
]);
593 // Add a second window, but this time only create two tab nodes, despite the
594 // window expecting four tabs.
595 SessionID::id_type tab_nums2
[] = {7, 15, 18, 20};
596 std::vector
<SessionID::id_type
> tab_list2(
597 tab_nums2
, tab_nums2
+ arraysize(tab_nums2
));
598 AddWindowSpecifics(1, tab_list2
, &meta
);
599 std::vector
<sync_pb::SessionSpecifics
> tabs2
;
601 for (size_t i
= 0; i
< 2; ++i
) {
602 BuildTabSpecifics(tag
, 0, tab_list2
[i
], &tabs2
[i
]);
605 // Update associator with the session's meta node containing two windows.
606 model_associator_
->AssociateForeignSpecifics(meta
, base::Time());
607 // Add tabs for first window.
608 for (std::vector
<sync_pb::SessionSpecifics
>::iterator iter
= tabs1
.begin();
609 iter
!= tabs1
.end(); ++iter
) {
610 model_associator_
->AssociateForeignSpecifics(*iter
, base::Time());
612 // Add tabs for second window.
613 for (std::vector
<sync_pb::SessionSpecifics
>::iterator iter
= tabs2
.begin();
614 iter
!= tabs2
.end(); ++iter
) {
615 model_associator_
->AssociateForeignSpecifics(*iter
, base::Time());
618 // Check that the foreign session was associated and retrieve the data.
619 std::vector
<const SyncedSession
*> foreign_sessions
;
620 ASSERT_TRUE(model_associator_
->GetAllForeignSessions(&foreign_sessions
));
621 ASSERT_EQ(1U, foreign_sessions
.size());
622 ASSERT_EQ(2U, foreign_sessions
[0]->windows
.size());
623 ASSERT_EQ(4U, foreign_sessions
[0]->windows
.find(0)->second
->tabs
.size());
624 ASSERT_EQ(4U, foreign_sessions
[0]->windows
.find(1)->second
->tabs
.size());
626 // Close the second window.
627 meta
.mutable_header()->clear_window();
628 AddWindowSpecifics(0, tab_list1
, &meta
);
630 // Update associator with the session's meta node containing one window.
631 model_associator_
->AssociateForeignSpecifics(meta
, base::Time());
633 // Check that the foreign session was associated and retrieve the data.
634 foreign_sessions
.clear();
635 ASSERT_TRUE(model_associator_
->GetAllForeignSessions(&foreign_sessions
));
636 ASSERT_EQ(1U, foreign_sessions
.size());
637 ASSERT_EQ(1U, foreign_sessions
[0]->windows
.size());
638 std::vector
<std::vector
<SessionID::id_type
> > session_reference
;
639 session_reference
.push_back(tab_list1
);
640 VerifySyncedSession(tag
, session_reference
, *(foreign_sessions
[0]));
643 // Test the DataTypeController on update.
644 TEST_F(ProfileSyncServiceSessionTest
, UpdatedSyncNodeActionUpdate
) {
645 CreateRootHelper
create_root(this);
646 ASSERT_TRUE(StartSyncService(create_root
.callback(), false));
647 ASSERT_TRUE(create_root
.success());
648 int64 node_id
= model_associator_
->GetSyncIdFromSessionTag(
649 model_associator_
->GetCurrentMachineTag());
650 ASSERT_FALSE(notified_of_update_
);
652 syncer::WriteTransaction
trans(FROM_HERE
, sync_service_
->GetUserShare());
653 change_processor_
->ApplyChangesFromSyncModel(
655 ProfileSyncServiceTestHelper::MakeSingletonChangeRecordList(
656 node_id
, ChangeRecord::ACTION_UPDATE
));
658 ASSERT_TRUE(notified_of_update_
);
661 // Test the DataTypeController on add.
662 TEST_F(ProfileSyncServiceSessionTest
, UpdatedSyncNodeActionAdd
) {
663 CreateRootHelper
create_root(this);
664 ASSERT_TRUE(StartSyncService(create_root
.callback(), false));
665 ASSERT_TRUE(create_root
.success());
667 int64 node_id
= model_associator_
->GetSyncIdFromSessionTag(
668 model_associator_
->GetCurrentMachineTag());
669 ASSERT_FALSE(notified_of_update_
);
671 syncer::WriteTransaction
trans(FROM_HERE
, sync_service_
->GetUserShare());
672 change_processor_
->ApplyChangesFromSyncModel(
674 ProfileSyncServiceTestHelper::MakeSingletonChangeRecordList(
675 node_id
, ChangeRecord::ACTION_ADD
));
677 ASSERT_TRUE(notified_of_update_
);
680 // Test the DataTypeController on delete.
681 TEST_F(ProfileSyncServiceSessionTest
, UpdatedSyncNodeActionDelete
) {
682 CreateRootHelper
create_root(this);
683 ASSERT_TRUE(StartSyncService(create_root
.callback(), false));
684 ASSERT_TRUE(create_root
.success());
686 int64 node_id
= model_associator_
->GetSyncIdFromSessionTag(
687 model_associator_
->GetCurrentMachineTag());
688 sync_pb::EntitySpecifics deleted_specifics
;
689 deleted_specifics
.mutable_session()->set_session_tag("tag");
690 ASSERT_FALSE(notified_of_update_
);
692 syncer::WriteTransaction
trans(FROM_HERE
, sync_service_
->GetUserShare());
693 change_processor_
->ApplyChangesFromSyncModel(
695 ProfileSyncServiceTestHelper::MakeSingletonDeletionChangeRecordList(
696 node_id
, deleted_specifics
));
698 ASSERT_TRUE(notified_of_update_
);
700 // Test the TabNodePool when it starts off empty.
701 TEST_F(ProfileSyncServiceSessionTest
, TabNodePoolEmpty
) {
702 CreateRootHelper
create_root(this);
703 ASSERT_TRUE(StartSyncService(create_root
.callback(), false));
704 ASSERT_TRUE(create_root
.success());
706 std::vector
<int64
> node_ids
;
707 ASSERT_EQ(0U, model_associator_
->tab_pool_
.capacity());
708 ASSERT_TRUE(model_associator_
->tab_pool_
.empty());
709 ASSERT_TRUE(model_associator_
->tab_pool_
.full());
710 const size_t num_ids
= 10;
711 for (size_t i
= 0; i
< num_ids
; ++i
) {
712 int64 id
= model_associator_
->tab_pool_
.GetFreeTabNode();
714 node_ids
.push_back(id
);
716 ASSERT_EQ(num_ids
, model_associator_
->tab_pool_
.capacity());
717 ASSERT_TRUE(model_associator_
->tab_pool_
.empty());
718 ASSERT_FALSE(model_associator_
->tab_pool_
.full());
719 for (size_t i
= 0; i
< num_ids
; ++i
) {
720 model_associator_
->tab_pool_
.FreeTabNode(node_ids
[i
]);
722 ASSERT_EQ(num_ids
, model_associator_
->tab_pool_
.capacity());
723 ASSERT_FALSE(model_associator_
->tab_pool_
.empty());
724 ASSERT_TRUE(model_associator_
->tab_pool_
.full());
727 // TODO(jhorwich): Re-enable when crbug.com/121487 addressed
728 // Test the TabNodePool when it starts off with nodes
729 TEST_F(ProfileSyncServiceSessionTest
, DISABLED_TabNodePoolNonEmpty
) {
730 CreateRootHelper
create_root(this);
731 ASSERT_TRUE(StartSyncService(create_root
.callback(), false));
732 ASSERT_TRUE(create_root
.success());
734 const size_t num_starting_nodes
= 3;
735 for (size_t i
= 0; i
< num_starting_nodes
; ++i
) {
736 model_associator_
->tab_pool_
.AddTabNode(i
);
739 std::vector
<int64
> node_ids
;
740 ASSERT_EQ(num_starting_nodes
, model_associator_
->tab_pool_
.capacity());
741 ASSERT_FALSE(model_associator_
->tab_pool_
.empty());
742 ASSERT_TRUE(model_associator_
->tab_pool_
.full());
743 const size_t num_ids
= 10;
744 for (size_t i
= 0; i
< num_ids
; ++i
) {
745 int64 id
= model_associator_
->tab_pool_
.GetFreeTabNode();
747 node_ids
.push_back(id
);
749 ASSERT_EQ(num_ids
, model_associator_
->tab_pool_
.capacity());
750 ASSERT_TRUE(model_associator_
->tab_pool_
.empty());
751 ASSERT_FALSE(model_associator_
->tab_pool_
.full());
752 for (size_t i
= 0; i
< num_ids
; ++i
) {
753 model_associator_
->tab_pool_
.FreeTabNode(node_ids
[i
]);
755 ASSERT_EQ(num_ids
, model_associator_
->tab_pool_
.capacity());
756 ASSERT_FALSE(model_associator_
->tab_pool_
.empty());
757 ASSERT_TRUE(model_associator_
->tab_pool_
.full());
760 // Write a foreign session to a node, and then delete it.
761 TEST_F(ProfileSyncServiceSessionTest
, DeleteForeignSession
) {
762 CreateRootHelper
create_root(this);
763 ASSERT_TRUE(StartSyncService(create_root
.callback(), false));
764 ASSERT_TRUE(create_root
.success());
766 // Check that the DataTypeController associated the models.
768 ASSERT_TRUE(model_associator_
->SyncModelHasUserCreatedNodes(&has_nodes
));
769 ASSERT_TRUE(has_nodes
);
771 // A foreign session's tag.
772 std::string tag
= "tag1";
774 // Should do nothing if the foreign session doesn't exist.
775 std::vector
<const SyncedSession
*> foreign_sessions
;
776 ASSERT_FALSE(model_associator_
->GetAllForeignSessions(&foreign_sessions
));
777 model_associator_
->DeleteForeignSession(tag
);
778 ASSERT_FALSE(model_associator_
->GetAllForeignSessions(&foreign_sessions
));
780 // Fill an instance of session specifics with a foreign session's data.
781 sync_pb::SessionSpecifics meta
;
782 BuildSessionSpecifics(tag
, &meta
);
783 SessionID::id_type tab_nums1
[] = {5, 10, 13, 17};
784 std::vector
<SessionID::id_type
> tab_list1(
785 tab_nums1
, tab_nums1
+ arraysize(tab_nums1
));
786 AddWindowSpecifics(0, tab_list1
, &meta
);
787 std::vector
<sync_pb::SessionSpecifics
> tabs1
;
788 tabs1
.resize(tab_list1
.size());
789 for (size_t i
= 0; i
< tab_list1
.size(); ++i
) {
790 BuildTabSpecifics(tag
, 0, tab_list1
[i
], &tabs1
[i
]);
793 // Update associator with the session's meta node containing one window.
794 model_associator_
->AssociateForeignSpecifics(meta
, base::Time());
795 // Add tabs for the window.
796 for (std::vector
<sync_pb::SessionSpecifics
>::iterator iter
= tabs1
.begin();
797 iter
!= tabs1
.end(); ++iter
) {
798 model_associator_
->AssociateForeignSpecifics(*iter
, base::Time());
801 // Check that the foreign session was associated and retrieve the data.
802 ASSERT_TRUE(model_associator_
->GetAllForeignSessions(&foreign_sessions
));
803 ASSERT_EQ(1U, foreign_sessions
.size());
804 std::vector
<std::vector
<SessionID::id_type
> > session_reference
;
805 session_reference
.push_back(tab_list1
);
806 VerifySyncedSession(tag
, session_reference
, *(foreign_sessions
[0]));
808 // Now delete the foreign session.
809 model_associator_
->DeleteForeignSession(tag
);
810 ASSERT_FALSE(model_associator_
->GetAllForeignSessions(&foreign_sessions
));
813 // Associate both a non-stale foreign session and a stale foreign session.
814 // Ensure only the stale session gets deleted.
815 TEST_F(ProfileSyncServiceSessionTest
, DeleteStaleSessions
) {
816 CreateRootHelper
create_root(this);
817 ASSERT_TRUE(StartSyncService(create_root
.callback(), false));
818 ASSERT_TRUE(create_root
.success());
820 // Fill two instances of session specifics with a foreign session's data.
821 std::string tag
= "tag1";
822 sync_pb::SessionSpecifics meta
;
823 BuildSessionSpecifics(tag
, &meta
);
824 SessionID::id_type tab_nums1
[] = {5, 10, 13, 17};
825 std::vector
<SessionID::id_type
> tab_list1(
826 tab_nums1
, tab_nums1
+ arraysize(tab_nums1
));
827 AddWindowSpecifics(0, tab_list1
, &meta
);
828 std::vector
<sync_pb::SessionSpecifics
> tabs1
;
829 tabs1
.resize(tab_list1
.size());
830 for (size_t i
= 0; i
< tab_list1
.size(); ++i
) {
831 BuildTabSpecifics(tag
, 0, tab_list1
[i
], &tabs1
[i
]);
833 std::string tag2
= "tag2";
834 sync_pb::SessionSpecifics meta2
;
835 BuildSessionSpecifics(tag2
, &meta2
);
836 SessionID::id_type tab_nums2
[] = {8, 15, 18, 20};
837 std::vector
<SessionID::id_type
> tab_list2(
838 tab_nums2
, tab_nums2
+ arraysize(tab_nums2
));
839 AddWindowSpecifics(0, tab_list2
, &meta2
);
840 std::vector
<sync_pb::SessionSpecifics
> tabs2
;
841 tabs2
.resize(tab_list2
.size());
842 for (size_t i
= 0; i
< tab_list2
.size(); ++i
) {
843 BuildTabSpecifics(tag2
, 0, tab_list2
[i
], &tabs2
[i
]);
846 // Set the modification time for tag1 to be 21 days ago, tag2 to 5 days ago.
847 base::Time tag1_time
= base::Time::Now() - base::TimeDelta::FromDays(21);
848 base::Time tag2_time
= base::Time::Now() - base::TimeDelta::FromDays(5);
850 // Associate specifics.
851 model_associator_
->AssociateForeignSpecifics(meta
, tag1_time
);
852 for (std::vector
<sync_pb::SessionSpecifics
>::iterator iter
= tabs1
.begin();
853 iter
!= tabs1
.end(); ++iter
) {
854 model_associator_
->AssociateForeignSpecifics(*iter
, tag1_time
);
856 model_associator_
->AssociateForeignSpecifics(meta2
, tag2_time
);
857 for (std::vector
<sync_pb::SessionSpecifics
>::iterator iter
= tabs2
.begin();
858 iter
!= tabs2
.end(); ++iter
) {
859 model_associator_
->AssociateForeignSpecifics(*iter
, tag2_time
);
862 // Check that the foreign session was associated and retrieve the data.
863 std::vector
<const SyncedSession
*> foreign_sessions
;
864 ASSERT_TRUE(model_associator_
->GetAllForeignSessions(&foreign_sessions
));
865 ASSERT_EQ(2U, foreign_sessions
.size());
867 // Now delete the stale session and verify the non-stale one is still there.
868 model_associator_
->DeleteStaleSessions();
869 ASSERT_TRUE(model_associator_
->GetAllForeignSessions(&foreign_sessions
));
870 ASSERT_EQ(1U, foreign_sessions
.size());
871 std::vector
<std::vector
<SessionID::id_type
> > session_reference
;
872 session_reference
.push_back(tab_list2
);
873 VerifySyncedSession(tag2
, session_reference
, *(foreign_sessions
[0]));
876 // Write a stale foreign session to a node. Then update one of its tabs so
877 // the session is no longer stale. Ensure it doesn't get deleted.
878 TEST_F(ProfileSyncServiceSessionTest
, StaleSessionRefresh
) {
879 CreateRootHelper
create_root(this);
880 ASSERT_TRUE(StartSyncService(create_root
.callback(), false));
881 ASSERT_TRUE(create_root
.success());
883 std::string tag
= "tag1";
884 sync_pb::SessionSpecifics meta
;
885 BuildSessionSpecifics(tag
, &meta
);
886 SessionID::id_type tab_nums1
[] = {5, 10, 13, 17};
887 std::vector
<SessionID::id_type
> tab_list1(
888 tab_nums1
, tab_nums1
+ arraysize(tab_nums1
));
889 AddWindowSpecifics(0, tab_list1
, &meta
);
890 std::vector
<sync_pb::SessionSpecifics
> tabs1
;
891 tabs1
.resize(tab_list1
.size());
892 for (size_t i
= 0; i
< tab_list1
.size(); ++i
) {
893 BuildTabSpecifics(tag
, 0, tab_list1
[i
], &tabs1
[i
]);
897 base::Time stale_time
= base::Time::Now() - base::TimeDelta::FromDays(21);
898 model_associator_
->AssociateForeignSpecifics(meta
, stale_time
);
899 for (std::vector
<sync_pb::SessionSpecifics
>::iterator iter
= tabs1
.begin();
900 iter
!= tabs1
.end(); ++iter
) {
901 model_associator_
->AssociateForeignSpecifics(*iter
, stale_time
);
904 // Associate one of the tabs with a non-stale time.
905 model_associator_
->AssociateForeignSpecifics(tabs1
[0], base::Time::Now());
907 // Check that the foreign session was associated and retrieve the data.
908 std::vector
<const SyncedSession
*> foreign_sessions
;
909 ASSERT_TRUE(model_associator_
->GetAllForeignSessions(&foreign_sessions
));
910 ASSERT_EQ(1U, foreign_sessions
.size());
912 // Verify the now non-stale session does not get deleted.
913 model_associator_
->DeleteStaleSessions();
914 ASSERT_TRUE(model_associator_
->GetAllForeignSessions(&foreign_sessions
));
915 ASSERT_EQ(1U, foreign_sessions
.size());
916 std::vector
<std::vector
<SessionID::id_type
> > session_reference
;
917 session_reference
.push_back(tab_list1
);
918 VerifySyncedSession(tag
, session_reference
, *(foreign_sessions
[0]));
921 // Test that tabs with nothing but "chrome://*" and "file://*" navigations are
923 // This test is crashing occasionally: http://crbug.com/116097
924 TEST_F(ProfileSyncServiceSessionTest
, DISABLED_ValidTabs
) {
925 CreateRootHelper
create_root(this);
926 ASSERT_TRUE(StartSyncService(create_root
.callback(), false));
927 ASSERT_TRUE(create_root
.success());
929 AddTab(browser(), GURL("chrome://bla1/"));
930 NavigateAndCommitActiveTab(GURL("chrome://bla2"));
931 AddTab(browser(), GURL("file://bla3/"));
932 AddTab(browser(), GURL("bla://bla"));
933 // Note: chrome://newtab has special handling which crashes in unit tests.
935 // Get the tabs for this machine. Only the bla:// url should be synced.
936 SessionModelAssociator::TabLinksMap tab_map
= model_associator_
->tab_map_
;
937 ASSERT_EQ(1U, tab_map
.size());
938 SessionModelAssociator::TabLinksMap::iterator iter
= tab_map
.begin();
939 ASSERT_EQ(1, iter
->second
->tab()->GetEntryCount());
940 ASSERT_EQ(GURL("bla://bla"), iter
->second
->tab()->
941 GetEntryAtIndex(0)->GetVirtualURL());
944 // Verify that AttemptSessionsDataRefresh triggers the
945 // NOTIFICATION_SYNC_REFRESH_LOCAL notification.
946 // TODO(zea): Once we can have unit tests that are able to open to the NTP,
947 // test that the NTP/#opentabs URL triggers a refresh as well (but only when
948 // it is the active tab).
949 TEST_F(ProfileSyncServiceSessionTest
, SessionsRefresh
) {
950 CreateRootHelper
create_root(this);
951 ASSERT_TRUE(StartSyncService(create_root
.callback(), false));
952 ASSERT_TRUE(create_root
.success());
954 // Empty, so returns false.
955 std::vector
<const SyncedSession
*> foreign_sessions
;
956 ASSERT_FALSE(model_associator_
->GetAllForeignSessions(&foreign_sessions
));
957 ASSERT_FALSE(notified_of_refresh_
);
958 model_associator_
->AttemptSessionsDataRefresh();
959 ASSERT_TRUE(notified_of_refresh_
);
961 // Nothing should have changed since we don't have unapplied data.
962 ASSERT_FALSE(model_associator_
->GetAllForeignSessions(&foreign_sessions
));
965 // Ensure model association associates the pre-existing tabs.
966 // TODO(jhorwich): Fix the test so that it doesn't crash (crbug.com/121487)
967 TEST_F(ProfileSyncServiceSessionTest
, DISABLED_ExistingTabs
) {
968 AddTab(browser(), GURL("http://foo1"));
969 NavigateAndCommitActiveTab(GURL("http://foo2"));
970 AddTab(browser(), GURL("http://bar1"));
971 NavigateAndCommitActiveTab(GURL("http://bar2"));
973 CreateRootHelper
create_root(this);
974 ASSERT_TRUE(StartSyncService(create_root
.callback(), false));
975 ASSERT_TRUE(create_root
.success());
977 ASSERT_TRUE(model_associator_
->SyncModelHasUserCreatedNodes(&has_nodes
));
978 ASSERT_TRUE(has_nodes
);
980 std::string machine_tag
= model_associator_
->GetCurrentMachineTag();
981 int64 sync_id
= model_associator_
->GetSyncIdFromSessionTag(machine_tag
);
982 ASSERT_NE(syncer::kInvalidId
, sync_id
);
984 // Check that this machine's data is not included in the foreign windows.
985 std::vector
<const SyncedSession
*> foreign_sessions
;
986 ASSERT_FALSE(model_associator_
->GetAllForeignSessions(&foreign_sessions
));
987 ASSERT_EQ(foreign_sessions
.size(), 0U);
989 // Get the tabs for this machine from the node and check that they were
991 SessionModelAssociator::TabLinksMap tab_map
= model_associator_
->tab_map_
;
992 ASSERT_EQ(2U, tab_map
.size());
993 // Tabs are ordered by sessionid in tab_map, so should be able to traverse
994 // the tree based on order of tabs created
995 SessionModelAssociator::TabLinksMap::iterator iter
= tab_map
.begin();
996 ASSERT_EQ(2, iter
->second
->tab()->GetEntryCount());
997 ASSERT_EQ(GURL("http://foo1"), iter
->second
->tab()->
998 GetEntryAtIndex(0)->GetVirtualURL());
999 ASSERT_EQ(GURL("http://foo2"), iter
->second
->tab()->
1000 GetEntryAtIndex(1)->GetVirtualURL());
1002 ASSERT_EQ(2, iter
->second
->tab()->GetEntryCount());
1003 ASSERT_EQ(GURL("http://bar1"), iter
->second
->tab()->
1004 GetEntryAtIndex(0)->GetVirtualURL());
1005 ASSERT_EQ(GURL("http://bar2"), iter
->second
->tab()->
1006 GetEntryAtIndex(1)->GetVirtualURL());
1009 // TODO(jhorwich): Re-enable when crbug.com/121487 addressed
1010 TEST_F(ProfileSyncServiceSessionTest
, DISABLED_MissingHeaderAndTab
) {
1011 AddTab(browser(), GURL("http://foo1"));
1012 NavigateAndCommitActiveTab(GURL("http://foo2"));
1013 AddTab(browser(), GURL("http://bar1"));
1014 NavigateAndCommitActiveTab(GURL("http://bar2"));
1015 CreateRootHelper
create_root(this);
1016 ASSERT_TRUE(StartSyncService(create_root
.callback(), false));
1017 syncer::SyncError error
;
1018 std::string local_tag
= model_associator_
->GetCurrentMachineTag();
1020 error
= model_associator_
->DisassociateModels();
1021 ASSERT_FALSE(error
.IsSet());
1023 // Create a sync node with the local tag but neither header nor tab field.
1024 syncer::WriteTransaction
trans(FROM_HERE
, sync_service_
->GetUserShare());
1025 syncer::ReadNode
root(&trans
);
1026 root
.InitByTagLookup(syncer::ModelTypeToRootTag(syncer::SESSIONS
));
1027 syncer::WriteNode
extra_header(&trans
);
1028 syncer::WriteNode::InitUniqueByCreationResult result
=
1029 extra_header
.InitUniqueByCreation(syncer::SESSIONS
, root
, "new_tag");
1030 ASSERT_EQ(syncer::WriteNode::INIT_SUCCESS
, result
);
1031 sync_pb::SessionSpecifics specifics
;
1032 specifics
.set_session_tag(local_tag
);
1033 extra_header
.SetSessionSpecifics(specifics
);
1036 error
= model_associator_
->AssociateModels(NULL
, NULL
);
1037 ASSERT_FALSE(error
.IsSet());
1040 // TODO(jhorwich): Re-enable when crbug.com/121487 addressed
1041 TEST_F(ProfileSyncServiceSessionTest
, DISABLED_MultipleHeaders
) {
1042 AddTab(browser(), GURL("http://foo1"));
1043 NavigateAndCommitActiveTab(GURL("http://foo2"));
1044 AddTab(browser(), GURL("http://bar1"));
1045 NavigateAndCommitActiveTab(GURL("http://bar2"));
1046 CreateRootHelper
create_root(this);
1047 ASSERT_TRUE(StartSyncService(create_root
.callback(), false));
1048 syncer::SyncError error
;
1049 std::string local_tag
= model_associator_
->GetCurrentMachineTag();
1051 error
= model_associator_
->DisassociateModels();
1052 ASSERT_FALSE(error
.IsSet());
1054 // Create another sync node with a header field and the local tag.
1055 syncer::WriteTransaction
trans(FROM_HERE
, sync_service_
->GetUserShare());
1056 syncer::ReadNode
root(&trans
);
1057 root
.InitByTagLookup(syncer::ModelTypeToRootTag(syncer::SESSIONS
));
1058 syncer::WriteNode
extra_header(&trans
);
1059 syncer::WriteNode::InitUniqueByCreationResult result
=
1060 extra_header
.InitUniqueByCreation(syncer::SESSIONS
,
1061 root
, local_tag
+ "_");
1062 ASSERT_EQ(syncer::WriteNode::INIT_SUCCESS
, result
);
1063 sync_pb::SessionSpecifics specifics
;
1064 specifics
.set_session_tag(local_tag
);
1065 specifics
.mutable_header();
1066 extra_header
.SetSessionSpecifics(specifics
);
1068 error
= model_associator_
->AssociateModels(NULL
, NULL
);
1069 ASSERT_FALSE(error
.IsSet());
1072 // TODO(jhorwich): Re-enable when crbug.com/121487 addressed
1073 TEST_F(ProfileSyncServiceSessionTest
, DISABLED_CorruptedForeign
) {
1074 AddTab(browser(), GURL("http://foo1"));
1075 NavigateAndCommitActiveTab(GURL("http://foo2"));
1076 AddTab(browser(), GURL("http://bar1"));
1077 NavigateAndCommitActiveTab(GURL("http://bar2"));
1078 CreateRootHelper
create_root(this);
1079 ASSERT_TRUE(StartSyncService(create_root
.callback(), false));
1080 syncer::SyncError error
;
1082 error
= model_associator_
->DisassociateModels();
1083 ASSERT_FALSE(error
.IsSet());
1085 // Create another sync node with neither header nor tab field and a foreign
1087 std::string foreign_tag
= "foreign_tag";
1088 syncer::WriteTransaction
trans(FROM_HERE
, sync_service_
->GetUserShare());
1089 syncer::ReadNode
root(&trans
);
1090 root
.InitByTagLookup(syncer::ModelTypeToRootTag(syncer::SESSIONS
));
1091 syncer::WriteNode
extra_header(&trans
);
1092 syncer::WriteNode::InitUniqueByCreationResult result
=
1093 extra_header
.InitUniqueByCreation(syncer::SESSIONS
,
1095 ASSERT_EQ(syncer::WriteNode::INIT_SUCCESS
, result
);
1096 sync_pb::SessionSpecifics specifics
;
1097 specifics
.set_session_tag(foreign_tag
);
1098 extra_header
.SetSessionSpecifics(specifics
);
1100 error
= model_associator_
->AssociateModels(NULL
, NULL
);
1101 ASSERT_FALSE(error
.IsSet());
1104 // TODO(jhorwich): Re-enable when crbug.com/121487 addressed
1105 TEST_F(ProfileSyncServiceSessionTest
, DISABLED_MissingLocalTabNode
) {
1106 AddTab(browser(), GURL("http://foo1"));
1107 NavigateAndCommitActiveTab(GURL("http://foo2"));
1108 AddTab(browser(), GURL("http://bar1"));
1109 NavigateAndCommitActiveTab(GURL("http://bar2"));
1110 CreateRootHelper
create_root(this);
1111 ASSERT_TRUE(StartSyncService(create_root
.callback(), false));
1112 std::string local_tag
= model_associator_
->GetCurrentMachineTag();
1113 syncer::SyncError error
;
1115 error
= model_associator_
->DisassociateModels();
1116 ASSERT_FALSE(error
.IsSet());
1118 // Delete the first sync tab node.
1119 std::string tab_tag
= SessionModelAssociator::TabIdToTag(local_tag
, 0);
1121 syncer::WriteTransaction
trans(FROM_HERE
, sync_service_
->GetUserShare());
1122 syncer::ReadNode
root(&trans
);
1123 root
.InitByTagLookup(syncer::ModelTypeToRootTag(syncer::SESSIONS
));
1124 syncer::WriteNode
tab_node(&trans
);
1125 ASSERT_TRUE(tab_node
.InitByClientTagLookup(syncer::SESSIONS
, tab_tag
));
1128 error
= model_associator_
->AssociateModels(NULL
, NULL
);
1129 ASSERT_FALSE(error
.IsSet());
1131 // Add some more tabs to ensure we don't conflict with the pre-existing tab
1133 AddTab(browser(), GURL("http://baz1"));
1134 AddTab(browser(), GURL("http://baz2"));
1137 TEST_F(ProfileSyncServiceSessionTest
, Favicons
) {
1138 CreateRootHelper
create_root(this);
1139 ASSERT_TRUE(StartSyncService(create_root
.callback(), false));
1140 ASSERT_TRUE(create_root
.success());
1142 // Build a foreign session with one window and one tab.
1143 std::string tag
= "tag1";
1144 sync_pb::SessionSpecifics meta
;
1145 BuildSessionSpecifics(tag
, &meta
);
1146 std::vector
<SessionID::id_type
> tab_list
;
1147 tab_list
.push_back(5);
1148 AddWindowSpecifics(0, tab_list
, &meta
);
1149 sync_pb::SessionSpecifics tab
;
1150 BuildTabSpecifics(tag
, 0, tab_list
[0], &tab
);
1151 std::string url
= tab
.tab().navigation(0).virtual_url();
1152 std::string favicon
;
1154 // Update associator.
1155 model_associator_
->AssociateForeignSpecifics(meta
, base::Time());
1156 model_associator_
->AssociateForeignSpecifics(tab
, base::Time());
1157 ASSERT_FALSE(model_associator_
->GetSyncedFaviconForPageURL(url
, &favicon
));
1159 // Now add a favicon.
1160 tab
.mutable_tab()->set_favicon_source("http://favicon_source.com/png.ico");
1161 tab
.mutable_tab()->set_favicon_type(sync_pb::SessionTab::TYPE_WEB_FAVICON
);
1162 tab
.mutable_tab()->set_favicon("data");
1163 model_associator_
->AssociateForeignSpecifics(tab
, base::Time());
1164 ASSERT_TRUE(model_associator_
->GetSyncedFaviconForPageURL(url
, &favicon
));
1165 ASSERT_EQ("data", favicon
);
1167 // Simulate navigating away. The associator should delete the favicon.
1168 tab
.mutable_tab()->clear_navigation();
1169 tab
.mutable_tab()->add_navigation()->set_virtual_url("http://new_url.com");
1170 tab
.mutable_tab()->clear_favicon_source();
1171 tab
.mutable_tab()->clear_favicon_type();
1172 tab
.mutable_tab()->clear_favicon();
1173 model_associator_
->AssociateForeignSpecifics(tab
, base::Time());
1174 ASSERT_FALSE(model_associator_
->GetSyncedFaviconForPageURL(url
, &favicon
));
1177 // TODO(jhorwich): Re-enable when crbug.com/121487 addressed
1178 TEST_F(ProfileSyncServiceSessionTest
, DISABLED_CorruptedLocalHeader
) {
1179 AddTab(browser(), GURL("http://foo1"));
1180 NavigateAndCommitActiveTab(GURL("http://foo2"));
1181 AddTab(browser(), GURL("http://bar1"));
1182 NavigateAndCommitActiveTab(GURL("http://bar2"));
1183 CreateRootHelper
create_root(this);
1184 ASSERT_TRUE(StartSyncService(create_root
.callback(), false));
1185 std::string local_tag
= model_associator_
->GetCurrentMachineTag();
1186 syncer::SyncError error
;
1188 error
= model_associator_
->DisassociateModels();
1189 ASSERT_FALSE(error
.IsSet());
1191 // Load the header node and clear it.
1192 syncer::WriteTransaction
trans(FROM_HERE
, sync_service_
->GetUserShare());
1193 syncer::WriteNode
header(&trans
);
1194 ASSERT_EQ(syncer::BaseNode::INIT_OK
,
1195 header
.InitByClientTagLookup(syncer::SESSIONS
, local_tag
));
1196 sync_pb::SessionSpecifics specifics
;
1197 header
.SetSessionSpecifics(specifics
);
1199 // Ensure we associate properly despite the pre-existing node with our local
1201 error
= model_associator_
->AssociateModels(NULL
, NULL
);
1202 ASSERT_FALSE(error
.IsSet());
1205 } // namespace browser_sync