- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / sync / glue / session_model_associator_unittest.cc
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(GetWebContents, content::WebContents*());
194   MOCK_CONST_METHOD0(GetSyncId, int());
195   MOCK_METHOD1(SetSyncId, void(int));
196 };
197
198 class SyncRefreshListener : public content::NotificationObserver {
199  public:
200   SyncRefreshListener() : notified_of_refresh_(false) {
201     registrar_.Add(this, chrome::NOTIFICATION_SYNC_REFRESH_LOCAL,
202         content::NotificationService::AllSources());
203   }
204
205   virtual void Observe(int type,
206                        const content::NotificationSource& source,
207                        const content::NotificationDetails& details) OVERRIDE {
208     if (type == chrome::NOTIFICATION_SYNC_REFRESH_LOCAL) {
209       notified_of_refresh_ = true;
210     }
211   }
212
213   bool notified_of_refresh() const { return notified_of_refresh_; }
214
215  private:
216   bool notified_of_refresh_;
217   content::NotificationRegistrar registrar_;
218 };
219
220 // Test that AttemptSessionsDataRefresh() triggers the
221 // NOTIFICATION_SYNC_REFRESH_LOCAL notification.
222 TEST_F(SyncSessionModelAssociatorTest, TriggerSessionRefresh) {
223   SyncRefreshListener refresh_listener;
224
225   EXPECT_FALSE(refresh_listener.notified_of_refresh());
226   model_associator_.AttemptSessionsDataRefresh();
227   EXPECT_TRUE(refresh_listener.notified_of_refresh());
228 }
229
230 // Test that we exclude tabs with only chrome:// and file:// schemed navigations
231 // from ShouldSyncTab(..).
232 TEST_F(SyncSessionModelAssociatorTest, ValidTabs) {
233   NiceMock<SyncedTabDelegateMock> tab_mock;
234
235   // A null entry shouldn't crash.
236   EXPECT_CALL(tab_mock, GetCurrentEntryIndex()).WillRepeatedly(Return(0));
237   EXPECT_CALL(tab_mock, GetEntryAtIndex(0)).WillRepeatedly(
238       Return((content::NavigationEntry *)NULL));
239   EXPECT_CALL(tab_mock, GetEntryCount()).WillRepeatedly(Return(1));
240   EXPECT_CALL(tab_mock, GetPendingEntryIndex()).WillRepeatedly(Return(-1));
241   EXPECT_FALSE(model_associator_.ShouldSyncTab(tab_mock));
242
243   // A chrome:// entry isn't valid.
244   scoped_ptr<content::NavigationEntry> entry(
245       content::NavigationEntry::Create());
246   entry->SetVirtualURL(GURL("chrome://preferences/"));
247   testing::Mock::VerifyAndClearExpectations(&tab_mock);
248   EXPECT_CALL(tab_mock, GetCurrentEntryIndex()).WillRepeatedly(Return(0));
249   EXPECT_CALL(tab_mock, GetEntryAtIndex(0)).WillRepeatedly(Return(entry.get()));
250   EXPECT_CALL(tab_mock, GetEntryCount()).WillRepeatedly(Return(1));
251   EXPECT_CALL(tab_mock, GetPendingEntryIndex()).WillRepeatedly(Return(-1));
252   EXPECT_FALSE(model_associator_.ShouldSyncTab(tab_mock));
253
254   // A file:// entry isn't valid, even in addition to another entry.
255   scoped_ptr<content::NavigationEntry> entry2(
256       content::NavigationEntry::Create());
257   entry2->SetVirtualURL(GURL("file://bla"));
258   testing::Mock::VerifyAndClearExpectations(&tab_mock);
259   EXPECT_CALL(tab_mock, GetCurrentEntryIndex()).WillRepeatedly(Return(0));
260   EXPECT_CALL(tab_mock, GetEntryAtIndex(0)).WillRepeatedly(Return(entry.get()));
261   EXPECT_CALL(tab_mock, GetEntryAtIndex(1)).WillRepeatedly(
262       Return(entry2.get()));
263   EXPECT_CALL(tab_mock, GetEntryCount()).WillRepeatedly(Return(2));
264   EXPECT_CALL(tab_mock, GetPendingEntryIndex()).WillRepeatedly(Return(-1));
265   EXPECT_FALSE(model_associator_.ShouldSyncTab(tab_mock));
266
267   // Add a valid scheme entry to tab, making the tab valid.
268   scoped_ptr<content::NavigationEntry> entry3(
269       content::NavigationEntry::Create());
270   entry3->SetVirtualURL(GURL("http://www.google.com"));
271   testing::Mock::VerifyAndClearExpectations(&tab_mock);
272   EXPECT_CALL(tab_mock, GetCurrentEntryIndex()).WillRepeatedly(Return(0));
273   EXPECT_CALL(tab_mock, GetEntryAtIndex(0)).WillRepeatedly(
274       Return(entry.get()));
275   EXPECT_CALL(tab_mock, GetEntryAtIndex(1)).WillRepeatedly(
276       Return(entry2.get()));
277   EXPECT_CALL(tab_mock, GetEntryAtIndex(2)).WillRepeatedly(
278       Return(entry3.get()));
279   EXPECT_CALL(tab_mock, GetEntryCount()).WillRepeatedly(Return(3));
280   EXPECT_CALL(tab_mock, GetPendingEntryIndex()).WillRepeatedly(Return(-1));
281   EXPECT_TRUE(model_associator_.ShouldSyncTab(tab_mock));
282 }
283
284 // TODO(akalin): We should really use a fake for SyncedTabDelegate.
285
286 // Make sure GetCurrentVirtualURL() returns the virtual URL of the pending
287 // entry if the current entry is pending.
288 TEST_F(SyncSessionModelAssociatorTest, GetCurrentVirtualURLPending) {
289   StrictMock<SyncedTabDelegateMock> tab_mock;
290   scoped_ptr<content::NavigationEntry> entry(
291       content::NavigationEntry::Create());
292   entry->SetVirtualURL(GURL("http://www.google.com"));
293   EXPECT_CALL(tab_mock, GetCurrentEntryIndex()).WillOnce(Return(0));
294   EXPECT_CALL(tab_mock, GetPendingEntryIndex()).WillOnce(Return(0));
295   EXPECT_CALL(tab_mock, GetPendingEntry()).WillOnce(Return(entry.get()));
296   EXPECT_EQ(entry->GetVirtualURL(), GetCurrentVirtualURL(tab_mock));
297 }
298
299 // Make sure GetCurrentVirtualURL() returns the virtual URL of the current
300 // entry if the current entry is non-pending.
301 TEST_F(SyncSessionModelAssociatorTest, GetCurrentVirtualURLNonPending) {
302   StrictMock<SyncedTabDelegateMock> tab_mock;
303   scoped_ptr<content::NavigationEntry> entry(
304       content::NavigationEntry::Create());
305   entry->SetVirtualURL(GURL("http://www.google.com"));
306   EXPECT_CALL(tab_mock, GetCurrentEntryIndex()).WillOnce(Return(0));
307   EXPECT_CALL(tab_mock, GetPendingEntryIndex()).WillOnce(Return(-1));
308   EXPECT_CALL(tab_mock, GetEntryAtIndex(0)).WillOnce(Return(entry.get()));
309   EXPECT_EQ(entry->GetVirtualURL(), GetCurrentVirtualURL(tab_mock));
310 }
311
312 const base::Time kTime1 = base::Time::FromInternalValue(100);
313 const base::Time kTime2 = base::Time::FromInternalValue(105);
314 const base::Time kTime3 = base::Time::FromInternalValue(110);
315 const base::Time kTime4 = base::Time::FromInternalValue(120);
316 const base::Time kTime5 = base::Time::FromInternalValue(130);
317
318 // Populate the mock tab delegate with some data and navigation
319 // entries and make sure that setting a SessionTab from it preserves
320 // those entries (and clobbers any existing data).
321 TEST_F(SyncSessionModelAssociatorTest, SetSessionTabFromDelegate) {
322   // Create a tab with three valid entries.
323   NiceMock<SyncedTabDelegateMock> tab_mock;
324   EXPECT_CALL(tab_mock, GetSessionId()).WillRepeatedly(Return(0));
325   scoped_ptr<content::NavigationEntry> entry1(
326       content::NavigationEntry::Create());
327   entry1->SetVirtualURL(GURL("http://www.google.com"));
328   entry1->SetTimestamp(kTime1);
329   entry1->SetHttpStatusCode(200);
330   scoped_ptr<content::NavigationEntry> entry2(
331       content::NavigationEntry::Create());
332   entry2->SetVirtualURL(GURL("http://www.noodle.com"));
333   entry2->SetTimestamp(kTime2);
334   entry2->SetHttpStatusCode(201);
335   scoped_ptr<content::NavigationEntry> entry3(
336       content::NavigationEntry::Create());
337   entry3->SetVirtualURL(GURL("http://www.doodle.com"));
338   entry3->SetTimestamp(kTime3);
339   entry3->SetHttpStatusCode(202);
340   EXPECT_CALL(tab_mock, GetCurrentEntryIndex()).WillRepeatedly(Return(2));
341   EXPECT_CALL(tab_mock, GetEntryAtIndex(0)).WillRepeatedly(
342       Return(entry1.get()));
343   EXPECT_CALL(tab_mock, GetEntryAtIndex(1)).WillRepeatedly(
344       Return(entry2.get()));
345   EXPECT_CALL(tab_mock, GetEntryAtIndex(2)).WillRepeatedly(
346       Return(entry3.get()));
347   EXPECT_CALL(tab_mock, GetEntryCount()).WillRepeatedly(Return(3));
348   EXPECT_CALL(tab_mock, GetPendingEntryIndex()).WillRepeatedly(Return(-1));
349   EXPECT_CALL(tab_mock, ProfileIsManaged()).WillRepeatedly(Return(false));
350
351   SessionTab session_tab;
352   session_tab.window_id.set_id(1);
353   session_tab.tab_id.set_id(1);
354   session_tab.tab_visual_index = 1;
355   session_tab.current_navigation_index = 1;
356   session_tab.pinned = true;
357   session_tab.extension_app_id = "app id";
358   session_tab.user_agent_override = "override";
359   session_tab.timestamp = kTime5;
360   session_tab.navigations.push_back(
361       SerializedNavigationEntryTestHelper::CreateNavigation(
362           "http://www.example.com", "Example"));
363   session_tab.session_storage_persistent_id = "persistent id";
364   SetSessionTabFromDelegate(tab_mock, kTime4, &session_tab);
365
366   EXPECT_EQ(0, session_tab.window_id.id());
367   EXPECT_EQ(0, session_tab.tab_id.id());
368   EXPECT_EQ(0, session_tab.tab_visual_index);
369   EXPECT_EQ(2, session_tab.current_navigation_index);
370   EXPECT_FALSE(session_tab.pinned);
371   EXPECT_TRUE(session_tab.extension_app_id.empty());
372   EXPECT_TRUE(session_tab.user_agent_override.empty());
373   EXPECT_EQ(kTime4, session_tab.timestamp);
374   ASSERT_EQ(3u, session_tab.navigations.size());
375   EXPECT_EQ(entry1->GetVirtualURL(),
376             session_tab.navigations[0].virtual_url());
377   EXPECT_EQ(entry2->GetVirtualURL(),
378             session_tab.navigations[1].virtual_url());
379   EXPECT_EQ(entry3->GetVirtualURL(),
380             session_tab.navigations[2].virtual_url());
381   EXPECT_EQ(kTime1, session_tab.navigations[0].timestamp());
382   EXPECT_EQ(kTime2, session_tab.navigations[1].timestamp());
383   EXPECT_EQ(kTime3, session_tab.navigations[2].timestamp());
384   EXPECT_EQ(200, session_tab.navigations[0].http_status_code());
385   EXPECT_EQ(201, session_tab.navigations[1].http_status_code());
386   EXPECT_EQ(202, session_tab.navigations[2].http_status_code());
387   EXPECT_EQ(SerializedNavigationEntry::STATE_INVALID,
388             session_tab.navigations[0].blocked_state());
389   EXPECT_EQ(SerializedNavigationEntry::STATE_INVALID,
390             session_tab.navigations[1].blocked_state());
391   EXPECT_EQ(SerializedNavigationEntry::STATE_INVALID,
392             session_tab.navigations[2].blocked_state());
393   EXPECT_TRUE(session_tab.session_storage_persistent_id.empty());
394 }
395
396 // Tests that for managed users blocked navigations are recorded and marked as
397 // such, while regular navigations are marked as allowed.
398 TEST_F(SyncSessionModelAssociatorTest, BlockedNavigations) {
399   NiceMock<SyncedTabDelegateMock> tab_mock;
400   EXPECT_CALL(tab_mock, GetSessionId()).WillRepeatedly(Return(0));
401   scoped_ptr<content::NavigationEntry> entry1(
402       content::NavigationEntry::Create());
403   entry1->SetVirtualURL(GURL("http://www.google.com"));
404   entry1->SetTimestamp(kTime1);
405   EXPECT_CALL(tab_mock, GetCurrentEntryIndex()).WillRepeatedly(Return(0));
406   EXPECT_CALL(tab_mock, GetEntryAtIndex(0)).WillRepeatedly(
407       Return(entry1.get()));
408   EXPECT_CALL(tab_mock, GetEntryCount()).WillRepeatedly(Return(1));
409   EXPECT_CALL(tab_mock, GetPendingEntryIndex()).WillRepeatedly(Return(-1));
410
411   content::NavigationEntry* entry2 = content::NavigationEntry::Create();
412   entry2->SetVirtualURL(GURL("http://blocked.com/foo"));
413   entry2->SetTimestamp(kTime2);
414   content::NavigationEntry* entry3 = content::NavigationEntry::Create();
415   entry3->SetVirtualURL(GURL("http://evil.com"));
416   entry3->SetTimestamp(kTime3);
417   ScopedVector<const content::NavigationEntry> blocked_navigations;
418   blocked_navigations.push_back(entry2);
419   blocked_navigations.push_back(entry3);
420
421   EXPECT_CALL(tab_mock, ProfileIsManaged()).WillRepeatedly(Return(true));
422   EXPECT_CALL(tab_mock, GetBlockedNavigations()).WillRepeatedly(
423       Return(&blocked_navigations.get()));
424
425   SessionTab session_tab;
426   session_tab.window_id.set_id(1);
427   session_tab.tab_id.set_id(1);
428   session_tab.tab_visual_index = 1;
429   session_tab.current_navigation_index = 1;
430   session_tab.pinned = true;
431   session_tab.extension_app_id = "app id";
432   session_tab.user_agent_override = "override";
433   session_tab.timestamp = kTime5;
434   session_tab.navigations.push_back(
435       SerializedNavigationEntryTestHelper::CreateNavigation(
436           "http://www.example.com", "Example"));
437   session_tab.session_storage_persistent_id = "persistent id";
438   SetSessionTabFromDelegate(tab_mock, kTime4, &session_tab);
439
440   EXPECT_EQ(0, session_tab.window_id.id());
441   EXPECT_EQ(0, session_tab.tab_id.id());
442   EXPECT_EQ(0, session_tab.tab_visual_index);
443   EXPECT_EQ(0, session_tab.current_navigation_index);
444   EXPECT_FALSE(session_tab.pinned);
445   EXPECT_TRUE(session_tab.extension_app_id.empty());
446   EXPECT_TRUE(session_tab.user_agent_override.empty());
447   EXPECT_EQ(kTime4, session_tab.timestamp);
448   ASSERT_EQ(3u, session_tab.navigations.size());
449   EXPECT_EQ(entry1->GetVirtualURL(),
450             session_tab.navigations[0].virtual_url());
451   EXPECT_EQ(entry2->GetVirtualURL(),
452             session_tab.navigations[1].virtual_url());
453   EXPECT_EQ(entry3->GetVirtualURL(),
454             session_tab.navigations[2].virtual_url());
455   EXPECT_EQ(kTime1, session_tab.navigations[0].timestamp());
456   EXPECT_EQ(kTime2, session_tab.navigations[1].timestamp());
457   EXPECT_EQ(kTime3, session_tab.navigations[2].timestamp());
458   EXPECT_EQ(SerializedNavigationEntry::STATE_ALLOWED,
459             session_tab.navigations[0].blocked_state());
460   EXPECT_EQ(SerializedNavigationEntry::STATE_BLOCKED,
461             session_tab.navigations[1].blocked_state());
462   EXPECT_EQ(SerializedNavigationEntry::STATE_BLOCKED,
463             session_tab.navigations[2].blocked_state());
464   EXPECT_TRUE(session_tab.session_storage_persistent_id.empty());
465 }
466
467 // Create tab specifics with an empty favicon. Ensure it gets ignored and not
468 // stored into the synced favicon lookups.
469 TEST_F(SyncSessionModelAssociatorTest, LoadEmptyFavicon) {
470   std::string favicon;
471   std::string favicon_url = "http://www.faviconurl.com/favicon.ico";
472   std::string page_url = "http://www.faviconurl.com/page.html";
473   sync_pb::SessionTab tab;
474   tab.set_favicon(favicon);
475   tab.set_favicon_source(favicon_url);
476   tab.set_favicon_type(sync_pb::SessionTab::TYPE_WEB_FAVICON);
477   sync_pb::TabNavigation* navigation = tab.add_navigation();
478   navigation->set_virtual_url(page_url);
479   tab.set_current_navigation_index(0);
480
481   EXPECT_TRUE(FaviconEquals(GURL(page_url), std::string()));
482   LoadTabFavicon(tab);
483   EXPECT_TRUE(FaviconEquals(GURL(page_url), std::string()));
484 }
485
486 // Create tab specifics with a non-web favicon. Ensure it gets ignored and not
487 // stored into the synced favicon lookups.
488 TEST_F(SyncSessionModelAssociatorTest, LoadNonWebFavicon) {
489   std::string favicon = "icon bytes";
490   std::string favicon_url = "http://www.faviconurl.com/favicon.ico";
491   std::string page_url = "http://www.faviconurl.com/page.html";
492   sync_pb::SessionTab tab;
493   tab.set_favicon(favicon);
494   tab.set_favicon_source(favicon_url);
495   // Set favicon type to an unsupported value (1 == WEB_FAVICON).
496   tab.mutable_unknown_fields()->AddVarint(9, 2);
497   sync_pb::TabNavigation* navigation = tab.add_navigation();
498   navigation->set_virtual_url(page_url);
499   tab.set_current_navigation_index(0);
500
501   EXPECT_TRUE(FaviconEquals(GURL(page_url), std::string()));
502   LoadTabFavicon(tab);
503   EXPECT_TRUE(FaviconEquals(GURL(page_url), std::string()));
504 }
505
506 // Create tab specifics with a valid favicon. Ensure it gets stored in the
507 // synced favicon lookups and is accessible by the page url.
508 TEST_F(SyncSessionModelAssociatorTest, LoadValidFavicon) {
509   std::string favicon = "icon bytes";
510   std::string favicon_url = "http://www.faviconurl.com/favicon.ico";
511   std::string page_url = "http://www.faviconurl.com/page.html";
512   sync_pb::SessionTab tab;
513   tab.set_favicon(favicon);
514   tab.set_favicon_source(favicon_url);
515   tab.set_favicon_type(sync_pb::SessionTab::TYPE_WEB_FAVICON);
516   sync_pb::TabNavigation* navigation = tab.add_navigation();
517   navigation->set_virtual_url(page_url);
518   tab.set_current_navigation_index(0);
519
520   EXPECT_TRUE(FaviconEquals(GURL(page_url), std::string()));
521   LoadTabFavicon(tab);
522   EXPECT_TRUE(FaviconEquals(GURL(page_url), favicon));
523 }
524
525 // Create tab specifics with a valid favicon, load it, then load tab specifics
526 // with a new favicon for the same favicon source but different page. Ensure the
527 // old favicon remains.
528 TEST_F(SyncSessionModelAssociatorTest, UpdateValidFavicon) {
529   std::string favicon_url = "http://www.faviconurl.com/favicon.ico";
530
531   std::string favicon = "icon bytes";
532   std::string page_url = "http://www.faviconurl.com/page.html";
533   sync_pb::SessionTab tab;
534   tab.set_favicon(favicon);
535   tab.set_favicon_source(favicon_url);
536   tab.set_favicon_type(sync_pb::SessionTab::TYPE_WEB_FAVICON);
537   sync_pb::TabNavigation* navigation = tab.add_navigation();
538   navigation->set_virtual_url(page_url);
539   tab.set_current_navigation_index(0);
540
541   EXPECT_TRUE(FaviconEquals(GURL(page_url), std::string()));
542   LoadTabFavicon(tab);
543   EXPECT_TRUE(FaviconEquals(GURL(page_url), favicon));
544
545   // Now have a new page with same favicon source but newer favicon data.
546   std::string favicon2 = "icon bytes 2";
547   std::string page_url2 = "http://www.faviconurl.com/page2.html";
548   sync_pb::SessionTab tab2;
549   tab2.set_favicon(favicon2);
550   tab2.set_favicon_source(favicon_url);
551   tab2.set_favicon_type(sync_pb::SessionTab::TYPE_WEB_FAVICON);
552   sync_pb::TabNavigation* navigation2 = tab2.add_navigation();
553   navigation2->set_virtual_url(page_url2);
554   tab2.set_current_navigation_index(0);
555
556   // The new page should be mapped to the old favicon data.
557   EXPECT_TRUE(FaviconEquals(GURL(page_url2), std::string()));
558   LoadTabFavicon(tab2);
559   EXPECT_TRUE(FaviconEquals(GURL(page_url), favicon));
560   EXPECT_TRUE(FaviconEquals(GURL(page_url2), favicon));
561 }
562
563 }  // namespace
564
565 }  // namespace browser_sync