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. 4 5 #include <string> 6 #include <vector> 7 8 #include "base/memory/scoped_ptr.h" 9 #include "base/message_loop/message_loop.h" 10 #include "chrome/browser/chrome_notification_types.h" 11 #include "chrome/browser/sessions/session_types.h" 12 #include "chrome/browser/sync/glue/session_model_associator.h" 13 #include "chrome/browser/sync/glue/synced_tab_delegate.h" 14 #include "chrome/browser/sync/profile_sync_service_mock.h" 15 #include "chrome/common/url_constants.h" 16 #include "chrome/test/base/profile_mock.h" 17 #include "components/sessions/serialized_navigation_entry_test_helper.h" 18 #include "content/public/browser/navigation_entry.h" 19 #include "content/public/browser/notification_details.h" 20 #include "content/public/browser/notification_service.h" 21 #include "content/public/common/page_transition_types.h" 22 #include "content/public/test/test_browser_thread.h" 23 #include "sync/protocol/session_specifics.pb.h" 24 #include "sync/util/time.h" 25 #include "testing/gmock/include/gmock/gmock.h" 26 #include "testing/gtest/include/gtest/gtest.h" 27 #include "url/gurl.h" 28 29 using content::BrowserThread; 30 using sessions::SerializedNavigationEntry; 31 using sessions::SerializedNavigationEntryTestHelper; 32 using testing::NiceMock; 33 using testing::Return; 34 using testing::StrictMock; 35 using testing::_; 36 37 namespace browser_sync { 38 39 class SyncSessionModelAssociatorTest : public testing::Test { 40 protected: 41 SyncSessionModelAssociatorTest() 42 : ui_thread_(BrowserThread::UI, &message_loop_), 43 sync_service_(&profile_), 44 model_associator_(&sync_service_, true) {} 45 46 void LoadTabFavicon(const sync_pb::SessionTab& tab) { 47 model_associator_.LoadForeignTabFavicon(tab); 48 message_loop_.RunUntilIdle(); 49 } 50 51 static GURL GetCurrentVirtualURL(const SyncedTabDelegate& tab_delegate) { 52 return SessionModelAssociator::GetCurrentVirtualURL(tab_delegate); 53 } 54 55 static void SetSessionTabFromDelegate( 56 const SyncedTabDelegate& tab_delegate, 57 base::Time mtime, 58 SessionTab* session_tab) { 59 SessionModelAssociator::SetSessionTabFromDelegate( 60 tab_delegate, 61 mtime, 62 session_tab); 63 } 64 65 bool FaviconEquals(const GURL page_url, 66 std::string expected_bytes) { 67 FaviconCache* cache = model_associator_.GetFaviconCache(); 68 GURL gurl(page_url); 69 scoped_refptr<base::RefCountedMemory> favicon; 70 if (!cache->GetSyncedFaviconForPageURL(gurl, &favicon)) 71 return expected_bytes.empty(); 72 if (favicon->size() != expected_bytes.size()) 73 return false; 74 for (size_t i = 0; i < favicon->size(); ++i) { 75 if (expected_bytes[i] != *(favicon->front() + i)) 76 return false; 77 } 78 return true; 79 } 80 81 private: 82 base::MessageLoopForUI message_loop_; 83 content::TestBrowserThread ui_thread_; 84 NiceMock<ProfileMock> profile_; 85 NiceMock<ProfileSyncServiceMock> sync_service_; 86 87 protected: 88 SessionModelAssociator model_associator_; 89 }; 90 91 namespace { 92 93 TEST_F(SyncSessionModelAssociatorTest, SessionWindowHasNoTabsToSync) { 94 SessionWindow win; 95 ASSERT_TRUE(SessionWindowHasNoTabsToSync(win)); 96 scoped_ptr<SessionTab> tab(new SessionTab()); 97 win.tabs.push_back(tab.release()); 98 ASSERT_TRUE(SessionWindowHasNoTabsToSync(win)); 99 SerializedNavigationEntry nav = 100 SerializedNavigationEntryTestHelper::CreateNavigation("about:bubba", 101 "title"); 102 win.tabs[0]->navigations.push_back(nav); 103 ASSERT_FALSE(SessionWindowHasNoTabsToSync(win)); 104 } 105 106 TEST_F(SyncSessionModelAssociatorTest, ShouldSyncSessionTab) { 107 SessionTab tab; 108 ASSERT_FALSE(ShouldSyncSessionTab(tab)); 109 SerializedNavigationEntry nav = 110 SerializedNavigationEntryTestHelper::CreateNavigation( 111 chrome::kChromeUINewTabURL, "title"); 112 tab.navigations.push_back(nav); 113 // NewTab does not count as valid if it's the only navigation. 114 ASSERT_FALSE(ShouldSyncSessionTab(tab)); 115 SerializedNavigationEntry nav2 = 116 SerializedNavigationEntryTestHelper::CreateNavigation("about:bubba", 117 "title"); 118 tab.navigations.push_back(nav2); 119 // Once there's another navigation, the tab is valid. 120 ASSERT_TRUE(ShouldSyncSessionTab(tab)); 121 } 122 123 TEST_F(SyncSessionModelAssociatorTest, 124 ShouldSyncSessionTabIgnoresFragmentForNtp) { 125 SessionTab tab; 126 ASSERT_FALSE(ShouldSyncSessionTab(tab)); 127 SerializedNavigationEntry nav = 128 SerializedNavigationEntryTestHelper::CreateNavigation( 129 std::string(chrome::kChromeUINewTabURL) + "#bookmarks", "title"); 130 tab.navigations.push_back(nav); 131 // NewTab does not count as valid if it's the only navigation. 132 ASSERT_FALSE(ShouldSyncSessionTab(tab)); 133 } 134 135 } // namespace 136 137 TEST_F(SyncSessionModelAssociatorTest, PopulateSessionHeader) { 138 sync_pb::SessionHeader header_s; 139 header_s.set_client_name("Client 1"); 140 header_s.set_device_type(sync_pb::SyncEnums_DeviceType_TYPE_WIN); 141 142 SyncedSession session; 143 base::Time time = base::Time::Now(); 144 SessionModelAssociator::PopulateSessionHeaderFromSpecifics( 145 header_s, time, &session); 146 ASSERT_EQ("Client 1", session.session_name); 147 ASSERT_EQ(SyncedSession::TYPE_WIN, session.device_type); 148 ASSERT_EQ(time, session.modified_time); 149 } 150 151 TEST_F(SyncSessionModelAssociatorTest, PopulateSessionWindow) { 152 sync_pb::SessionWindow window_s; 153 window_s.add_tab(0); 154 window_s.set_browser_type(sync_pb::SessionWindow_BrowserType_TYPE_TABBED); 155 window_s.set_selected_tab_index(1); 156 157 std::string tag = "tag"; 158 SyncedSessionTracker tracker; 159 SyncedSession* session = tracker.GetSession(tag); 160 tracker.PutWindowInSession(tag, 0); 161 SessionModelAssociator::PopulateSessionWindowFromSpecifics( 162 tag, window_s, base::Time(), session->windows[0], &tracker); 163 ASSERT_EQ(1U, session->windows[0]->tabs.size()); 164 ASSERT_EQ(1, session->windows[0]->selected_tab_index); 165 ASSERT_EQ(1, session->windows[0]->type); 166 ASSERT_EQ(1U, tracker.num_synced_sessions()); 167 ASSERT_EQ(1U, tracker.num_synced_tabs(std::string("tag"))); 168 } 169 170 namespace { 171 172 class SyncedTabDelegateMock : public SyncedTabDelegate { 173 public: 174 SyncedTabDelegateMock() {} 175 virtual ~SyncedTabDelegateMock() {} 176 177 MOCK_CONST_METHOD0(GetWindowId, SessionID::id_type()); 178 MOCK_CONST_METHOD0(GetSessionId, SessionID::id_type()); 179 MOCK_CONST_METHOD0(IsBeingDestroyed, bool()); 180 MOCK_CONST_METHOD0(profile, Profile*()); 181 MOCK_CONST_METHOD0(GetExtensionAppId, std::string()); 182 MOCK_CONST_METHOD0(GetCurrentEntryIndex, int()); 183 MOCK_CONST_METHOD0(GetEntryCount, int()); 184 MOCK_CONST_METHOD0(GetPendingEntryIndex, int()); 185 MOCK_CONST_METHOD0(GetPendingEntry, content::NavigationEntry*()); 186 MOCK_CONST_METHOD1(GetEntryAtIndex, content::NavigationEntry*(int i)); 187 MOCK_CONST_METHOD0(GetActiveEntry, content::NavigationEntry*()); 188 MOCK_CONST_METHOD0(ProfileIsManaged, bool()); 189 MOCK_CONST_METHOD0(GetBlockedNavigations, 190 const std::vector<const content::NavigationEntry*>*()); 191 MOCK_CONST_METHOD0(IsPinned, bool()); 192 MOCK_CONST_METHOD0(HasWebContents, bool()); 193 MOCK_CONST_METHOD0(GetSyncId, int()); 194 MOCK_METHOD1(SetSyncId, void(int)); 195 }; 196 197 class SyncRefreshListener : public content::NotificationObserver { 198 public: 199 SyncRefreshListener() : notified_of_refresh_(false) { 200 registrar_.Add(this, chrome::NOTIFICATION_SYNC_REFRESH_LOCAL, 201 content::NotificationService::AllSources()); 202 } 203 204 virtual void Observe(int type, 205 const content::NotificationSource& source, 206 const content::NotificationDetails& details) OVERRIDE { 207 if (type == chrome::NOTIFICATION_SYNC_REFRESH_LOCAL) { 208 notified_of_refresh_ = true; 209 } 210 } 211 212 bool notified_of_refresh() const { return notified_of_refresh_; } 213 214 private: 215 bool notified_of_refresh_; 216 content::NotificationRegistrar registrar_; 217 }; 218 219 // Test that AttemptSessionsDataRefresh() triggers the 220 // NOTIFICATION_SYNC_REFRESH_LOCAL notification. 221 TEST_F(SyncSessionModelAssociatorTest, TriggerSessionRefresh) { 222 SyncRefreshListener refresh_listener; 223 224 EXPECT_FALSE(refresh_listener.notified_of_refresh()); 225 model_associator_.AttemptSessionsDataRefresh(); 226 EXPECT_TRUE(refresh_listener.notified_of_refresh()); 227 } 228 229 // Test that we exclude tabs with only chrome:// and file:// schemed navigations 230 // from ShouldSyncTab(..). 231 TEST_F(SyncSessionModelAssociatorTest, ValidTabs) { 232 NiceMock<SyncedTabDelegateMock> tab_mock; 233 234 // A null entry shouldn't crash. 235 EXPECT_CALL(tab_mock, GetCurrentEntryIndex()).WillRepeatedly(Return(0)); 236 EXPECT_CALL(tab_mock, GetEntryAtIndex(0)).WillRepeatedly( 237 Return((content::NavigationEntry *)NULL)); 238 EXPECT_CALL(tab_mock, GetEntryCount()).WillRepeatedly(Return(1)); 239 EXPECT_CALL(tab_mock, GetPendingEntryIndex()).WillRepeatedly(Return(-1)); 240 EXPECT_FALSE(model_associator_.ShouldSyncTab(tab_mock)); 241 242 // A chrome:// entry isn't valid. 243 scoped_ptr<content::NavigationEntry> entry( 244 content::NavigationEntry::Create()); 245 entry->SetVirtualURL(GURL("chrome://preferences/")); 246 testing::Mock::VerifyAndClearExpectations(&tab_mock); 247 EXPECT_CALL(tab_mock, GetCurrentEntryIndex()).WillRepeatedly(Return(0)); 248 EXPECT_CALL(tab_mock, GetEntryAtIndex(0)).WillRepeatedly(Return(entry.get())); 249 EXPECT_CALL(tab_mock, GetEntryCount()).WillRepeatedly(Return(1)); 250 EXPECT_CALL(tab_mock, GetPendingEntryIndex()).WillRepeatedly(Return(-1)); 251 EXPECT_FALSE(model_associator_.ShouldSyncTab(tab_mock)); 252 253 // A file:// entry isn't valid, even in addition to another entry. 254 scoped_ptr<content::NavigationEntry> entry2( 255 content::NavigationEntry::Create()); 256 entry2->SetVirtualURL(GURL("file://bla")); 257 testing::Mock::VerifyAndClearExpectations(&tab_mock); 258 EXPECT_CALL(tab_mock, GetCurrentEntryIndex()).WillRepeatedly(Return(0)); 259 EXPECT_CALL(tab_mock, GetEntryAtIndex(0)).WillRepeatedly(Return(entry.get())); 260 EXPECT_CALL(tab_mock, GetEntryAtIndex(1)).WillRepeatedly( 261 Return(entry2.get())); 262 EXPECT_CALL(tab_mock, GetEntryCount()).WillRepeatedly(Return(2)); 263 EXPECT_CALL(tab_mock, GetPendingEntryIndex()).WillRepeatedly(Return(-1)); 264 EXPECT_FALSE(model_associator_.ShouldSyncTab(tab_mock)); 265 266 // Add a valid scheme entry to tab, making the tab valid. 267 scoped_ptr<content::NavigationEntry> entry3( 268 content::NavigationEntry::Create()); 269 entry3->SetVirtualURL(GURL("http://www.google.com")); 270 testing::Mock::VerifyAndClearExpectations(&tab_mock); 271 EXPECT_CALL(tab_mock, GetCurrentEntryIndex()).WillRepeatedly(Return(0)); 272 EXPECT_CALL(tab_mock, GetEntryAtIndex(0)).WillRepeatedly( 273 Return(entry.get())); 274 EXPECT_CALL(tab_mock, GetEntryAtIndex(1)).WillRepeatedly( 275 Return(entry2.get())); 276 EXPECT_CALL(tab_mock, GetEntryAtIndex(2)).WillRepeatedly( 277 Return(entry3.get())); 278 EXPECT_CALL(tab_mock, GetEntryCount()).WillRepeatedly(Return(3)); 279 EXPECT_CALL(tab_mock, GetPendingEntryIndex()).WillRepeatedly(Return(-1)); 280 EXPECT_TRUE(model_associator_.ShouldSyncTab(tab_mock)); 281 } 282 283 // TODO(akalin): We should really use a fake for SyncedTabDelegate. 284 285 // Make sure GetCurrentVirtualURL() returns the virtual URL of the pending 286 // entry if the current entry is pending. 287 TEST_F(SyncSessionModelAssociatorTest, GetCurrentVirtualURLPending) { 288 StrictMock<SyncedTabDelegateMock> tab_mock; 289 scoped_ptr<content::NavigationEntry> entry( 290 content::NavigationEntry::Create()); 291 entry->SetVirtualURL(GURL("http://www.google.com")); 292 EXPECT_CALL(tab_mock, GetCurrentEntryIndex()).WillOnce(Return(0)); 293 EXPECT_CALL(tab_mock, GetPendingEntryIndex()).WillOnce(Return(0)); 294 EXPECT_CALL(tab_mock, GetPendingEntry()).WillOnce(Return(entry.get())); 295 EXPECT_EQ(entry->GetVirtualURL(), GetCurrentVirtualURL(tab_mock)); 296 } 297 298 // Make sure GetCurrentVirtualURL() returns the virtual URL of the current 299 // entry if the current entry is non-pending. 300 TEST_F(SyncSessionModelAssociatorTest, GetCurrentVirtualURLNonPending) { 301 StrictMock<SyncedTabDelegateMock> tab_mock; 302 scoped_ptr<content::NavigationEntry> entry( 303 content::NavigationEntry::Create()); 304 entry->SetVirtualURL(GURL("http://www.google.com")); 305 EXPECT_CALL(tab_mock, GetCurrentEntryIndex()).WillOnce(Return(0)); 306 EXPECT_CALL(tab_mock, GetPendingEntryIndex()).WillOnce(Return(-1)); 307 EXPECT_CALL(tab_mock, GetEntryAtIndex(0)).WillOnce(Return(entry.get())); 308 EXPECT_EQ(entry->GetVirtualURL(), GetCurrentVirtualURL(tab_mock)); 309 } 310 311 const base::Time kTime1 = base::Time::FromInternalValue(100); 312 const base::Time kTime2 = base::Time::FromInternalValue(105); 313 const base::Time kTime3 = base::Time::FromInternalValue(110); 314 const base::Time kTime4 = base::Time::FromInternalValue(120); 315 const base::Time kTime5 = base::Time::FromInternalValue(130); 316 317 // Populate the mock tab delegate with some data and navigation 318 // entries and make sure that setting a SessionTab from it preserves 319 // those entries (and clobbers any existing data). 320 TEST_F(SyncSessionModelAssociatorTest, SetSessionTabFromDelegate) { 321 // Create a tab with three valid entries. 322 NiceMock<SyncedTabDelegateMock> tab_mock; 323 EXPECT_CALL(tab_mock, GetSessionId()).WillRepeatedly(Return(0)); 324 scoped_ptr<content::NavigationEntry> entry1( 325 content::NavigationEntry::Create()); 326 entry1->SetVirtualURL(GURL("http://www.google.com")); 327 entry1->SetTimestamp(kTime1); 328 scoped_ptr<content::NavigationEntry> entry2( 329 content::NavigationEntry::Create()); 330 entry2->SetVirtualURL(GURL("http://www.noodle.com")); 331 entry2->SetTimestamp(kTime2); 332 scoped_ptr<content::NavigationEntry> entry3( 333 content::NavigationEntry::Create()); 334 entry3->SetVirtualURL(GURL("http://www.doodle.com")); 335 entry3->SetTimestamp(kTime3); 336 EXPECT_CALL(tab_mock, GetCurrentEntryIndex()).WillRepeatedly(Return(2)); 337 EXPECT_CALL(tab_mock, GetEntryAtIndex(0)).WillRepeatedly( 338 Return(entry1.get())); 339 EXPECT_CALL(tab_mock, GetEntryAtIndex(1)).WillRepeatedly( 340 Return(entry2.get())); 341 EXPECT_CALL(tab_mock, GetEntryAtIndex(2)).WillRepeatedly( 342 Return(entry3.get())); 343 EXPECT_CALL(tab_mock, GetEntryCount()).WillRepeatedly(Return(3)); 344 EXPECT_CALL(tab_mock, GetPendingEntryIndex()).WillRepeatedly(Return(-1)); 345 EXPECT_CALL(tab_mock, ProfileIsManaged()).WillRepeatedly(Return(false)); 346 347 SessionTab session_tab; 348 session_tab.window_id.set_id(1); 349 session_tab.tab_id.set_id(1); 350 session_tab.tab_visual_index = 1; 351 session_tab.current_navigation_index = 1; 352 session_tab.pinned = true; 353 session_tab.extension_app_id = "app id"; 354 session_tab.user_agent_override = "override"; 355 session_tab.timestamp = kTime5; 356 session_tab.navigations.push_back( 357 SerializedNavigationEntryTestHelper::CreateNavigation( 358 "http://www.example.com", "Example")); 359 session_tab.session_storage_persistent_id = "persistent id"; 360 SetSessionTabFromDelegate(tab_mock, kTime4, &session_tab); 361 362 EXPECT_EQ(0, session_tab.window_id.id()); 363 EXPECT_EQ(0, session_tab.tab_id.id()); 364 EXPECT_EQ(0, session_tab.tab_visual_index); 365 EXPECT_EQ(2, session_tab.current_navigation_index); 366 EXPECT_FALSE(session_tab.pinned); 367 EXPECT_TRUE(session_tab.extension_app_id.empty()); 368 EXPECT_TRUE(session_tab.user_agent_override.empty()); 369 EXPECT_EQ(kTime4, session_tab.timestamp); 370 ASSERT_EQ(3u, session_tab.navigations.size()); 371 EXPECT_EQ(entry1->GetVirtualURL(), 372 session_tab.navigations[0].virtual_url()); 373 EXPECT_EQ(entry2->GetVirtualURL(), 374 session_tab.navigations[1].virtual_url()); 375 EXPECT_EQ(entry3->GetVirtualURL(), 376 session_tab.navigations[2].virtual_url()); 377 EXPECT_EQ(kTime1, session_tab.navigations[0].timestamp()); 378 EXPECT_EQ(kTime2, session_tab.navigations[1].timestamp()); 379 EXPECT_EQ(kTime3, session_tab.navigations[2].timestamp()); 380 EXPECT_EQ(SerializedNavigationEntry::STATE_INVALID, 381 session_tab.navigations[0].blocked_state()); 382 EXPECT_EQ(SerializedNavigationEntry::STATE_INVALID, 383 session_tab.navigations[1].blocked_state()); 384 EXPECT_EQ(SerializedNavigationEntry::STATE_INVALID, 385 session_tab.navigations[2].blocked_state()); 386 EXPECT_TRUE(session_tab.session_storage_persistent_id.empty()); 387 } 388 389 // Tests that for managed users blocked navigations are recorded and marked as 390 // such, while regular navigations are marked as allowed. 391 TEST_F(SyncSessionModelAssociatorTest, BlockedNavigations) { 392 NiceMock<SyncedTabDelegateMock> tab_mock; 393 EXPECT_CALL(tab_mock, GetSessionId()).WillRepeatedly(Return(0)); 394 scoped_ptr<content::NavigationEntry> entry1( 395 content::NavigationEntry::Create()); 396 entry1->SetVirtualURL(GURL("http://www.google.com")); 397 entry1->SetTimestamp(kTime1); 398 EXPECT_CALL(tab_mock, GetCurrentEntryIndex()).WillRepeatedly(Return(0)); 399 EXPECT_CALL(tab_mock, GetEntryAtIndex(0)).WillRepeatedly( 400 Return(entry1.get())); 401 EXPECT_CALL(tab_mock, GetEntryCount()).WillRepeatedly(Return(1)); 402 EXPECT_CALL(tab_mock, GetPendingEntryIndex()).WillRepeatedly(Return(-1)); 403 404 content::NavigationEntry* entry2 = content::NavigationEntry::Create(); 405 entry2->SetVirtualURL(GURL("http://blocked.com/foo")); 406 entry2->SetTimestamp(kTime2); 407 content::NavigationEntry* entry3 = content::NavigationEntry::Create(); 408 entry3->SetVirtualURL(GURL("http://evil.com")); 409 entry3->SetTimestamp(kTime3); 410 ScopedVector<const content::NavigationEntry> blocked_navigations; 411 blocked_navigations.push_back(entry2); 412 blocked_navigations.push_back(entry3); 413 414 EXPECT_CALL(tab_mock, ProfileIsManaged()).WillRepeatedly(Return(true)); 415 EXPECT_CALL(tab_mock, GetBlockedNavigations()).WillRepeatedly( 416 Return(&blocked_navigations.get())); 417 418 SessionTab session_tab; 419 session_tab.window_id.set_id(1); 420 session_tab.tab_id.set_id(1); 421 session_tab.tab_visual_index = 1; 422 session_tab.current_navigation_index = 1; 423 session_tab.pinned = true; 424 session_tab.extension_app_id = "app id"; 425 session_tab.user_agent_override = "override"; 426 session_tab.timestamp = kTime5; 427 session_tab.navigations.push_back( 428 SerializedNavigationEntryTestHelper::CreateNavigation( 429 "http://www.example.com", "Example")); 430 session_tab.session_storage_persistent_id = "persistent id"; 431 SetSessionTabFromDelegate(tab_mock, kTime4, &session_tab); 432 433 EXPECT_EQ(0, session_tab.window_id.id()); 434 EXPECT_EQ(0, session_tab.tab_id.id()); 435 EXPECT_EQ(0, session_tab.tab_visual_index); 436 EXPECT_EQ(0, session_tab.current_navigation_index); 437 EXPECT_FALSE(session_tab.pinned); 438 EXPECT_TRUE(session_tab.extension_app_id.empty()); 439 EXPECT_TRUE(session_tab.user_agent_override.empty()); 440 EXPECT_EQ(kTime4, session_tab.timestamp); 441 ASSERT_EQ(3u, session_tab.navigations.size()); 442 EXPECT_EQ(entry1->GetVirtualURL(), 443 session_tab.navigations[0].virtual_url()); 444 EXPECT_EQ(entry2->GetVirtualURL(), 445 session_tab.navigations[1].virtual_url()); 446 EXPECT_EQ(entry3->GetVirtualURL(), 447 session_tab.navigations[2].virtual_url()); 448 EXPECT_EQ(kTime1, session_tab.navigations[0].timestamp()); 449 EXPECT_EQ(kTime2, session_tab.navigations[1].timestamp()); 450 EXPECT_EQ(kTime3, session_tab.navigations[2].timestamp()); 451 EXPECT_EQ(SerializedNavigationEntry::STATE_ALLOWED, 452 session_tab.navigations[0].blocked_state()); 453 EXPECT_EQ(SerializedNavigationEntry::STATE_BLOCKED, 454 session_tab.navigations[1].blocked_state()); 455 EXPECT_EQ(SerializedNavigationEntry::STATE_BLOCKED, 456 session_tab.navigations[2].blocked_state()); 457 EXPECT_TRUE(session_tab.session_storage_persistent_id.empty()); 458 } 459 460 // Create tab specifics with an empty favicon. Ensure it gets ignored and not 461 // stored into the synced favicon lookups. 462 TEST_F(SyncSessionModelAssociatorTest, LoadEmptyFavicon) { 463 std::string favicon; 464 std::string favicon_url = "http://www.faviconurl.com/favicon.ico"; 465 std::string page_url = "http://www.faviconurl.com/page.html"; 466 sync_pb::SessionTab tab; 467 tab.set_favicon(favicon); 468 tab.set_favicon_source(favicon_url); 469 tab.set_favicon_type(sync_pb::SessionTab::TYPE_WEB_FAVICON); 470 sync_pb::TabNavigation* navigation = tab.add_navigation(); 471 navigation->set_virtual_url(page_url); 472 tab.set_current_navigation_index(0); 473 474 EXPECT_TRUE(FaviconEquals(GURL(page_url), std::string())); 475 LoadTabFavicon(tab); 476 EXPECT_TRUE(FaviconEquals(GURL(page_url), std::string())); 477 } 478 479 // Create tab specifics with a non-web favicon. Ensure it gets ignored and not 480 // stored into the synced favicon lookups. 481 TEST_F(SyncSessionModelAssociatorTest, LoadNonWebFavicon) { 482 std::string favicon = "icon bytes"; 483 std::string favicon_url = "http://www.faviconurl.com/favicon.ico"; 484 std::string page_url = "http://www.faviconurl.com/page.html"; 485 sync_pb::SessionTab tab; 486 tab.set_favicon(favicon); 487 tab.set_favicon_source(favicon_url); 488 // Set favicon type to an unsupported value (1 == WEB_FAVICON). 489 tab.mutable_unknown_fields()->AddVarint(9, 2); 490 sync_pb::TabNavigation* navigation = tab.add_navigation(); 491 navigation->set_virtual_url(page_url); 492 tab.set_current_navigation_index(0); 493 494 EXPECT_TRUE(FaviconEquals(GURL(page_url), std::string())); 495 LoadTabFavicon(tab); 496 EXPECT_TRUE(FaviconEquals(GURL(page_url), std::string())); 497 } 498 499 // Create tab specifics with a valid favicon. Ensure it gets stored in the 500 // synced favicon lookups and is accessible by the page url. 501 TEST_F(SyncSessionModelAssociatorTest, LoadValidFavicon) { 502 std::string favicon = "icon bytes"; 503 std::string favicon_url = "http://www.faviconurl.com/favicon.ico"; 504 std::string page_url = "http://www.faviconurl.com/page.html"; 505 sync_pb::SessionTab tab; 506 tab.set_favicon(favicon); 507 tab.set_favicon_source(favicon_url); 508 tab.set_favicon_type(sync_pb::SessionTab::TYPE_WEB_FAVICON); 509 sync_pb::TabNavigation* navigation = tab.add_navigation(); 510 navigation->set_virtual_url(page_url); 511 tab.set_current_navigation_index(0); 512 513 EXPECT_TRUE(FaviconEquals(GURL(page_url), std::string())); 514 LoadTabFavicon(tab); 515 EXPECT_TRUE(FaviconEquals(GURL(page_url), favicon)); 516 } 517 518 // Create tab specifics with a valid favicon, load it, then load tab specifics 519 // with a new favicon for the same favicon source but different page. Ensure the 520 // old favicon remains. 521 TEST_F(SyncSessionModelAssociatorTest, UpdateValidFavicon) { 522 std::string favicon_url = "http://www.faviconurl.com/favicon.ico"; 523 524 std::string favicon = "icon bytes"; 525 std::string page_url = "http://www.faviconurl.com/page.html"; 526 sync_pb::SessionTab tab; 527 tab.set_favicon(favicon); 528 tab.set_favicon_source(favicon_url); 529 tab.set_favicon_type(sync_pb::SessionTab::TYPE_WEB_FAVICON); 530 sync_pb::TabNavigation* navigation = tab.add_navigation(); 531 navigation->set_virtual_url(page_url); 532 tab.set_current_navigation_index(0); 533 534 EXPECT_TRUE(FaviconEquals(GURL(page_url), std::string())); 535 LoadTabFavicon(tab); 536 EXPECT_TRUE(FaviconEquals(GURL(page_url), favicon)); 537 538 // Now have a new page with same favicon source but newer favicon data. 539 std::string favicon2 = "icon bytes 2"; 540 std::string page_url2 = "http://www.faviconurl.com/page2.html"; 541 sync_pb::SessionTab tab2; 542 tab2.set_favicon(favicon2); 543 tab2.set_favicon_source(favicon_url); 544 tab2.set_favicon_type(sync_pb::SessionTab::TYPE_WEB_FAVICON); 545 sync_pb::TabNavigation* navigation2 = tab2.add_navigation(); 546 navigation2->set_virtual_url(page_url2); 547 tab2.set_current_navigation_index(0); 548 549 // The new page should be mapped to the old favicon data. 550 EXPECT_TRUE(FaviconEquals(GURL(page_url2), std::string())); 551 LoadTabFavicon(tab2); 552 EXPECT_TRUE(FaviconEquals(GURL(page_url), favicon)); 553 EXPECT_TRUE(FaviconEquals(GURL(page_url2), favicon)); 554 } 555 556 } // namespace 557 558 } // namespace browser_sync 559