blob: 3cd85e698e8810b8b60ee5c9c345690b103c40f2 [file] [log] [blame]
[email protected]02798a982012-01-27 00:45:331// Copyright (c) 2012 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
initial.commit09911bf2008-07-26 23:55:295#include <cstdio>
[email protected]c38831a12011-10-28 12:44:496#include <string>
7#include <vector>
initial.commit09911bf2008-07-26 23:55:298
initial.commit09911bf2008-07-26 23:55:299#include "base/file_util.h"
[email protected]c38831a12011-10-28 12:44:4910#include "base/message_loop.h"
initial.commit09911bf2008-07-26 23:55:2911#include "base/path_service.h"
[email protected]c2c998c2009-01-27 19:08:3912#include "base/process_util.h"
initial.commit09911bf2008-07-26 23:55:2913#include "base/shared_memory.h"
14#include "base/string_util.h"
[email protected]853e01b2012-09-21 20:14:1115#include "base/time.h"
[email protected]4c3d9d62013-01-09 22:37:2016#include "chrome/browser/visitedlink/visitedlink_delegate.h"
[email protected]8ecad5e2010-12-02 21:18:3317#include "chrome/browser/visitedlink/visitedlink_event_listener.h"
[email protected]c38831a12011-10-28 12:44:4918#include "chrome/browser/visitedlink/visitedlink_master.h"
[email protected]3e90d4a2009-07-03 17:38:3919#include "chrome/common/render_messages.h"
initial.commit09911bf2008-07-26 23:55:2920#include "chrome/renderer/visitedlink_slave.h"
[email protected]93ab5932011-09-14 07:38:1721#include "chrome/test/base/chrome_render_view_host_test_harness.h"
[email protected]a4ff9eae2011-08-01 19:58:1622#include "chrome/test/base/testing_profile.h"
[email protected]ad50def52011-10-19 23:17:0723#include "content/public/browser/notification_service.h"
[email protected]0d6e9bd2011-10-18 04:29:1624#include "content/public/browser/notification_types.h"
[email protected]08a932d52012-06-03 21:42:1225#include "content/public/test/mock_render_process_host.h"
[email protected]4c3d9d62013-01-09 22:37:2026#include "content/public/test/test_browser_context.h"
[email protected]e97882f2012-06-04 02:23:1727#include "content/public/test/test_browser_thread.h"
[email protected]b1e3f202012-06-04 14:45:5028#include "content/public/test/test_renderer_host.h"
initial.commit09911bf2008-07-26 23:55:2929#include "googleurl/src/gurl.h"
30#include "testing/gtest/include/gtest/gtest.h"
31
[email protected]631bb742011-11-02 11:29:3932using content::BrowserThread;
[email protected]eddd886702012-03-16 14:53:2333using content::MockRenderProcessHost;
[email protected]c0257382012-03-12 20:15:3434using content::RenderViewHostTester;
[email protected]631bb742011-11-02 11:29:3935
initial.commit09911bf2008-07-26 23:55:2936namespace {
37
[email protected]4c3d9d62013-01-09 22:37:2038typedef std::vector<GURL> URLs;
39
initial.commit09911bf2008-07-26 23:55:2940// a nice long URL that we can append numbers to to get new URLs
41const char g_test_prefix[] =
42 "http://www.google.com/products/foo/index.html?id=45028640526508376&seq=";
43const int g_test_count = 1000;
44
45// Returns a test URL for index |i|
46GURL TestURL(int i) {
47 return GURL(StringPrintf("%s%d", g_test_prefix, i));
48}
49
[email protected]4c3d9d62013-01-09 22:37:2050std::vector<VisitedLinkSlave*> g_slaves;
51
52class TestVisitedLinkDelegate : public VisitedLinkDelegate {
53 public:
54 virtual bool AreEquivalentContexts(
55 content::BrowserContext* context1,
56 content::BrowserContext* context2) OVERRIDE;
57 virtual void RebuildTable(
58 const scoped_refptr<URLEnumerator>& enumerator) OVERRIDE;
59
60 void AddURLForRebuild(const GURL& url);
61
62 private:
63
64 URLs rebuild_urls_;
65};
66
67bool TestVisitedLinkDelegate::AreEquivalentContexts(
68 content::BrowserContext* context1, content::BrowserContext* context2) {
69 DCHECK_EQ(context1, context2);
70 return true; // Test only has one profile.
[email protected]2ccc01042013-01-04 22:35:1671}
72
[email protected]4c3d9d62013-01-09 22:37:2073void TestVisitedLinkDelegate::RebuildTable(
74 const scoped_refptr<URLEnumerator>& enumerator) {
75 for (URLs::const_iterator itr = rebuild_urls_.begin();
76 itr != rebuild_urls_.end();
77 ++itr)
78 enumerator->OnURL(*itr);
79 enumerator->OnComplete(true);
80}
81
82void TestVisitedLinkDelegate::AddURLForRebuild(const GURL& url) {
83 rebuild_urls_.push_back(url);
84}
85
86class TestURLIterator : public VisitedLinkMaster::URLIterator {
87 public:
88 explicit TestURLIterator(const URLs& urls);
89
90 virtual const GURL& NextURL() OVERRIDE;
91 virtual bool HasNextURL() const OVERRIDE;
92
93 private:
94 URLs::const_iterator iterator_;
95 URLs::const_iterator end_;
96};
97
98TestURLIterator::TestURLIterator(const URLs& urls)
99 : iterator_(urls.begin()),
100 end_(urls.end()) {
101}
102
103const GURL& TestURLIterator::NextURL() {
104 return *(iterator_++);
105}
106
107bool TestURLIterator::HasNextURL() const {
108 return iterator_ != end_;
109}
[email protected]dba45e32013-01-04 20:27:15110
[email protected]3e90d4a2009-07-03 17:38:39111} // namespace
112
113class TrackingVisitedLinkEventListener : public VisitedLinkMaster::Listener {
114 public:
115 TrackingVisitedLinkEventListener()
116 : reset_count_(0),
117 add_count_(0) {}
118
119 virtual void NewTable(base::SharedMemory* table) {
120 if (table) {
121 for (std::vector<VisitedLinkSlave>::size_type i = 0;
122 i < g_slaves.size(); i++) {
123 base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle();
124 table->ShareToProcess(base::GetCurrentProcessHandle(), &new_handle);
[email protected]8d97ade2011-04-14 18:17:08125 g_slaves[i]->OnUpdateVisitedLinks(new_handle);
[email protected]3e90d4a2009-07-03 17:38:39126 }
initial.commit09911bf2008-07-26 23:55:29127 }
128 }
[email protected]3e90d4a2009-07-03 17:38:39129 virtual void Add(VisitedLinkCommon::Fingerprint) { add_count_++; }
130 virtual void Reset() { reset_count_++; }
initial.commit09911bf2008-07-26 23:55:29131
[email protected]3e90d4a2009-07-03 17:38:39132 void SetUp() {
133 reset_count_ = 0;
134 add_count_ = 0;
135 }
136
137 int reset_count() const { return reset_count_; }
138 int add_count() const { return add_count_; }
139
140 private:
141 int reset_count_;
142 int add_count_;
143};
[email protected]c2c998c2009-01-27 19:08:39144
[email protected]583844c2011-08-27 00:38:35145class VisitedLinkTest : public testing::Test {
initial.commit09911bf2008-07-26 23:55:29146 protected:
[email protected]6fad2632009-11-02 05:59:37147 VisitedLinkTest()
[email protected]0c7d74f2010-10-11 11:55:26148 : ui_thread_(BrowserThread::UI, &message_loop_),
149 file_thread_(BrowserThread::FILE, &message_loop_) {}
initial.commit09911bf2008-07-26 23:55:29150 // Initializes the visited link objects. Pass in the size that you want a
151 // freshly created table to be. 0 means use the default.
152 //
153 // |suppress_rebuild| is set when we're not testing rebuilding, see
154 // the VisitedLinkMaster constructor.
155 bool InitVisited(int initial_size, bool suppress_rebuild) {
156 // Initialize the visited link system.
[email protected]b42e6d82012-11-02 02:44:56157 master_.reset(new VisitedLinkMaster(new TrackingVisitedLinkEventListener(),
[email protected]4c3d9d62013-01-09 22:37:20158 &delegate_,
[email protected]3e90d4a2009-07-03 17:38:39159 suppress_rebuild, visited_file_,
160 initial_size));
initial.commit09911bf2008-07-26 23:55:29161 return master_->Init();
162 }
163
164 // May be called multiple times (some tests will do this to clear things,
165 // and TearDown will do this to make sure eveything is shiny before quitting.
166 void ClearDB() {
167 if (master_.get())
168 master_.reset(NULL);
169
[email protected]3189013e2012-01-19 04:11:57170 // Wait for all pending file I/O to be completed.
171 BrowserThread::GetBlockingPool()->FlushForTesting();
initial.commit09911bf2008-07-26 23:55:29172 }
173
174 // Loads the database from disk and makes sure that the same URLs are present
175 // as were generated by TestIO_Create(). This also checks the URLs with a
176 // slave to make sure it reads the data properly.
177 void Reload() {
178 // Clean up after our caller, who may have left the database open.
179 ClearDB();
180
initial.commit09911bf2008-07-26 23:55:29181 ASSERT_TRUE(InitVisited(0, true));
182 master_->DebugValidate();
183
184 // check that the table has the proper number of entries
185 int used_count = master_->GetUsedCount();
186 ASSERT_EQ(used_count, g_test_count);
187
188 // Create a slave database.
189 VisitedLinkSlave slave;
[email protected]76aac1e2009-03-16 16:45:36190 base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle();
[email protected]9610ef242009-11-18 02:41:26191 master_->shared_memory()->ShareToProcess(
192 base::GetCurrentProcessHandle(), &new_handle);
[email protected]8d97ade2011-04-14 18:17:08193 slave.OnUpdateVisitedLinks(new_handle);
initial.commit09911bf2008-07-26 23:55:29194 g_slaves.push_back(&slave);
195
196 bool found;
197 for (int i = 0; i < g_test_count; i++) {
198 GURL cur = TestURL(i);
199 found = master_->IsVisited(cur);
200 EXPECT_TRUE(found) << "URL " << i << "not found in master.";
201
202 found = slave.IsVisited(cur);
203 EXPECT_TRUE(found) << "URL " << i << "not found in slave.";
204 }
205
206 // test some random URL so we know that it returns false sometimes too
207 found = master_->IsVisited(GURL("http://unfound.site/"));
208 ASSERT_FALSE(found);
209 found = slave.IsVisited(GURL("http://unfound.site/"));
210 ASSERT_FALSE(found);
211
212 master_->DebugValidate();
213
214 g_slaves.clear();
215 }
216
217 // testing::Test
218 virtual void SetUp() {
[email protected]f708ed12010-09-23 12:18:34219 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
220
221 history_dir_ = temp_dir_.path().AppendASCII("VisitedLinkTest");
222 ASSERT_TRUE(file_util::CreateDirectory(history_dir_));
initial.commit09911bf2008-07-26 23:55:29223
[email protected]c2c998c2009-01-27 19:08:39224 visited_file_ = history_dir_.Append(FILE_PATH_LITERAL("VisitedLinks"));
initial.commit09911bf2008-07-26 23:55:29225 }
226
227 virtual void TearDown() {
228 ClearDB();
initial.commit09911bf2008-07-26 23:55:29229 }
[email protected]f0a51fb52009-03-05 12:46:38230
[email protected]ea1a3f62012-11-16 20:34:23231 base::ScopedTempDir temp_dir_;
[email protected]f708ed12010-09-23 12:18:34232
[email protected]ab820df2008-08-26 05:55:10233 MessageLoop message_loop_;
[email protected]c38831a12011-10-28 12:44:49234 content::TestBrowserThread ui_thread_;
235 content::TestBrowserThread file_thread_;
initial.commit09911bf2008-07-26 23:55:29236
237 // Filenames for the services;
[email protected]c2c998c2009-01-27 19:08:39238 FilePath history_dir_;
239 FilePath visited_file_;
initial.commit09911bf2008-07-26 23:55:29240
241 scoped_ptr<VisitedLinkMaster> master_;
[email protected]4c3d9d62013-01-09 22:37:20242 TestVisitedLinkDelegate delegate_;
initial.commit09911bf2008-07-26 23:55:29243};
244
initial.commit09911bf2008-07-26 23:55:29245// This test creates and reads some databases to make sure the data is
246// preserved throughout those operations.
247TEST_F(VisitedLinkTest, DatabaseIO) {
initial.commit09911bf2008-07-26 23:55:29248 ASSERT_TRUE(InitVisited(0, true));
249
250 for (int i = 0; i < g_test_count; i++)
251 master_->AddURL(TestURL(i));
252
253 // Test that the database was written properly
254 Reload();
255}
256
257// Checks that we can delete things properly when there are collisions.
258TEST_F(VisitedLinkTest, Delete) {
259 static const int32 kInitialSize = 17;
initial.commit09911bf2008-07-26 23:55:29260 ASSERT_TRUE(InitVisited(kInitialSize, true));
261
262 // Add a cluster from 14-17 wrapping around to 0. These will all hash to the
263 // same value.
[email protected]c2c998c2009-01-27 19:08:39264 const VisitedLinkCommon::Fingerprint kFingerprint0 = kInitialSize * 0 + 14;
265 const VisitedLinkCommon::Fingerprint kFingerprint1 = kInitialSize * 1 + 14;
266 const VisitedLinkCommon::Fingerprint kFingerprint2 = kInitialSize * 2 + 14;
267 const VisitedLinkCommon::Fingerprint kFingerprint3 = kInitialSize * 3 + 14;
268 const VisitedLinkCommon::Fingerprint kFingerprint4 = kInitialSize * 4 + 14;
[email protected]f8c42c92009-07-04 17:22:08269 master_->AddFingerprint(kFingerprint0, false); // @14
270 master_->AddFingerprint(kFingerprint1, false); // @15
271 master_->AddFingerprint(kFingerprint2, false); // @16
272 master_->AddFingerprint(kFingerprint3, false); // @0
273 master_->AddFingerprint(kFingerprint4, false); // @1
initial.commit09911bf2008-07-26 23:55:29274
275 // Deleting 14 should move the next value up one slot (we do not specify an
276 // order).
277 EXPECT_EQ(kFingerprint3, master_->hash_table_[0]);
278 master_->DeleteFingerprint(kFingerprint3, false);
[email protected]c2c998c2009-01-27 19:08:39279 VisitedLinkCommon::Fingerprint zero_fingerprint = 0;
280 EXPECT_EQ(zero_fingerprint, master_->hash_table_[1]);
281 EXPECT_NE(zero_fingerprint, master_->hash_table_[0]);
initial.commit09911bf2008-07-26 23:55:29282
283 // Deleting the other four should leave the table empty.
284 master_->DeleteFingerprint(kFingerprint0, false);
285 master_->DeleteFingerprint(kFingerprint1, false);
286 master_->DeleteFingerprint(kFingerprint2, false);
287 master_->DeleteFingerprint(kFingerprint4, false);
288
289 EXPECT_EQ(0, master_->used_items_);
290 for (int i = 0; i < kInitialSize; i++)
[email protected]c2c998c2009-01-27 19:08:39291 EXPECT_EQ(zero_fingerprint, master_->hash_table_[i]) <<
292 "Hash table has values in it.";
initial.commit09911bf2008-07-26 23:55:29293}
294
295// When we delete more than kBigDeleteThreshold we trigger different behavior
296// where the entire file is rewritten.
297TEST_F(VisitedLinkTest, BigDelete) {
initial.commit09911bf2008-07-26 23:55:29298 ASSERT_TRUE(InitVisited(16381, true));
299
300 // Add the base set of URLs that won't be deleted.
301 // Reload() will test for these.
302 for (int32 i = 0; i < g_test_count; i++)
303 master_->AddURL(TestURL(i));
304
305 // Add more URLs than necessary to trigger this case.
306 const int kTestDeleteCount = VisitedLinkMaster::kBigDeleteThreshold + 2;
[email protected]4c3d9d62013-01-09 22:37:20307 URLs urls_to_delete;
initial.commit09911bf2008-07-26 23:55:29308 for (int32 i = g_test_count; i < g_test_count + kTestDeleteCount; i++) {
309 GURL url(TestURL(i));
310 master_->AddURL(url);
[email protected]4c3d9d62013-01-09 22:37:20311 urls_to_delete.push_back(url);
initial.commit09911bf2008-07-26 23:55:29312 }
313
[email protected]4c3d9d62013-01-09 22:37:20314 TestURLIterator iterator(urls_to_delete);
315 master_->DeleteURLs(&iterator);
initial.commit09911bf2008-07-26 23:55:29316 master_->DebugValidate();
317
318 Reload();
319}
320
321TEST_F(VisitedLinkTest, DeleteAll) {
initial.commit09911bf2008-07-26 23:55:29322 ASSERT_TRUE(InitVisited(0, true));
323
324 {
325 VisitedLinkSlave slave;
[email protected]76aac1e2009-03-16 16:45:36326 base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle();
[email protected]9610ef242009-11-18 02:41:26327 master_->shared_memory()->ShareToProcess(
328 base::GetCurrentProcessHandle(), &new_handle);
[email protected]8d97ade2011-04-14 18:17:08329 slave.OnUpdateVisitedLinks(new_handle);
initial.commit09911bf2008-07-26 23:55:29330 g_slaves.push_back(&slave);
331
332 // Add the test URLs.
333 for (int i = 0; i < g_test_count; i++) {
334 master_->AddURL(TestURL(i));
335 ASSERT_EQ(i + 1, master_->GetUsedCount());
336 }
337 master_->DebugValidate();
338
339 // Make sure the slave picked up the adds.
340 for (int i = 0; i < g_test_count; i++)
341 EXPECT_TRUE(slave.IsVisited(TestURL(i)));
342
343 // Clear the table and make sure the slave picked it up.
344 master_->DeleteAllURLs();
345 EXPECT_EQ(0, master_->GetUsedCount());
346 for (int i = 0; i < g_test_count; i++) {
347 EXPECT_FALSE(master_->IsVisited(TestURL(i)));
348 EXPECT_FALSE(slave.IsVisited(TestURL(i)));
349 }
350
351 // Close the database.
352 g_slaves.clear();
353 ClearDB();
354 }
355
356 // Reopen and validate.
initial.commit09911bf2008-07-26 23:55:29357 ASSERT_TRUE(InitVisited(0, true));
358 master_->DebugValidate();
359 EXPECT_EQ(0, master_->GetUsedCount());
360 for (int i = 0; i < g_test_count; i++)
361 EXPECT_FALSE(master_->IsVisited(TestURL(i)));
362}
363
364// This tests that the master correctly resizes its tables when it gets too
365// full, notifies its slaves of the change, and updates the disk.
366TEST_F(VisitedLinkTest, Resizing) {
367 // Create a very small database.
368 const int32 initial_size = 17;
initial.commit09911bf2008-07-26 23:55:29369 ASSERT_TRUE(InitVisited(initial_size, true));
370
371 // ...and a slave
372 VisitedLinkSlave slave;
[email protected]76aac1e2009-03-16 16:45:36373 base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle();
[email protected]9610ef242009-11-18 02:41:26374 master_->shared_memory()->ShareToProcess(
375 base::GetCurrentProcessHandle(), &new_handle);
[email protected]8d97ade2011-04-14 18:17:08376 slave.OnUpdateVisitedLinks(new_handle);
initial.commit09911bf2008-07-26 23:55:29377 g_slaves.push_back(&slave);
378
379 int32 used_count = master_->GetUsedCount();
380 ASSERT_EQ(used_count, 0);
381
382 for (int i = 0; i < g_test_count; i++) {
383 master_->AddURL(TestURL(i));
384 used_count = master_->GetUsedCount();
385 ASSERT_EQ(i + 1, used_count);
386 }
387
388 // Verify that the table got resized sufficiently.
389 int32 table_size;
390 VisitedLinkCommon::Fingerprint* table;
391 master_->GetUsageStatistics(&table_size, &table);
392 used_count = master_->GetUsedCount();
393 ASSERT_GT(table_size, used_count);
394 ASSERT_EQ(used_count, g_test_count) <<
395 "table count doesn't match the # of things we added";
396
397 // Verify that the slave got the resize message and has the same
398 // table information.
399 int32 child_table_size;
400 VisitedLinkCommon::Fingerprint* child_table;
401 slave.GetUsageStatistics(&child_table_size, &child_table);
402 ASSERT_EQ(table_size, child_table_size);
403 for (int32 i = 0; i < table_size; i++) {
404 ASSERT_EQ(table[i], child_table[i]);
405 }
406
407 master_->DebugValidate();
408 g_slaves.clear();
409
410 // This tests that the file is written correctly by reading it in using
411 // a new database.
412 Reload();
413}
414
415// Tests that if the database doesn't exist, it will be rebuilt from history.
416TEST_F(VisitedLinkTest, Rebuild) {
initial.commit09911bf2008-07-26 23:55:29417 // Add half of our URLs to history. This needs to be done before we
418 // initialize the visited link DB.
419 int history_count = g_test_count / 2;
420 for (int i = 0; i < history_count; i++)
[email protected]4c3d9d62013-01-09 22:37:20421 delegate_.AddURLForRebuild(TestURL(i));
initial.commit09911bf2008-07-26 23:55:29422
423 // Initialize the visited link DB. Since the visited links file doesn't exist
424 // and we don't suppress history rebuilding, this will load from history.
425 ASSERT_TRUE(InitVisited(0, false));
426
427 // While the table is rebuilding, add the rest of the URLs to the visited
428 // link system. This isn't guaranteed to happen during the rebuild, so we
429 // can't be 100% sure we're testing the right thing, but in practice is.
430 // All the adds above will generally take some time queuing up on the
431 // history thread, and it will take a while to catch up to actually
432 // processing the rebuild that has queued behind it. We will generally
433 // finish adding all of the URLs before it has even found the first URL.
434 for (int i = history_count; i < g_test_count; i++)
435 master_->AddURL(TestURL(i));
436
437 // Add one more and then delete it.
438 master_->AddURL(TestURL(g_test_count));
[email protected]4c3d9d62013-01-09 22:37:20439 URLs urls_to_delete;
440 urls_to_delete.push_back(TestURL(g_test_count));
441 TestURLIterator iterator(urls_to_delete);
442 master_->DeleteURLs(&iterator);
initial.commit09911bf2008-07-26 23:55:29443
444 // Wait for the rebuild to complete. The task will terminate the message
445 // loop when the rebuild is done. There's no chance that the rebuild will
446 // complete before we set the task because the rebuild completion message
447 // is posted to the message loop; until we Run() it, rebuild can not
448 // complete.
[email protected]1cb1a242011-12-10 18:36:51449 master_->set_rebuild_complete_task(MessageLoop::QuitClosure());
initial.commit09911bf2008-07-26 23:55:29450 MessageLoop::current()->Run();
451
452 // Test that all URLs were written to the database properly.
453 Reload();
454
455 // Make sure the extra one was *not* written (Reload won't test this).
456 EXPECT_FALSE(master_->IsVisited(TestURL(g_test_count)));
457}
[email protected]3e90d4a2009-07-03 17:38:39458
[email protected]aed132ed2009-08-19 22:44:12459// Test that importing a large number of URLs will work
460TEST_F(VisitedLinkTest, BigImport) {
[email protected]aed132ed2009-08-19 22:44:12461 ASSERT_TRUE(InitVisited(0, false));
462
463 // Before the table rebuilds, add a large number of URLs
464 int total_count = VisitedLinkMaster::kDefaultTableSize + 10;
465 for (int i = 0; i < total_count; i++)
466 master_->AddURL(TestURL(i));
467
468 // Wait for the rebuild to complete.
[email protected]1cb1a242011-12-10 18:36:51469 master_->set_rebuild_complete_task(MessageLoop::QuitClosure());
[email protected]aed132ed2009-08-19 22:44:12470 MessageLoop::current()->Run();
471
472 // Ensure that the right number of URLs are present
473 int used_count = master_->GetUsedCount();
474 ASSERT_EQ(used_count, total_count);
475}
476
[email protected]3e90d4a2009-07-03 17:38:39477TEST_F(VisitedLinkTest, Listener) {
[email protected]3e90d4a2009-07-03 17:38:39478 ASSERT_TRUE(InitVisited(0, true));
479
480 // Add test URLs.
481 for (int i = 0; i < g_test_count; i++) {
482 master_->AddURL(TestURL(i));
483 ASSERT_EQ(i + 1, master_->GetUsedCount());
484 }
485
[email protected]3e90d4a2009-07-03 17:38:39486 // Delete an URL.
[email protected]4c3d9d62013-01-09 22:37:20487 URLs urls_to_delete;
488 urls_to_delete.push_back(TestURL(0));
489 TestURLIterator iterator(urls_to_delete);
490 master_->DeleteURLs(&iterator);
491
[email protected]3e90d4a2009-07-03 17:38:39492 // ... and all of the remaining ones.
493 master_->DeleteAllURLs();
494
[email protected]b42e6d82012-11-02 02:44:56495 TrackingVisitedLinkEventListener* listener =
496 static_cast<TrackingVisitedLinkEventListener*>(master_->GetListener());
497
[email protected]3e90d4a2009-07-03 17:38:39498 // Verify that VisitedLinkMaster::Listener::Add was called for each added URL.
[email protected]b42e6d82012-11-02 02:44:56499 EXPECT_EQ(g_test_count, listener->add_count());
[email protected]3e90d4a2009-07-03 17:38:39500 // Verify that VisitedLinkMaster::Listener::Reset was called both when one and
501 // all URLs are deleted.
[email protected]b42e6d82012-11-02 02:44:56502 EXPECT_EQ(2, listener->reset_count());
[email protected]3e90d4a2009-07-03 17:38:39503}
504
[email protected]4c3d9d62013-01-09 22:37:20505// TODO(boliu): Inherit content::TestBrowserContext when componentized.
[email protected]3e90d4a2009-07-03 17:38:39506class VisitCountingProfile : public TestingProfile {
507 public:
[email protected]2d66488c2011-10-14 21:10:00508 VisitCountingProfile()
[email protected]3e90d4a2009-07-03 17:38:39509 : add_count_(0),
510 add_event_count_(0),
[email protected]9a46725f2012-10-24 18:25:48511 reset_event_count_(0) {}
[email protected]3e90d4a2009-07-03 17:38:39512
513 void CountAddEvent(int by) {
514 add_count_ += by;
515 add_event_count_++;
516 }
517
518 void CountResetEvent() {
519 reset_event_count_++;
520 }
521
[email protected]3e90d4a2009-07-03 17:38:39522 int add_count() const { return add_count_; }
523 int add_event_count() const { return add_event_count_; }
524 int reset_event_count() const { return reset_event_count_; }
525
526 private:
527 int add_count_;
528 int add_event_count_;
529 int reset_event_count_;
[email protected]3e90d4a2009-07-03 17:38:39530};
531
[email protected]f3b1a082011-11-18 00:34:30532// Stub out as little as possible, borrowing from RenderProcessHost.
[email protected]b6a2f8de2012-01-31 17:28:49533class VisitRelayingRenderProcessHost : public MockRenderProcessHost {
[email protected]3e90d4a2009-07-03 17:38:39534 public:
[email protected]3d7474ff2011-07-27 17:47:37535 explicit VisitRelayingRenderProcessHost(
536 content::BrowserContext* browser_context)
[email protected]b6a2f8de2012-01-31 17:28:49537 : MockRenderProcessHost(browser_context), widgets_(0) {
[email protected]ad50def52011-10-19 23:17:07538 content::NotificationService::current()->Notify(
[email protected]432115822011-07-10 15:52:27539 content::NOTIFICATION_RENDERER_PROCESS_CREATED,
[email protected]6c2381d2011-10-19 02:52:53540 content::Source<RenderProcessHost>(this),
[email protected]ad50def52011-10-19 23:17:07541 content::NotificationService::NoDetails());
[email protected]3e90d4a2009-07-03 17:38:39542 }
543 virtual ~VisitRelayingRenderProcessHost() {
[email protected]ad50def52011-10-19 23:17:07544 content::NotificationService::current()->Notify(
[email protected]432115822011-07-10 15:52:27545 content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
[email protected]f3b1a082011-11-18 00:34:30546 content::Source<content::RenderProcessHost>(this),
[email protected]ad50def52011-10-19 23:17:07547 content::NotificationService::NoDetails());
[email protected]3e90d4a2009-07-03 17:38:39548 }
549
[email protected]b6a2f8de2012-01-31 17:28:49550 virtual void WidgetRestored() OVERRIDE { widgets_++; }
551 virtual void WidgetHidden() OVERRIDE { widgets_--; }
552 virtual int VisibleWidgetCount() const OVERRIDE { return widgets_; }
[email protected]3e90d4a2009-07-03 17:38:39553
[email protected]b6a2f8de2012-01-31 17:28:49554 virtual bool Send(IPC::Message* msg) OVERRIDE {
[email protected]3e90d4a2009-07-03 17:38:39555 VisitCountingProfile* counting_profile =
[email protected]9b62ecf2011-07-27 20:23:08556 static_cast<VisitCountingProfile*>(
[email protected]4c3d9d62013-01-09 22:37:20557 GetBrowserContext());
[email protected]3e90d4a2009-07-03 17:38:39558
[email protected]2ccf45c2011-08-19 23:35:50559 if (msg->type() == ChromeViewMsg_VisitedLink_Add::ID) {
[email protected]ce208f872012-03-07 20:42:56560 PickleIterator iter(*msg);
[email protected]7fa7dd52011-04-24 01:09:42561 std::vector<uint64> fingerprints;
562 CHECK(IPC::ReadParam(msg, &iter, &fingerprints));
563 counting_profile->CountAddEvent(fingerprints.size());
[email protected]2ccf45c2011-08-19 23:35:50564 } else if (msg->type() == ChromeViewMsg_VisitedLink_Reset::ID) {
[email protected]3e90d4a2009-07-03 17:38:39565 counting_profile->CountResetEvent();
[email protected]7fa7dd52011-04-24 01:09:42566 }
[email protected]3e90d4a2009-07-03 17:38:39567
568 delete msg;
569 return true;
570 }
571
[email protected]3e90d4a2009-07-03 17:38:39572 private:
[email protected]b6a2f8de2012-01-31 17:28:49573 int widgets_;
574
[email protected]3e90d4a2009-07-03 17:38:39575 DISALLOW_COPY_AND_ASSIGN(VisitRelayingRenderProcessHost);
576};
577
578class VisitedLinkRenderProcessHostFactory
[email protected]f3b1a082011-11-18 00:34:30579 : public content::RenderProcessHostFactory {
[email protected]3e90d4a2009-07-03 17:38:39580 public:
581 VisitedLinkRenderProcessHostFactory()
[email protected]f3b1a082011-11-18 00:34:30582 : content::RenderProcessHostFactory() {}
583 virtual content::RenderProcessHost* CreateRenderProcessHost(
[email protected]3d7474ff2011-07-27 17:47:37584 content::BrowserContext* browser_context) const OVERRIDE {
585 return new VisitRelayingRenderProcessHost(browser_context);
[email protected]3e90d4a2009-07-03 17:38:39586 }
587
[email protected]3e90d4a2009-07-03 17:38:39588 private:
[email protected]3e90d4a2009-07-03 17:38:39589
590 DISALLOW_COPY_AND_ASSIGN(VisitedLinkRenderProcessHostFactory);
591};
592
[email protected]4c3d9d62013-01-09 22:37:20593// TODO(boliu): Inherit content::RenderViewHostTestHarness when componentized.
[email protected]93ab5932011-09-14 07:38:17594class VisitedLinkEventsTest : public ChromeRenderViewHostTestHarness {
[email protected]3e90d4a2009-07-03 17:38:39595 public:
[email protected]6fad2632009-11-02 05:59:37596 VisitedLinkEventsTest()
[email protected]93ab5932011-09-14 07:38:17597 : ui_thread_(BrowserThread::UI, &message_loop_),
[email protected]0c7d74f2010-10-11 11:55:26598 file_thread_(BrowserThread::FILE, &message_loop_) {}
[email protected]93ab5932011-09-14 07:38:17599 virtual ~VisitedLinkEventsTest() {}
[email protected]3e90d4a2009-07-03 17:38:39600 virtual void SetUp() {
[email protected]2d66488c2011-10-14 21:10:00601 browser_context_.reset(new VisitCountingProfile());
[email protected]4c3d9d62013-01-09 22:37:20602 master_.reset(new VisitedLinkMaster(profile(), &delegate_));
603 master_->Init();
[email protected]9a46725f2012-10-24 18:25:48604 SetRenderProcessHostFactory(&vc_rph_factory_);
[email protected]4c3d9d62013-01-09 22:37:20605 content::RenderViewHostTestHarness::SetUp();
[email protected]3e90d4a2009-07-03 17:38:39606 }
607
608 VisitCountingProfile* profile() const {
[email protected]93ab5932011-09-14 07:38:17609 return static_cast<VisitCountingProfile*>(browser_context_.get());
[email protected]3e90d4a2009-07-03 17:38:39610 }
611
[email protected]5016ee12012-10-26 23:56:31612 VisitedLinkMaster* master() const {
[email protected]4c3d9d62013-01-09 22:37:20613 return master_.get();
[email protected]5016ee12012-10-26 23:56:31614 }
615
[email protected]3e90d4a2009-07-03 17:38:39616 void WaitForCoalescense() {
617 // Let the timer fire.
[email protected]02798a982012-01-27 00:45:33618 MessageLoop::current()->PostDelayedTask(
619 FROM_HERE,
620 MessageLoop::QuitClosure(),
621 base::TimeDelta::FromMilliseconds(110));
[email protected]3e90d4a2009-07-03 17:38:39622 MessageLoop::current()->Run();
623 }
624
625 protected:
626 VisitedLinkRenderProcessHostFactory vc_rph_factory_;
627
628 private:
[email protected]4c3d9d62013-01-09 22:37:20629 TestVisitedLinkDelegate delegate_;
630 scoped_ptr<VisitedLinkMaster> master_;
[email protected]c38831a12011-10-28 12:44:49631 content::TestBrowserThread ui_thread_;
632 content::TestBrowserThread file_thread_;
[email protected]3e90d4a2009-07-03 17:38:39633
634 DISALLOW_COPY_AND_ASSIGN(VisitedLinkEventsTest);
635};
636
[email protected]3e90d4a2009-07-03 17:38:39637TEST_F(VisitedLinkEventsTest, Coalescense) {
638 // add some URLs to master.
[email protected]3e90d4a2009-07-03 17:38:39639 // Add a few URLs.
[email protected]5016ee12012-10-26 23:56:31640 master()->AddURL(GURL("http://acidtests.org/"));
641 master()->AddURL(GURL("http://google.com/"));
642 master()->AddURL(GURL("http://chromium.org/"));
[email protected]3e90d4a2009-07-03 17:38:39643 // Just for kicks, add a duplicate URL. This shouldn't increase the resulting
[email protected]5016ee12012-10-26 23:56:31644 master()->AddURL(GURL("http://acidtests.org/"));
[email protected]3e90d4a2009-07-03 17:38:39645
646 // Make sure that coalescing actually occurs. There should be no links or
647 // events received by the renderer.
648 EXPECT_EQ(0, profile()->add_count());
649 EXPECT_EQ(0, profile()->add_event_count());
650
651 WaitForCoalescense();
652
653 // We now should have 3 entries added in 1 event.
654 EXPECT_EQ(3, profile()->add_count());
655 EXPECT_EQ(1, profile()->add_event_count());
656
657 // Test whether the coalescing continues by adding a few more URLs.
[email protected]5016ee12012-10-26 23:56:31658 master()->AddURL(GURL("http://google.com/chrome/"));
659 master()->AddURL(GURL("http://webkit.org/"));
660 master()->AddURL(GURL("http://acid3.acidtests.org/"));
[email protected]3e90d4a2009-07-03 17:38:39661
662 WaitForCoalescense();
663
664 // We should have 6 entries added in 2 events.
665 EXPECT_EQ(6, profile()->add_count());
666 EXPECT_EQ(2, profile()->add_event_count());
667
668 // Test whether duplicate entries produce add events.
[email protected]5016ee12012-10-26 23:56:31669 master()->AddURL(GURL("http://acidtests.org/"));
[email protected]3e90d4a2009-07-03 17:38:39670
671 WaitForCoalescense();
672
673 // We should have no change in results.
674 EXPECT_EQ(6, profile()->add_count());
675 EXPECT_EQ(2, profile()->add_event_count());
676
677 // Ensure that the coalescing does not resume after resetting.
[email protected]5016ee12012-10-26 23:56:31678 master()->AddURL(GURL("http://build.chromium.org/"));
679 master()->DeleteAllURLs();
[email protected]3e90d4a2009-07-03 17:38:39680
681 WaitForCoalescense();
682
683 // We should have no change in results except for one new reset event.
684 EXPECT_EQ(6, profile()->add_count());
685 EXPECT_EQ(2, profile()->add_event_count());
686 EXPECT_EQ(1, profile()->reset_event_count());
687}
688
[email protected]7fa7dd52011-04-24 01:09:42689TEST_F(VisitedLinkEventsTest, Basics) {
[email protected]4c3d9d62013-01-09 22:37:20690 RenderViewHostTester::For(rvh())->CreateRenderView(string16(),
[email protected]7900bfdb2012-05-24 19:31:24691 MSG_ROUTING_NONE,
[email protected]7900bfdb2012-05-24 19:31:24692 -1);
[email protected]6e8d64642009-08-10 15:27:19693
[email protected]3e90d4a2009-07-03 17:38:39694 // Add a few URLs.
[email protected]5016ee12012-10-26 23:56:31695 master()->AddURL(GURL("http://acidtests.org/"));
696 master()->AddURL(GURL("http://google.com/"));
697 master()->AddURL(GURL("http://chromium.org/"));
[email protected]3e90d4a2009-07-03 17:38:39698
699 WaitForCoalescense();
700
701 // We now should have 1 add event.
702 EXPECT_EQ(1, profile()->add_event_count());
703 EXPECT_EQ(0, profile()->reset_event_count());
704
[email protected]5016ee12012-10-26 23:56:31705 master()->DeleteAllURLs();
[email protected]3e90d4a2009-07-03 17:38:39706
707 WaitForCoalescense();
708
709 // We should have no change in add results, plus one new reset event.
710 EXPECT_EQ(1, profile()->add_event_count());
711 EXPECT_EQ(1, profile()->reset_event_count());
712}
713
[email protected]7fa7dd52011-04-24 01:09:42714TEST_F(VisitedLinkEventsTest, TabVisibility) {
[email protected]4c3d9d62013-01-09 22:37:20715 RenderViewHostTester::For(rvh())->CreateRenderView(string16(),
[email protected]7900bfdb2012-05-24 19:31:24716 MSG_ROUTING_NONE,
[email protected]7900bfdb2012-05-24 19:31:24717 -1);
[email protected]3e90d4a2009-07-03 17:38:39718
719 // Simulate tab becoming inactive.
[email protected]4c3d9d62013-01-09 22:37:20720 RenderViewHostTester::For(rvh())->SimulateWasHidden();
[email protected]3e90d4a2009-07-03 17:38:39721
722 // Add a few URLs.
[email protected]5016ee12012-10-26 23:56:31723 master()->AddURL(GURL("http://acidtests.org/"));
724 master()->AddURL(GURL("http://google.com/"));
725 master()->AddURL(GURL("http://chromium.org/"));
[email protected]3e90d4a2009-07-03 17:38:39726
727 WaitForCoalescense();
728
729 // We shouldn't have any events.
730 EXPECT_EQ(0, profile()->add_event_count());
731 EXPECT_EQ(0, profile()->reset_event_count());
732
733 // Simulate the tab becoming active.
[email protected]4c3d9d62013-01-09 22:37:20734 RenderViewHostTester::For(rvh())->SimulateWasShown();
[email protected]3e90d4a2009-07-03 17:38:39735
736 // We should now have 3 add events, still no reset events.
737 EXPECT_EQ(1, profile()->add_event_count());
738 EXPECT_EQ(0, profile()->reset_event_count());
739
740 // Deactivate the tab again.
[email protected]4c3d9d62013-01-09 22:37:20741 RenderViewHostTester::For(rvh())->SimulateWasHidden();
[email protected]3e90d4a2009-07-03 17:38:39742
743 // Add a bunch of URLs (over 50) to exhaust the link event buffer.
744 for (int i = 0; i < 100; i++)
[email protected]5016ee12012-10-26 23:56:31745 master()->AddURL(TestURL(i));
[email protected]3e90d4a2009-07-03 17:38:39746
747 WaitForCoalescense();
748
749 // Again, no change in events until tab is active.
750 EXPECT_EQ(1, profile()->add_event_count());
751 EXPECT_EQ(0, profile()->reset_event_count());
752
753 // Activate the tab.
[email protected]4c3d9d62013-01-09 22:37:20754 RenderViewHostTester::For(rvh())->SimulateWasShown();
[email protected]3e90d4a2009-07-03 17:38:39755
756 // We should have only one more reset event.
757 EXPECT_EQ(1, profile()->add_event_count());
758 EXPECT_EQ(1, profile()->reset_event_count());
759}