OLD | NEW |
| (Empty) |
1 // Copyright (c) 2006-2008 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 <vector> | |
6 #include <string> | |
7 #include <cstdio> | |
8 | |
9 #include "base/message_loop.h" | |
10 #include "base/file_util.h" | |
11 #include "base/path_service.h" | |
12 #include "base/process_util.h" | |
13 #include "base/shared_memory.h" | |
14 #include "base/string_util.h" | |
15 #include "chrome/browser/browser_thread.h" | |
16 #include "chrome/browser/visitedlink_master.h" | |
17 #include "chrome/browser/visitedlink_event_listener.h" | |
18 #include "chrome/browser/renderer_host/browser_render_process_host.h" | |
19 #include "chrome/browser/renderer_host/test/test_render_view_host.h" | |
20 #include "chrome/common/render_messages.h" | |
21 #include "chrome/renderer/visitedlink_slave.h" | |
22 #include "chrome/test/testing_profile.h" | |
23 #include "googleurl/src/gurl.h" | |
24 #include "testing/gtest/include/gtest/gtest.h" | |
25 | |
26 namespace { | |
27 | |
28 // a nice long URL that we can append numbers to to get new URLs | |
29 const char g_test_prefix[] = | |
30 "http://www.google.com/products/foo/index.html?id=45028640526508376&seq="; | |
31 const int g_test_count = 1000; | |
32 | |
33 // Returns a test URL for index |i| | |
34 GURL TestURL(int i) { | |
35 return GURL(StringPrintf("%s%d", g_test_prefix, i)); | |
36 } | |
37 | |
38 std::vector<VisitedLinkSlave*> g_slaves; | |
39 | |
40 } // namespace | |
41 | |
42 class TrackingVisitedLinkEventListener : public VisitedLinkMaster::Listener { | |
43 public: | |
44 TrackingVisitedLinkEventListener() | |
45 : reset_count_(0), | |
46 add_count_(0) {} | |
47 | |
48 virtual void NewTable(base::SharedMemory* table) { | |
49 if (table) { | |
50 for (std::vector<VisitedLinkSlave>::size_type i = 0; | |
51 i < g_slaves.size(); i++) { | |
52 base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle(); | |
53 table->ShareToProcess(base::GetCurrentProcessHandle(), &new_handle); | |
54 g_slaves[i]->Init(new_handle); | |
55 } | |
56 } | |
57 } | |
58 virtual void Add(VisitedLinkCommon::Fingerprint) { add_count_++; } | |
59 virtual void Reset() { reset_count_++; } | |
60 | |
61 void SetUp() { | |
62 reset_count_ = 0; | |
63 add_count_ = 0; | |
64 } | |
65 | |
66 int reset_count() const { return reset_count_; } | |
67 int add_count() const { return add_count_; } | |
68 | |
69 private: | |
70 int reset_count_; | |
71 int add_count_; | |
72 }; | |
73 | |
74 class VisitedLinkTest : public testing::Test { | |
75 protected: | |
76 VisitedLinkTest() | |
77 : ui_thread_(BrowserThread::UI, &message_loop_), | |
78 file_thread_(BrowserThread::FILE, &message_loop_) {} | |
79 // Initialize the history system. This should be called before InitVisited(). | |
80 bool InitHistory() { | |
81 history_service_ = new HistoryService; | |
82 return history_service_->Init(history_dir_, NULL); | |
83 } | |
84 | |
85 // Initializes the visited link objects. Pass in the size that you want a | |
86 // freshly created table to be. 0 means use the default. | |
87 // | |
88 // |suppress_rebuild| is set when we're not testing rebuilding, see | |
89 // the VisitedLinkMaster constructor. | |
90 bool InitVisited(int initial_size, bool suppress_rebuild) { | |
91 // Initialize the visited link system. | |
92 master_.reset(new VisitedLinkMaster(&listener_, history_service_, | |
93 suppress_rebuild, visited_file_, | |
94 initial_size)); | |
95 return master_->Init(); | |
96 } | |
97 | |
98 // May be called multiple times (some tests will do this to clear things, | |
99 // and TearDown will do this to make sure eveything is shiny before quitting. | |
100 void ClearDB() { | |
101 if (master_.get()) | |
102 master_.reset(NULL); | |
103 | |
104 if (history_service_.get()) { | |
105 history_service_->SetOnBackendDestroyTask(new MessageLoop::QuitTask); | |
106 history_service_->Cleanup(); | |
107 history_service_ = NULL; | |
108 | |
109 // Wait for the backend class to terminate before deleting the files and | |
110 // moving to the next test. Note: if this never terminates, somebody is | |
111 // probably leaking a reference to the history backend, so it never calls | |
112 // our destroy task. | |
113 MessageLoop::current()->Run(); | |
114 } | |
115 } | |
116 | |
117 // Loads the database from disk and makes sure that the same URLs are present | |
118 // as were generated by TestIO_Create(). This also checks the URLs with a | |
119 // slave to make sure it reads the data properly. | |
120 void Reload() { | |
121 // Clean up after our caller, who may have left the database open. | |
122 ClearDB(); | |
123 | |
124 ASSERT_TRUE(InitHistory()); | |
125 ASSERT_TRUE(InitVisited(0, true)); | |
126 master_->DebugValidate(); | |
127 | |
128 // check that the table has the proper number of entries | |
129 int used_count = master_->GetUsedCount(); | |
130 ASSERT_EQ(used_count, g_test_count); | |
131 | |
132 // Create a slave database. | |
133 VisitedLinkSlave slave; | |
134 base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle(); | |
135 master_->shared_memory()->ShareToProcess( | |
136 base::GetCurrentProcessHandle(), &new_handle); | |
137 bool success = slave.Init(new_handle); | |
138 ASSERT_TRUE(success); | |
139 g_slaves.push_back(&slave); | |
140 | |
141 bool found; | |
142 for (int i = 0; i < g_test_count; i++) { | |
143 GURL cur = TestURL(i); | |
144 found = master_->IsVisited(cur); | |
145 EXPECT_TRUE(found) << "URL " << i << "not found in master."; | |
146 | |
147 found = slave.IsVisited(cur); | |
148 EXPECT_TRUE(found) << "URL " << i << "not found in slave."; | |
149 } | |
150 | |
151 // test some random URL so we know that it returns false sometimes too | |
152 found = master_->IsVisited(GURL("http://unfound.site/")); | |
153 ASSERT_FALSE(found); | |
154 found = slave.IsVisited(GURL("http://unfound.site/")); | |
155 ASSERT_FALSE(found); | |
156 | |
157 master_->DebugValidate(); | |
158 | |
159 g_slaves.clear(); | |
160 } | |
161 | |
162 // testing::Test | |
163 virtual void SetUp() { | |
164 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | |
165 | |
166 history_dir_ = temp_dir_.path().AppendASCII("VisitedLinkTest"); | |
167 ASSERT_TRUE(file_util::CreateDirectory(history_dir_)); | |
168 | |
169 visited_file_ = history_dir_.Append(FILE_PATH_LITERAL("VisitedLinks")); | |
170 listener_.SetUp(); | |
171 } | |
172 | |
173 virtual void TearDown() { | |
174 ClearDB(); | |
175 } | |
176 | |
177 ScopedTempDir temp_dir_; | |
178 | |
179 MessageLoop message_loop_; | |
180 BrowserThread ui_thread_; | |
181 BrowserThread file_thread_; | |
182 | |
183 // Filenames for the services; | |
184 FilePath history_dir_; | |
185 FilePath visited_file_; | |
186 | |
187 scoped_ptr<VisitedLinkMaster> master_; | |
188 scoped_refptr<HistoryService> history_service_; | |
189 TrackingVisitedLinkEventListener listener_; | |
190 }; | |
191 | |
192 // This test creates and reads some databases to make sure the data is | |
193 // preserved throughout those operations. | |
194 TEST_F(VisitedLinkTest, DatabaseIO) { | |
195 ASSERT_TRUE(InitHistory()); | |
196 ASSERT_TRUE(InitVisited(0, true)); | |
197 | |
198 for (int i = 0; i < g_test_count; i++) | |
199 master_->AddURL(TestURL(i)); | |
200 | |
201 // Test that the database was written properly | |
202 Reload(); | |
203 } | |
204 | |
205 // Checks that we can delete things properly when there are collisions. | |
206 TEST_F(VisitedLinkTest, Delete) { | |
207 static const int32 kInitialSize = 17; | |
208 ASSERT_TRUE(InitHistory()); | |
209 ASSERT_TRUE(InitVisited(kInitialSize, true)); | |
210 | |
211 // Add a cluster from 14-17 wrapping around to 0. These will all hash to the | |
212 // same value. | |
213 const VisitedLinkCommon::Fingerprint kFingerprint0 = kInitialSize * 0 + 14; | |
214 const VisitedLinkCommon::Fingerprint kFingerprint1 = kInitialSize * 1 + 14; | |
215 const VisitedLinkCommon::Fingerprint kFingerprint2 = kInitialSize * 2 + 14; | |
216 const VisitedLinkCommon::Fingerprint kFingerprint3 = kInitialSize * 3 + 14; | |
217 const VisitedLinkCommon::Fingerprint kFingerprint4 = kInitialSize * 4 + 14; | |
218 master_->AddFingerprint(kFingerprint0, false); // @14 | |
219 master_->AddFingerprint(kFingerprint1, false); // @15 | |
220 master_->AddFingerprint(kFingerprint2, false); // @16 | |
221 master_->AddFingerprint(kFingerprint3, false); // @0 | |
222 master_->AddFingerprint(kFingerprint4, false); // @1 | |
223 | |
224 // Deleting 14 should move the next value up one slot (we do not specify an | |
225 // order). | |
226 EXPECT_EQ(kFingerprint3, master_->hash_table_[0]); | |
227 master_->DeleteFingerprint(kFingerprint3, false); | |
228 VisitedLinkCommon::Fingerprint zero_fingerprint = 0; | |
229 EXPECT_EQ(zero_fingerprint, master_->hash_table_[1]); | |
230 EXPECT_NE(zero_fingerprint, master_->hash_table_[0]); | |
231 | |
232 // Deleting the other four should leave the table empty. | |
233 master_->DeleteFingerprint(kFingerprint0, false); | |
234 master_->DeleteFingerprint(kFingerprint1, false); | |
235 master_->DeleteFingerprint(kFingerprint2, false); | |
236 master_->DeleteFingerprint(kFingerprint4, false); | |
237 | |
238 EXPECT_EQ(0, master_->used_items_); | |
239 for (int i = 0; i < kInitialSize; i++) | |
240 EXPECT_EQ(zero_fingerprint, master_->hash_table_[i]) << | |
241 "Hash table has values in it."; | |
242 } | |
243 | |
244 // When we delete more than kBigDeleteThreshold we trigger different behavior | |
245 // where the entire file is rewritten. | |
246 TEST_F(VisitedLinkTest, BigDelete) { | |
247 ASSERT_TRUE(InitHistory()); | |
248 ASSERT_TRUE(InitVisited(16381, true)); | |
249 | |
250 // Add the base set of URLs that won't be deleted. | |
251 // Reload() will test for these. | |
252 for (int32 i = 0; i < g_test_count; i++) | |
253 master_->AddURL(TestURL(i)); | |
254 | |
255 // Add more URLs than necessary to trigger this case. | |
256 const int kTestDeleteCount = VisitedLinkMaster::kBigDeleteThreshold + 2; | |
257 std::set<GURL> urls_to_delete; | |
258 for (int32 i = g_test_count; i < g_test_count + kTestDeleteCount; i++) { | |
259 GURL url(TestURL(i)); | |
260 master_->AddURL(url); | |
261 urls_to_delete.insert(url); | |
262 } | |
263 | |
264 master_->DeleteURLs(urls_to_delete); | |
265 master_->DebugValidate(); | |
266 | |
267 Reload(); | |
268 } | |
269 | |
270 TEST_F(VisitedLinkTest, DeleteAll) { | |
271 ASSERT_TRUE(InitHistory()); | |
272 ASSERT_TRUE(InitVisited(0, true)); | |
273 | |
274 { | |
275 VisitedLinkSlave slave; | |
276 base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle(); | |
277 master_->shared_memory()->ShareToProcess( | |
278 base::GetCurrentProcessHandle(), &new_handle); | |
279 ASSERT_TRUE(slave.Init(new_handle)); | |
280 g_slaves.push_back(&slave); | |
281 | |
282 // Add the test URLs. | |
283 for (int i = 0; i < g_test_count; i++) { | |
284 master_->AddURL(TestURL(i)); | |
285 ASSERT_EQ(i + 1, master_->GetUsedCount()); | |
286 } | |
287 master_->DebugValidate(); | |
288 | |
289 // Make sure the slave picked up the adds. | |
290 for (int i = 0; i < g_test_count; i++) | |
291 EXPECT_TRUE(slave.IsVisited(TestURL(i))); | |
292 | |
293 // Clear the table and make sure the slave picked it up. | |
294 master_->DeleteAllURLs(); | |
295 EXPECT_EQ(0, master_->GetUsedCount()); | |
296 for (int i = 0; i < g_test_count; i++) { | |
297 EXPECT_FALSE(master_->IsVisited(TestURL(i))); | |
298 EXPECT_FALSE(slave.IsVisited(TestURL(i))); | |
299 } | |
300 | |
301 // Close the database. | |
302 g_slaves.clear(); | |
303 ClearDB(); | |
304 } | |
305 | |
306 // Reopen and validate. | |
307 ASSERT_TRUE(InitHistory()); | |
308 ASSERT_TRUE(InitVisited(0, true)); | |
309 master_->DebugValidate(); | |
310 EXPECT_EQ(0, master_->GetUsedCount()); | |
311 for (int i = 0; i < g_test_count; i++) | |
312 EXPECT_FALSE(master_->IsVisited(TestURL(i))); | |
313 } | |
314 | |
315 // This tests that the master correctly resizes its tables when it gets too | |
316 // full, notifies its slaves of the change, and updates the disk. | |
317 TEST_F(VisitedLinkTest, Resizing) { | |
318 // Create a very small database. | |
319 const int32 initial_size = 17; | |
320 ASSERT_TRUE(InitHistory()); | |
321 ASSERT_TRUE(InitVisited(initial_size, true)); | |
322 | |
323 // ...and a slave | |
324 VisitedLinkSlave slave; | |
325 base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle(); | |
326 master_->shared_memory()->ShareToProcess( | |
327 base::GetCurrentProcessHandle(), &new_handle); | |
328 bool success = slave.Init(new_handle); | |
329 ASSERT_TRUE(success); | |
330 g_slaves.push_back(&slave); | |
331 | |
332 int32 used_count = master_->GetUsedCount(); | |
333 ASSERT_EQ(used_count, 0); | |
334 | |
335 for (int i = 0; i < g_test_count; i++) { | |
336 master_->AddURL(TestURL(i)); | |
337 used_count = master_->GetUsedCount(); | |
338 ASSERT_EQ(i + 1, used_count); | |
339 } | |
340 | |
341 // Verify that the table got resized sufficiently. | |
342 int32 table_size; | |
343 VisitedLinkCommon::Fingerprint* table; | |
344 master_->GetUsageStatistics(&table_size, &table); | |
345 used_count = master_->GetUsedCount(); | |
346 ASSERT_GT(table_size, used_count); | |
347 ASSERT_EQ(used_count, g_test_count) << | |
348 "table count doesn't match the # of things we added"; | |
349 | |
350 // Verify that the slave got the resize message and has the same | |
351 // table information. | |
352 int32 child_table_size; | |
353 VisitedLinkCommon::Fingerprint* child_table; | |
354 slave.GetUsageStatistics(&child_table_size, &child_table); | |
355 ASSERT_EQ(table_size, child_table_size); | |
356 for (int32 i = 0; i < table_size; i++) { | |
357 ASSERT_EQ(table[i], child_table[i]); | |
358 } | |
359 | |
360 master_->DebugValidate(); | |
361 g_slaves.clear(); | |
362 | |
363 // This tests that the file is written correctly by reading it in using | |
364 // a new database. | |
365 Reload(); | |
366 } | |
367 | |
368 // Tests that if the database doesn't exist, it will be rebuilt from history. | |
369 TEST_F(VisitedLinkTest, Rebuild) { | |
370 ASSERT_TRUE(InitHistory()); | |
371 | |
372 // Add half of our URLs to history. This needs to be done before we | |
373 // initialize the visited link DB. | |
374 int history_count = g_test_count / 2; | |
375 for (int i = 0; i < history_count; i++) | |
376 history_service_->AddPage(TestURL(i), history::SOURCE_BROWSED); | |
377 | |
378 // Initialize the visited link DB. Since the visited links file doesn't exist | |
379 // and we don't suppress history rebuilding, this will load from history. | |
380 ASSERT_TRUE(InitVisited(0, false)); | |
381 | |
382 // While the table is rebuilding, add the rest of the URLs to the visited | |
383 // link system. This isn't guaranteed to happen during the rebuild, so we | |
384 // can't be 100% sure we're testing the right thing, but in practice is. | |
385 // All the adds above will generally take some time queuing up on the | |
386 // history thread, and it will take a while to catch up to actually | |
387 // processing the rebuild that has queued behind it. We will generally | |
388 // finish adding all of the URLs before it has even found the first URL. | |
389 for (int i = history_count; i < g_test_count; i++) | |
390 master_->AddURL(TestURL(i)); | |
391 | |
392 // Add one more and then delete it. | |
393 master_->AddURL(TestURL(g_test_count)); | |
394 std::set<GURL> deleted_urls; | |
395 deleted_urls.insert(TestURL(g_test_count)); | |
396 master_->DeleteURLs(deleted_urls); | |
397 | |
398 // Wait for the rebuild to complete. The task will terminate the message | |
399 // loop when the rebuild is done. There's no chance that the rebuild will | |
400 // complete before we set the task because the rebuild completion message | |
401 // is posted to the message loop; until we Run() it, rebuild can not | |
402 // complete. | |
403 master_->set_rebuild_complete_task(new MessageLoop::QuitTask); | |
404 MessageLoop::current()->Run(); | |
405 | |
406 // Test that all URLs were written to the database properly. | |
407 Reload(); | |
408 | |
409 // Make sure the extra one was *not* written (Reload won't test this). | |
410 EXPECT_FALSE(master_->IsVisited(TestURL(g_test_count))); | |
411 } | |
412 | |
413 // Test that importing a large number of URLs will work | |
414 TEST_F(VisitedLinkTest, BigImport) { | |
415 ASSERT_TRUE(InitHistory()); | |
416 ASSERT_TRUE(InitVisited(0, false)); | |
417 | |
418 // Before the table rebuilds, add a large number of URLs | |
419 int total_count = VisitedLinkMaster::kDefaultTableSize + 10; | |
420 for (int i = 0; i < total_count; i++) | |
421 master_->AddURL(TestURL(i)); | |
422 | |
423 // Wait for the rebuild to complete. | |
424 master_->set_rebuild_complete_task(new MessageLoop::QuitTask); | |
425 MessageLoop::current()->Run(); | |
426 | |
427 // Ensure that the right number of URLs are present | |
428 int used_count = master_->GetUsedCount(); | |
429 ASSERT_EQ(used_count, total_count); | |
430 } | |
431 | |
432 TEST_F(VisitedLinkTest, Listener) { | |
433 ASSERT_TRUE(InitHistory()); | |
434 ASSERT_TRUE(InitVisited(0, true)); | |
435 | |
436 // Add test URLs. | |
437 for (int i = 0; i < g_test_count; i++) { | |
438 master_->AddURL(TestURL(i)); | |
439 ASSERT_EQ(i + 1, master_->GetUsedCount()); | |
440 } | |
441 | |
442 std::set<GURL> deleted_urls; | |
443 deleted_urls.insert(TestURL(0)); | |
444 // Delete an URL. | |
445 master_->DeleteURLs(deleted_urls); | |
446 // ... and all of the remaining ones. | |
447 master_->DeleteAllURLs(); | |
448 | |
449 // Verify that VisitedLinkMaster::Listener::Add was called for each added URL. | |
450 EXPECT_EQ(g_test_count, listener_.add_count()); | |
451 // Verify that VisitedLinkMaster::Listener::Reset was called both when one and | |
452 // all URLs are deleted. | |
453 EXPECT_EQ(2, listener_.reset_count()); | |
454 } | |
455 | |
456 class VisitCountingProfile : public TestingProfile { | |
457 public: | |
458 explicit VisitCountingProfile(VisitedLinkEventListener* event_listener) | |
459 : add_count_(0), | |
460 add_event_count_(0), | |
461 reset_event_count_(0), | |
462 event_listener_(event_listener) {} | |
463 | |
464 virtual VisitedLinkMaster* GetVisitedLinkMaster() { | |
465 if (!visited_link_master_.get()) { | |
466 visited_link_master_.reset(new VisitedLinkMaster(event_listener_, this)); | |
467 visited_link_master_->Init(); | |
468 } | |
469 return visited_link_master_.get(); | |
470 } | |
471 | |
472 void CountAddEvent(int by) { | |
473 add_count_ += by; | |
474 add_event_count_++; | |
475 } | |
476 | |
477 void CountResetEvent() { | |
478 reset_event_count_++; | |
479 } | |
480 | |
481 VisitedLinkMaster* master() const { return visited_link_master_.get(); } | |
482 int add_count() const { return add_count_; } | |
483 int add_event_count() const { return add_event_count_; } | |
484 int reset_event_count() const { return reset_event_count_; } | |
485 | |
486 private: | |
487 int add_count_; | |
488 int add_event_count_; | |
489 int reset_event_count_; | |
490 VisitedLinkEventListener* event_listener_; | |
491 scoped_ptr<VisitedLinkMaster> visited_link_master_; | |
492 }; | |
493 | |
494 class VisitCountingRenderProcessHost : public MockRenderProcessHost { | |
495 public: | |
496 explicit VisitCountingRenderProcessHost(Profile* profile) | |
497 : MockRenderProcessHost(profile) {} | |
498 | |
499 virtual void AddVisitedLinks( | |
500 const VisitedLinkCommon::Fingerprints& visited_links) { | |
501 VisitCountingProfile* counting_profile = | |
502 static_cast<VisitCountingProfile*>(profile()); | |
503 counting_profile->CountAddEvent(visited_links.size()); | |
504 } | |
505 virtual void ResetVisitedLinks() { | |
506 VisitCountingProfile* counting_profile = | |
507 static_cast<VisitCountingProfile*>(profile()); | |
508 counting_profile->CountResetEvent(); | |
509 } | |
510 | |
511 private: | |
512 DISALLOW_COPY_AND_ASSIGN(VisitCountingRenderProcessHost); | |
513 }; | |
514 | |
515 // Stub out as little as possible, borrowing from MockRenderProcessHost. | |
516 class VisitRelayingRenderProcessHost : public BrowserRenderProcessHost { | |
517 public: | |
518 explicit VisitRelayingRenderProcessHost(Profile* profile) | |
519 : BrowserRenderProcessHost(profile) { | |
520 } | |
521 virtual ~VisitRelayingRenderProcessHost() { | |
522 } | |
523 | |
524 virtual bool Init() { return true; } | |
525 | |
526 virtual void CancelResourceRequests(int render_widget_id) { | |
527 } | |
528 | |
529 virtual void CrossSiteClosePageACK(int new_render_process_host_id, | |
530 int new_request_id) { | |
531 } | |
532 | |
533 virtual bool WaitForPaintMsg(int render_widget_id, | |
534 const base::TimeDelta& max_delay, | |
535 IPC::Message* msg) { | |
536 return false; | |
537 } | |
538 | |
539 virtual bool Send(IPC::Message* msg) { | |
540 VisitCountingProfile* counting_profile = | |
541 static_cast<VisitCountingProfile*>(profile()); | |
542 | |
543 if (msg->type() == ViewMsg_VisitedLink_Add::ID) | |
544 counting_profile->CountAddEvent(1); | |
545 else if (msg->type() == ViewMsg_VisitedLink_Reset::ID) | |
546 counting_profile->CountResetEvent(); | |
547 | |
548 delete msg; | |
549 return true; | |
550 } | |
551 | |
552 virtual void SetBackgrounded(bool backgrounded) { | |
553 backgrounded_ = backgrounded; | |
554 } | |
555 | |
556 private: | |
557 DISALLOW_COPY_AND_ASSIGN(VisitRelayingRenderProcessHost); | |
558 }; | |
559 | |
560 class VisitedLinkRenderProcessHostFactory | |
561 : public MockRenderProcessHostFactory { | |
562 public: | |
563 VisitedLinkRenderProcessHostFactory() | |
564 : MockRenderProcessHostFactory(), | |
565 relay_mode_(false) {} | |
566 virtual RenderProcessHost* CreateRenderProcessHost(Profile* profile) const { | |
567 if (relay_mode_) | |
568 return new VisitRelayingRenderProcessHost(profile); | |
569 else | |
570 return new VisitCountingRenderProcessHost(profile); | |
571 } | |
572 | |
573 void set_relay_mode(bool mode) { relay_mode_ = mode; } | |
574 | |
575 private: | |
576 bool relay_mode_; | |
577 | |
578 DISALLOW_COPY_AND_ASSIGN(VisitedLinkRenderProcessHostFactory); | |
579 }; | |
580 | |
581 class VisitedLinkEventsTest : public RenderViewHostTestHarness { | |
582 public: | |
583 VisitedLinkEventsTest() | |
584 : RenderViewHostTestHarness(), | |
585 file_thread_(BrowserThread::FILE, &message_loop_) {} | |
586 ~VisitedLinkEventsTest() { | |
587 // This ends up using the file thread to schedule the delete. | |
588 profile_.reset(); | |
589 message_loop_.RunAllPending(); | |
590 } | |
591 virtual void SetFactoryMode() {} | |
592 virtual void SetUp() { | |
593 SetFactoryMode(); | |
594 event_listener_.reset(new VisitedLinkEventListener()); | |
595 rvh_factory_.set_render_process_host_factory(&vc_rph_factory_); | |
596 profile_.reset(new VisitCountingProfile(event_listener_.get())); | |
597 RenderViewHostTestHarness::SetUp(); | |
598 } | |
599 | |
600 VisitCountingProfile* profile() const { | |
601 return static_cast<VisitCountingProfile*>(profile_.get()); | |
602 } | |
603 | |
604 void WaitForCoalescense() { | |
605 // Let the timer fire. | |
606 MessageLoop::current()->PostDelayedTask(FROM_HERE, | |
607 new MessageLoop::QuitTask(), 110); | |
608 MessageLoop::current()->Run(); | |
609 } | |
610 | |
611 protected: | |
612 VisitedLinkRenderProcessHostFactory vc_rph_factory_; | |
613 | |
614 private: | |
615 scoped_ptr<VisitedLinkEventListener> event_listener_; | |
616 BrowserThread file_thread_; | |
617 | |
618 DISALLOW_COPY_AND_ASSIGN(VisitedLinkEventsTest); | |
619 }; | |
620 | |
621 class VisitedLinkRelayTest : public VisitedLinkEventsTest { | |
622 public: | |
623 virtual void SetFactoryMode() { vc_rph_factory_.set_relay_mode(true); } | |
624 }; | |
625 | |
626 TEST_F(VisitedLinkEventsTest, Coalescense) { | |
627 // add some URLs to master. | |
628 VisitedLinkMaster* master = profile_->GetVisitedLinkMaster(); | |
629 // Add a few URLs. | |
630 master->AddURL(GURL("http://acidtests.org/")); | |
631 master->AddURL(GURL("http://google.com/")); | |
632 master->AddURL(GURL("http://chromium.org/")); | |
633 // Just for kicks, add a duplicate URL. This shouldn't increase the resulting | |
634 master->AddURL(GURL("http://acidtests.org/")); | |
635 | |
636 // Make sure that coalescing actually occurs. There should be no links or | |
637 // events received by the renderer. | |
638 EXPECT_EQ(0, profile()->add_count()); | |
639 EXPECT_EQ(0, profile()->add_event_count()); | |
640 | |
641 WaitForCoalescense(); | |
642 | |
643 // We now should have 3 entries added in 1 event. | |
644 EXPECT_EQ(3, profile()->add_count()); | |
645 EXPECT_EQ(1, profile()->add_event_count()); | |
646 | |
647 // Test whether the coalescing continues by adding a few more URLs. | |
648 master->AddURL(GURL("http://google.com/chrome/")); | |
649 master->AddURL(GURL("http://webkit.org/")); | |
650 master->AddURL(GURL("http://acid3.acidtests.org/")); | |
651 | |
652 WaitForCoalescense(); | |
653 | |
654 // We should have 6 entries added in 2 events. | |
655 EXPECT_EQ(6, profile()->add_count()); | |
656 EXPECT_EQ(2, profile()->add_event_count()); | |
657 | |
658 // Test whether duplicate entries produce add events. | |
659 master->AddURL(GURL("http://acidtests.org/")); | |
660 | |
661 WaitForCoalescense(); | |
662 | |
663 // We should have no change in results. | |
664 EXPECT_EQ(6, profile()->add_count()); | |
665 EXPECT_EQ(2, profile()->add_event_count()); | |
666 | |
667 // Ensure that the coalescing does not resume after resetting. | |
668 master->AddURL(GURL("http://build.chromium.org/")); | |
669 master->DeleteAllURLs(); | |
670 | |
671 WaitForCoalescense(); | |
672 | |
673 // We should have no change in results except for one new reset event. | |
674 EXPECT_EQ(6, profile()->add_count()); | |
675 EXPECT_EQ(2, profile()->add_event_count()); | |
676 EXPECT_EQ(1, profile()->reset_event_count()); | |
677 } | |
678 | |
679 TEST_F(VisitedLinkRelayTest, Basics) { | |
680 VisitedLinkMaster* master = profile_->GetVisitedLinkMaster(); | |
681 rvh()->CreateRenderView(string16()); | |
682 | |
683 // Add a few URLs. | |
684 master->AddURL(GURL("http://acidtests.org/")); | |
685 master->AddURL(GURL("http://google.com/")); | |
686 master->AddURL(GURL("http://chromium.org/")); | |
687 | |
688 WaitForCoalescense(); | |
689 | |
690 // We now should have 1 add event. | |
691 EXPECT_EQ(1, profile()->add_event_count()); | |
692 EXPECT_EQ(0, profile()->reset_event_count()); | |
693 | |
694 master->DeleteAllURLs(); | |
695 | |
696 WaitForCoalescense(); | |
697 | |
698 // We should have no change in add results, plus one new reset event. | |
699 EXPECT_EQ(1, profile()->add_event_count()); | |
700 EXPECT_EQ(1, profile()->reset_event_count()); | |
701 } | |
702 | |
703 TEST_F(VisitedLinkRelayTest, TabVisibility) { | |
704 VisitedLinkMaster* master = profile_->GetVisitedLinkMaster(); | |
705 rvh()->CreateRenderView(string16()); | |
706 | |
707 // Simulate tab becoming inactive. | |
708 rvh()->WasHidden(); | |
709 | |
710 // Add a few URLs. | |
711 master->AddURL(GURL("http://acidtests.org/")); | |
712 master->AddURL(GURL("http://google.com/")); | |
713 master->AddURL(GURL("http://chromium.org/")); | |
714 | |
715 WaitForCoalescense(); | |
716 | |
717 // We shouldn't have any events. | |
718 EXPECT_EQ(0, profile()->add_event_count()); | |
719 EXPECT_EQ(0, profile()->reset_event_count()); | |
720 | |
721 // Simulate the tab becoming active. | |
722 rvh()->WasRestored(); | |
723 | |
724 // We should now have 3 add events, still no reset events. | |
725 EXPECT_EQ(1, profile()->add_event_count()); | |
726 EXPECT_EQ(0, profile()->reset_event_count()); | |
727 | |
728 // Deactivate the tab again. | |
729 rvh()->WasHidden(); | |
730 | |
731 // Add a bunch of URLs (over 50) to exhaust the link event buffer. | |
732 for (int i = 0; i < 100; i++) | |
733 master->AddURL(TestURL(i)); | |
734 | |
735 WaitForCoalescense(); | |
736 | |
737 // Again, no change in events until tab is active. | |
738 EXPECT_EQ(1, profile()->add_event_count()); | |
739 EXPECT_EQ(0, profile()->reset_event_count()); | |
740 | |
741 // Activate the tab. | |
742 rvh()->WasRestored(); | |
743 | |
744 // We should have only one more reset event. | |
745 EXPECT_EQ(1, profile()->add_event_count()); | |
746 EXPECT_EQ(1, profile()->reset_event_count()); | |
747 } | |
748 | |
749 TEST_F(VisitedLinkRelayTest, WebViewReadiness) { | |
750 VisitedLinkMaster* master = profile_->GetVisitedLinkMaster(); | |
751 | |
752 // Add a few URLs. | |
753 master->AddURL(GURL("http://acidtests.org/")); | |
754 master->AddURL(GURL("http://google.com/")); | |
755 master->AddURL(GURL("http://chromium.org/")); | |
756 | |
757 WaitForCoalescense(); | |
758 | |
759 std::set<GURL> deleted_urls; | |
760 deleted_urls.insert(GURL("http://acidtests.org/")); | |
761 master->DeleteURLs(deleted_urls); | |
762 | |
763 // We shouldn't have any events, because RenderView hasn't been created, | |
764 // and we ensure that updates are sent until it is. | |
765 EXPECT_EQ(0, profile()->add_event_count()); | |
766 EXPECT_EQ(0, profile()->reset_event_count()); | |
767 | |
768 rvh()->CreateRenderView(string16()); | |
769 | |
770 // We should now have just a reset event: adds are eaten up by a reset | |
771 // that followed. | |
772 EXPECT_EQ(0, profile()->add_event_count()); | |
773 EXPECT_EQ(1, profile()->reset_event_count()); | |
774 } | |
OLD | NEW |