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.
8 #include "base/memory/scoped_ptr.h"
9 #include "base/rand_util.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "chrome/browser/sessions/session_types.h"
13 #include "chrome/browser/sync/glue/synced_session_tracker.h"
14 #include "components/sessions/serialized_navigation_entry_test_helper.h"
15 #include "testing/gtest/include/gtest/gtest.h"
17 namespace browser_sync
{
19 typedef testing::Test SyncedSessionTrackerTest
;
21 TEST_F(SyncedSessionTrackerTest
, GetSession
) {
22 SyncedSessionTracker tracker
;
23 SyncedSession
* session1
= tracker
.GetSession("tag");
24 SyncedSession
* session2
= tracker
.GetSession("tag2");
25 ASSERT_EQ(session1
, tracker
.GetSession("tag"));
26 ASSERT_NE(session1
, session2
);
27 // Should clean up memory on its own.
30 TEST_F(SyncedSessionTrackerTest
, GetTabUnmapped
) {
31 SyncedSessionTracker tracker
;
32 SessionTab
* tab
= tracker
.GetTab("tag", 0, 0);
33 ASSERT_EQ(tab
, tracker
.GetTab("tag", 0, 0));
34 // Should clean up memory on its own.
37 TEST_F(SyncedSessionTrackerTest
, PutWindowInSession
) {
38 SyncedSessionTracker tracker
;
39 tracker
.PutWindowInSession("tag", 0);
40 SyncedSession
* session
= tracker
.GetSession("tag");
41 ASSERT_EQ(1U, session
->windows
.size());
42 // Should clean up memory on its own.
45 TEST_F(SyncedSessionTrackerTest
, PutTabInWindow
) {
46 SyncedSessionTracker tracker
;
47 tracker
.PutWindowInSession("tag", 10);
48 tracker
.PutTabInWindow("tag", 10, 15, 0); // win id 10, tab id 15, tab ind 0.
49 SyncedSession
* session
= tracker
.GetSession("tag");
50 ASSERT_EQ(1U, session
->windows
.size());
51 ASSERT_EQ(1U, session
->windows
[10]->tabs
.size());
52 ASSERT_EQ(tracker
.GetTab("tag", 15, 1), session
->windows
[10]->tabs
[0]);
53 // Should clean up memory on its own.
56 TEST_F(SyncedSessionTrackerTest
, LookupAllForeignSessions
) {
57 SyncedSessionTracker tracker
;
58 std::vector
<const SyncedSession
*> sessions
;
59 ASSERT_FALSE(tracker
.LookupAllForeignSessions(&sessions
));
60 tracker
.GetSession("tag1");
61 tracker
.GetSession("tag2");
62 tracker
.PutWindowInSession("tag1", 0);
63 tracker
.PutTabInWindow("tag1", 0, 15, 0);
64 SessionTab
* tab
= tracker
.GetTab("tag1", 15, 1);
66 tab
->navigations
.push_back(
67 sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
68 "bla://valid_url", "title"));
69 ASSERT_TRUE(tracker
.LookupAllForeignSessions(&sessions
));
70 // Only the session with a valid window and tab gets returned.
71 ASSERT_EQ(1U, sessions
.size());
72 ASSERT_EQ("tag1", sessions
[0]->session_tag
);
75 TEST_F(SyncedSessionTrackerTest
, LookupSessionWindows
) {
76 SyncedSessionTracker tracker
;
77 std::vector
<const SessionWindow
*> windows
;
78 ASSERT_FALSE(tracker
.LookupSessionWindows("tag1", &windows
));
79 tracker
.GetSession("tag1");
80 tracker
.PutWindowInSession("tag1", 0);
81 tracker
.PutWindowInSession("tag1", 2);
82 tracker
.GetSession("tag2");
83 tracker
.PutWindowInSession("tag2", 0);
84 tracker
.PutWindowInSession("tag2", 2);
85 ASSERT_TRUE(tracker
.LookupSessionWindows("tag1", &windows
));
86 ASSERT_EQ(2U, windows
.size()); // Only windows from tag1 session.
87 ASSERT_NE((SessionWindow
*)NULL
, windows
[0]);
88 ASSERT_NE((SessionWindow
*)NULL
, windows
[1]);
89 ASSERT_NE(windows
[1], windows
[0]);
92 TEST_F(SyncedSessionTrackerTest
, LookupSessionTab
) {
93 SyncedSessionTracker tracker
;
94 const SessionTab
* tab
;
95 ASSERT_FALSE(tracker
.LookupSessionTab("tag1", 5, &tab
));
96 tracker
.GetSession("tag1");
97 tracker
.PutWindowInSession("tag1", 0);
98 tracker
.PutTabInWindow("tag1", 0, 5, 0);
99 ASSERT_TRUE(tracker
.LookupSessionTab("tag1", 5, &tab
));
100 ASSERT_NE((SessionTab
*)NULL
, tab
);
103 TEST_F(SyncedSessionTrackerTest
, Complex
) {
104 const std::string tag1
= "tag";
105 const std::string tag2
= "tag2";
106 const std::string tag3
= "tag3";
107 SyncedSessionTracker tracker
;
108 std::vector
<SessionTab
*> tabs1
, tabs2
;
109 SessionTab
* temp_tab
;
110 ASSERT_TRUE(tracker
.Empty());
111 ASSERT_EQ(0U, tracker
.num_synced_sessions());
112 ASSERT_EQ(0U, tracker
.num_synced_tabs(tag1
));
113 tabs1
.push_back(tracker
.GetTab(tag1
, 0, 0));
114 tabs1
.push_back(tracker
.GetTab(tag1
, 1, 1));
115 tabs1
.push_back(tracker
.GetTab(tag1
, 2, 2));
116 ASSERT_EQ(3U, tracker
.num_synced_tabs(tag1
));
117 ASSERT_EQ(0U, tracker
.num_synced_sessions());
118 temp_tab
= tracker
.GetTab(tag1
, 0, 0); // Already created.
119 ASSERT_EQ(3U, tracker
.num_synced_tabs(tag1
));
120 ASSERT_EQ(0U, tracker
.num_synced_sessions());
121 ASSERT_EQ(tabs1
[0], temp_tab
);
122 tabs2
.push_back(tracker
.GetTab(tag2
, 0, 0));
123 ASSERT_EQ(1U, tracker
.num_synced_tabs(tag2
));
124 ASSERT_EQ(0U, tracker
.num_synced_sessions());
125 ASSERT_FALSE(tracker
.DeleteSession(tag3
));
127 SyncedSession
* session
= tracker
.GetSession(tag1
);
128 SyncedSession
* session2
= tracker
.GetSession(tag2
);
129 SyncedSession
* session3
= tracker
.GetSession(tag3
);
130 ASSERT_EQ(3U, tracker
.num_synced_sessions());
132 ASSERT_TRUE(session
);
133 ASSERT_TRUE(session2
);
134 ASSERT_TRUE(session3
);
135 ASSERT_NE(session
, session2
);
136 ASSERT_NE(session2
, session3
);
137 ASSERT_TRUE(tracker
.DeleteSession(tag3
));
138 ASSERT_EQ(2U, tracker
.num_synced_sessions());
140 tracker
.PutWindowInSession(tag1
, 0); // Create a window.
141 tracker
.PutTabInWindow(tag1
, 0, 2, 0); // No longer unmapped.
142 ASSERT_EQ(3U, tracker
.num_synced_tabs(tag1
)); // Has not changed.
144 const SessionTab
*tab_ptr
;
145 ASSERT_TRUE(tracker
.LookupSessionTab(tag1
, 0, &tab_ptr
));
146 ASSERT_EQ(tab_ptr
, tabs1
[0]);
147 ASSERT_TRUE(tracker
.LookupSessionTab(tag1
, 2, &tab_ptr
));
148 ASSERT_EQ(tab_ptr
, tabs1
[2]);
149 ASSERT_FALSE(tracker
.LookupSessionTab(tag1
, 3, &tab_ptr
));
150 ASSERT_EQ(static_cast<const SessionTab
*>(NULL
), tab_ptr
);
152 std::vector
<const SessionWindow
*> windows
;
153 ASSERT_TRUE(tracker
.LookupSessionWindows(tag1
, &windows
));
154 ASSERT_EQ(1U, windows
.size());
155 ASSERT_TRUE(tracker
.LookupSessionWindows(tag2
, &windows
));
156 ASSERT_EQ(0U, windows
.size());
158 // The sessions don't have valid tabs, lookup should not succeed.
159 std::vector
<const SyncedSession
*> sessions
;
160 ASSERT_FALSE(tracker
.LookupAllForeignSessions(&sessions
));
163 ASSERT_EQ(0U, tracker
.num_synced_tabs(tag1
));
164 ASSERT_EQ(0U, tracker
.num_synced_tabs(tag2
));
165 ASSERT_EQ(0U, tracker
.num_synced_sessions());
168 TEST_F(SyncedSessionTrackerTest
, ManyGetTabs
) {
169 SyncedSessionTracker tracker
;
170 ASSERT_TRUE(tracker
.Empty());
171 const int kMaxSessions
= 10;
172 const int kMaxTabs
= 1000;
173 const int kMaxAttempts
= 10000;
174 for (int j
=0; j
<kMaxSessions
; ++j
) {
175 std::string tag
= base::StringPrintf("tag%d", j
);
176 for (int i
=0; i
<kMaxAttempts
; ++i
) {
177 // More attempts than tabs means we'll sometimes get the same tabs,
178 // sometimes have to allocate new tabs.
179 int rand_tab_num
= base::RandInt(0, kMaxTabs
);
180 SessionTab
* tab
= tracker
.GetTab(tag
, rand_tab_num
, rand_tab_num
+ 1);
186 TEST_F(SyncedSessionTrackerTest
, LookupTabNodeIds
) {
187 SyncedSessionTracker tracker
;
188 std::set
<int> result
;
189 std::string tag1
= "session1";
190 std::string tag2
= "session2";
191 std::string tag3
= "session3";
193 tracker
.GetTab(tag1
, 1, 1);
194 tracker
.GetTab(tag1
, 2, 2);
195 EXPECT_TRUE(tracker
.LookupTabNodeIds(tag1
, &result
));
196 EXPECT_EQ(2U, result
.size());
197 EXPECT_FALSE(result
.end() == result
.find(1));
198 EXPECT_FALSE(result
.end() == result
.find(2));
199 EXPECT_FALSE(tracker
.LookupTabNodeIds(tag2
, &result
));
201 tracker
.PutWindowInSession(tag1
, 0);
202 tracker
.PutTabInWindow(tag1
, 0, 3, 0);
203 EXPECT_TRUE(tracker
.LookupTabNodeIds(tag1
, &result
));
204 EXPECT_EQ(2U, result
.size());
206 tracker
.GetTab(tag1
, 3, 3);
207 EXPECT_TRUE(tracker
.LookupTabNodeIds(tag1
, &result
));
208 EXPECT_EQ(3U, result
.size());
209 EXPECT_FALSE(result
.end() == result
.find(3));
211 tracker
.GetTab(tag2
, 1, 21);
212 tracker
.GetTab(tag2
, 2, 22);
213 EXPECT_TRUE(tracker
.LookupTabNodeIds(tag2
, &result
));
214 EXPECT_EQ(2U, result
.size());
215 EXPECT_FALSE(result
.end() == result
.find(21));
216 EXPECT_FALSE(result
.end() == result
.find(22));
217 EXPECT_TRUE(tracker
.LookupTabNodeIds(tag1
, &result
));
218 EXPECT_EQ(3U, result
.size());
219 EXPECT_FALSE(result
.end() == result
.find(1));
220 EXPECT_FALSE(result
.end() == result
.find(2));
222 EXPECT_FALSE(tracker
.LookupTabNodeIds(tag3
, &result
));
223 tracker
.PutWindowInSession(tag3
, 1);
224 tracker
.PutTabInWindow(tag3
, 1, 5, 0);
225 EXPECT_TRUE(tracker
.LookupTabNodeIds(tag3
, &result
));
226 EXPECT_TRUE(result
.empty());
227 EXPECT_TRUE(tracker
.DeleteSession(tag3
));
228 EXPECT_FALSE(tracker
.LookupTabNodeIds(tag3
, &result
));
230 EXPECT_TRUE(tracker
.DeleteSession(tag1
));
231 EXPECT_FALSE(tracker
.LookupTabNodeIds(tag1
, &result
));
232 EXPECT_TRUE(tracker
.LookupTabNodeIds(tag2
, &result
));
233 EXPECT_EQ(2U, result
.size());
234 EXPECT_FALSE(result
.end() == result
.find(21));
235 EXPECT_FALSE(result
.end() == result
.find(22));
236 EXPECT_TRUE(tracker
.DeleteSession(tag2
));
237 EXPECT_FALSE(tracker
.LookupTabNodeIds(tag2
, &result
));
240 TEST_F(SyncedSessionTrackerTest
, SessionTracking
) {
241 SyncedSessionTracker tracker
;
242 ASSERT_TRUE(tracker
.Empty());
243 std::string tag1
= "tag1";
244 std::string tag2
= "tag2";
246 // Create some session information that is stale.
247 SyncedSession
* session1
= tracker
.GetSession(tag1
);
248 tracker
.PutWindowInSession(tag1
, 0);
249 tracker
.PutTabInWindow(tag1
, 0, 0, 0);
250 tracker
.PutTabInWindow(tag1
, 0, 1, 1);
251 tracker
.GetTab(tag1
, 2, 3U)->window_id
.set_id(0); // Will be unmapped.
252 tracker
.GetTab(tag1
, 3, 4U)->window_id
.set_id(0); // Will be unmapped.
253 tracker
.PutWindowInSession(tag1
, 1);
254 tracker
.PutTabInWindow(tag1
, 1, 4, 0);
255 tracker
.PutTabInWindow(tag1
, 1, 5, 1);
256 ASSERT_EQ(2U, session1
->windows
.size());
257 ASSERT_EQ(2U, session1
->windows
[0]->tabs
.size());
258 ASSERT_EQ(2U, session1
->windows
[1]->tabs
.size());
259 ASSERT_EQ(6U, tracker
.num_synced_tabs(tag1
));
261 // Create a session that should not be affected.
262 SyncedSession
* session2
= tracker
.GetSession(tag2
);
263 tracker
.PutWindowInSession(tag2
, 2);
264 tracker
.PutTabInWindow(tag2
, 2, 1, 0);
265 ASSERT_EQ(1U, session2
->windows
.size());
266 ASSERT_EQ(1U, session2
->windows
[2]->tabs
.size());
267 ASSERT_EQ(1U, tracker
.num_synced_tabs(tag2
));
269 // Reset tracking and get the current windows/tabs.
270 // We simulate moving a tab from one window to another, then closing the
271 // first window (including its one remaining tab), and opening a new tab
272 // on the remaining window.
274 // New tab, arrived before meta node so unmapped.
275 tracker
.GetTab(tag1
, 6, 7U);
276 tracker
.ResetSessionTracking(tag1
);
277 tracker
.PutWindowInSession(tag1
, 0);
278 tracker
.PutTabInWindow(tag1
, 0, 0, 0);
280 tracker
.PutTabInWindow(tag1
, 0, 2, 1); // No longer unmapped.
281 // Tab 3 was unmapped and does not get used.
282 tracker
.PutTabInWindow(tag1
, 0, 4, 2); // Moved from window 1.
283 // Window 1 was closed, along with tab 5.
284 tracker
.PutTabInWindow(tag1
, 0, 6, 3); // No longer unmapped.
285 // Session 2 should not be affected.
286 tracker
.CleanupSession(tag1
);
288 // Verify that only those parts of the session not owned have been removed.
289 ASSERT_EQ(1U, session1
->windows
.size());
290 ASSERT_EQ(4U, session1
->windows
[0]->tabs
.size());
291 ASSERT_EQ(1U, session2
->windows
.size());
292 ASSERT_EQ(1U, session2
->windows
[2]->tabs
.size());
293 ASSERT_EQ(2U, tracker
.num_synced_sessions());
294 ASSERT_EQ(4U, tracker
.num_synced_tabs(tag1
));
295 ASSERT_EQ(1U, tracker
.num_synced_tabs(tag2
));
297 // All memory should be properly deallocated by destructor for the
298 // SyncedSessionTracker.
301 } // namespace browser_sync