blob: a20ea88820c57f133fd68e746df4a1e1d4895f6a [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]93ab5932011-09-14 07:38:1716#include "chrome/test/base/chrome_render_view_host_test_harness.h"
[email protected]a4ff9eae2011-08-01 19:58:1617#include "chrome/test/base/testing_profile.h"
[email protected]1f371fa2013-01-23 00:35:1418#include "components/visitedlink/browser/visitedlink_delegate.h"
19#include "components/visitedlink/browser/visitedlink_event_listener.h"
20#include "components/visitedlink/browser/visitedlink_master.h"
21#include "components/visitedlink/common/visitedlink_messages.h"
22#include "components/visitedlink/renderer/visitedlink_slave.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
[email protected]1f371fa2013-01-23 00:35:1436namespace components {
37
initial.commit09911bf2008-07-26 23:55:2938namespace {
39
[email protected]4c3d9d62013-01-09 22:37:2040typedef std::vector<GURL> URLs;
41
initial.commit09911bf2008-07-26 23:55:2942// a nice long URL that we can append numbers to to get new URLs
43const char g_test_prefix[] =
44 "http://www.google.com/products/foo/index.html?id=45028640526508376&seq=";
45const int g_test_count = 1000;
46
47// Returns a test URL for index |i|
48GURL TestURL(int i) {
49 return GURL(StringPrintf("%s%d", g_test_prefix, i));
50}
51
[email protected]4c3d9d62013-01-09 22:37:2052std::vector<VisitedLinkSlave*> g_slaves;
53
54class TestVisitedLinkDelegate : public VisitedLinkDelegate {
55 public:
[email protected]4c3d9d62013-01-09 22:37:2056 virtual void RebuildTable(
57 const scoped_refptr<URLEnumerator>& enumerator) OVERRIDE;
58
59 void AddURLForRebuild(const GURL& url);
60
61 private:
62
63 URLs rebuild_urls_;
64};
65
[email protected]4c3d9d62013-01-09 22:37:2066void TestVisitedLinkDelegate::RebuildTable(
67 const scoped_refptr<URLEnumerator>& enumerator) {
68 for (URLs::const_iterator itr = rebuild_urls_.begin();
69 itr != rebuild_urls_.end();
70 ++itr)
71 enumerator->OnURL(*itr);
72 enumerator->OnComplete(true);
73}
74
75void TestVisitedLinkDelegate::AddURLForRebuild(const GURL& url) {
76 rebuild_urls_.push_back(url);
77}
78
79class TestURLIterator : public VisitedLinkMaster::URLIterator {
80 public:
81 explicit TestURLIterator(const URLs& urls);
82
83 virtual const GURL& NextURL() OVERRIDE;
84 virtual bool HasNextURL() const OVERRIDE;
85
86 private:
87 URLs::const_iterator iterator_;
88 URLs::const_iterator end_;
89};
90
91TestURLIterator::TestURLIterator(const URLs& urls)
92 : iterator_(urls.begin()),
93 end_(urls.end()) {
94}
95
96const GURL& TestURLIterator::NextURL() {
97 return *(iterator_++);
98}
99
100bool TestURLIterator::HasNextURL() const {
101 return iterator_ != end_;
102}
[email protected]dba45e32013-01-04 20:27:15103
[email protected]3e90d4a2009-07-03 17:38:39104} // namespace
105
106class TrackingVisitedLinkEventListener : public VisitedLinkMaster::Listener {
107 public:
108 TrackingVisitedLinkEventListener()
109 : reset_count_(0),
110 add_count_(0) {}
111
112 virtual void NewTable(base::SharedMemory* table) {
113 if (table) {
114 for (std::vector<VisitedLinkSlave>::size_type i = 0;
115 i < g_slaves.size(); i++) {
116 base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle();
117 table->ShareToProcess(base::GetCurrentProcessHandle(), &new_handle);
[email protected]8d97ade2011-04-14 18:17:08118 g_slaves[i]->OnUpdateVisitedLinks(new_handle);
[email protected]3e90d4a2009-07-03 17:38:39119 }
initial.commit09911bf2008-07-26 23:55:29120 }
121 }
[email protected]3e90d4a2009-07-03 17:38:39122 virtual void Add(VisitedLinkCommon::Fingerprint) { add_count_++; }
123 virtual void Reset() { reset_count_++; }
initial.commit09911bf2008-07-26 23:55:29124
[email protected]3e90d4a2009-07-03 17:38:39125 void SetUp() {
126 reset_count_ = 0;
127 add_count_ = 0;
128 }
129
130 int reset_count() const { return reset_count_; }
131 int add_count() const { return add_count_; }
132
133 private:
134 int reset_count_;
135 int add_count_;
136};
[email protected]c2c998c2009-01-27 19:08:39137
[email protected]583844c2011-08-27 00:38:35138class VisitedLinkTest : public testing::Test {
initial.commit09911bf2008-07-26 23:55:29139 protected:
[email protected]6fad2632009-11-02 05:59:37140 VisitedLinkTest()
[email protected]0c7d74f2010-10-11 11:55:26141 : ui_thread_(BrowserThread::UI, &message_loop_),
142 file_thread_(BrowserThread::FILE, &message_loop_) {}
initial.commit09911bf2008-07-26 23:55:29143 // Initializes the visited link objects. Pass in the size that you want a
144 // freshly created table to be. 0 means use the default.
145 //
146 // |suppress_rebuild| is set when we're not testing rebuilding, see
147 // the VisitedLinkMaster constructor.
148 bool InitVisited(int initial_size, bool suppress_rebuild) {
149 // Initialize the visited link system.
[email protected]b42e6d82012-11-02 02:44:56150 master_.reset(new VisitedLinkMaster(new TrackingVisitedLinkEventListener(),
[email protected]4c3d9d62013-01-09 22:37:20151 &delegate_,
[email protected]bff706b2013-01-25 00:15:01152 true,
[email protected]3e90d4a2009-07-03 17:38:39153 suppress_rebuild, visited_file_,
154 initial_size));
initial.commit09911bf2008-07-26 23:55:29155 return master_->Init();
156 }
157
158 // May be called multiple times (some tests will do this to clear things,
159 // and TearDown will do this to make sure eveything is shiny before quitting.
160 void ClearDB() {
161 if (master_.get())
162 master_.reset(NULL);
163
[email protected]3189013e2012-01-19 04:11:57164 // Wait for all pending file I/O to be completed.
165 BrowserThread::GetBlockingPool()->FlushForTesting();
initial.commit09911bf2008-07-26 23:55:29166 }
167
168 // Loads the database from disk and makes sure that the same URLs are present
169 // as were generated by TestIO_Create(). This also checks the URLs with a
170 // slave to make sure it reads the data properly.
171 void Reload() {
172 // Clean up after our caller, who may have left the database open.
173 ClearDB();
174
initial.commit09911bf2008-07-26 23:55:29175 ASSERT_TRUE(InitVisited(0, true));
176 master_->DebugValidate();
177
178 // check that the table has the proper number of entries
179 int used_count = master_->GetUsedCount();
180 ASSERT_EQ(used_count, g_test_count);
181
182 // Create a slave database.
183 VisitedLinkSlave slave;
[email protected]76aac1e2009-03-16 16:45:36184 base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle();
[email protected]9610ef242009-11-18 02:41:26185 master_->shared_memory()->ShareToProcess(
186 base::GetCurrentProcessHandle(), &new_handle);
[email protected]8d97ade2011-04-14 18:17:08187 slave.OnUpdateVisitedLinks(new_handle);
initial.commit09911bf2008-07-26 23:55:29188 g_slaves.push_back(&slave);
189
190 bool found;
191 for (int i = 0; i < g_test_count; i++) {
192 GURL cur = TestURL(i);
193 found = master_->IsVisited(cur);
194 EXPECT_TRUE(found) << "URL " << i << "not found in master.";
195
196 found = slave.IsVisited(cur);
197 EXPECT_TRUE(found) << "URL " << i << "not found in slave.";
198 }
199
200 // test some random URL so we know that it returns false sometimes too
201 found = master_->IsVisited(GURL("http://unfound.site/"));
202 ASSERT_FALSE(found);
203 found = slave.IsVisited(GURL("http://unfound.site/"));
204 ASSERT_FALSE(found);
205
206 master_->DebugValidate();
207
208 g_slaves.clear();
209 }
210
211 // testing::Test
212 virtual void SetUp() {
[email protected]f708ed12010-09-23 12:18:34213 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
214
215 history_dir_ = temp_dir_.path().AppendASCII("VisitedLinkTest");
216 ASSERT_TRUE(file_util::CreateDirectory(history_dir_));
initial.commit09911bf2008-07-26 23:55:29217
[email protected]c2c998c2009-01-27 19:08:39218 visited_file_ = history_dir_.Append(FILE_PATH_LITERAL("VisitedLinks"));
initial.commit09911bf2008-07-26 23:55:29219 }
220
221 virtual void TearDown() {
222 ClearDB();
initial.commit09911bf2008-07-26 23:55:29223 }
[email protected]f0a51fb52009-03-05 12:46:38224
[email protected]ea1a3f62012-11-16 20:34:23225 base::ScopedTempDir temp_dir_;
[email protected]f708ed12010-09-23 12:18:34226
[email protected]ab820df2008-08-26 05:55:10227 MessageLoop message_loop_;
[email protected]c38831a12011-10-28 12:44:49228 content::TestBrowserThread ui_thread_;
229 content::TestBrowserThread file_thread_;
initial.commit09911bf2008-07-26 23:55:29230
231 // Filenames for the services;
[email protected]c2c998c2009-01-27 19:08:39232 FilePath history_dir_;
233 FilePath visited_file_;
initial.commit09911bf2008-07-26 23:55:29234
235 scoped_ptr<VisitedLinkMaster> master_;
[email protected]4c3d9d62013-01-09 22:37:20236 TestVisitedLinkDelegate delegate_;
initial.commit09911bf2008-07-26 23:55:29237};
238
initial.commit09911bf2008-07-26 23:55:29239// This test creates and reads some databases to make sure the data is
240// preserved throughout those operations.
241TEST_F(VisitedLinkTest, DatabaseIO) {
initial.commit09911bf2008-07-26 23:55:29242 ASSERT_TRUE(InitVisited(0, true));
243
244 for (int i = 0; i < g_test_count; i++)
245 master_->AddURL(TestURL(i));
246
247 // Test that the database was written properly
248 Reload();
249}
250
251// Checks that we can delete things properly when there are collisions.
252TEST_F(VisitedLinkTest, Delete) {
253 static const int32 kInitialSize = 17;
initial.commit09911bf2008-07-26 23:55:29254 ASSERT_TRUE(InitVisited(kInitialSize, true));
255
256 // Add a cluster from 14-17 wrapping around to 0. These will all hash to the
257 // same value.
[email protected]c2c998c2009-01-27 19:08:39258 const VisitedLinkCommon::Fingerprint kFingerprint0 = kInitialSize * 0 + 14;
259 const VisitedLinkCommon::Fingerprint kFingerprint1 = kInitialSize * 1 + 14;
260 const VisitedLinkCommon::Fingerprint kFingerprint2 = kInitialSize * 2 + 14;
261 const VisitedLinkCommon::Fingerprint kFingerprint3 = kInitialSize * 3 + 14;
262 const VisitedLinkCommon::Fingerprint kFingerprint4 = kInitialSize * 4 + 14;
[email protected]f8c42c92009-07-04 17:22:08263 master_->AddFingerprint(kFingerprint0, false); // @14
264 master_->AddFingerprint(kFingerprint1, false); // @15
265 master_->AddFingerprint(kFingerprint2, false); // @16
266 master_->AddFingerprint(kFingerprint3, false); // @0
267 master_->AddFingerprint(kFingerprint4, false); // @1
initial.commit09911bf2008-07-26 23:55:29268
269 // Deleting 14 should move the next value up one slot (we do not specify an
270 // order).
271 EXPECT_EQ(kFingerprint3, master_->hash_table_[0]);
272 master_->DeleteFingerprint(kFingerprint3, false);
[email protected]c2c998c2009-01-27 19:08:39273 VisitedLinkCommon::Fingerprint zero_fingerprint = 0;
274 EXPECT_EQ(zero_fingerprint, master_->hash_table_[1]);
275 EXPECT_NE(zero_fingerprint, master_->hash_table_[0]);
initial.commit09911bf2008-07-26 23:55:29276
277 // Deleting the other four should leave the table empty.
278 master_->DeleteFingerprint(kFingerprint0, false);
279 master_->DeleteFingerprint(kFingerprint1, false);
280 master_->DeleteFingerprint(kFingerprint2, false);
281 master_->DeleteFingerprint(kFingerprint4, false);
282
283 EXPECT_EQ(0, master_->used_items_);
284 for (int i = 0; i < kInitialSize; i++)
[email protected]c2c998c2009-01-27 19:08:39285 EXPECT_EQ(zero_fingerprint, master_->hash_table_[i]) <<
286 "Hash table has values in it.";
initial.commit09911bf2008-07-26 23:55:29287}
288
289// When we delete more than kBigDeleteThreshold we trigger different behavior
290// where the entire file is rewritten.
291TEST_F(VisitedLinkTest, BigDelete) {
initial.commit09911bf2008-07-26 23:55:29292 ASSERT_TRUE(InitVisited(16381, true));
293
294 // Add the base set of URLs that won't be deleted.
295 // Reload() will test for these.
296 for (int32 i = 0; i < g_test_count; i++)
297 master_->AddURL(TestURL(i));
298
299 // Add more URLs than necessary to trigger this case.
300 const int kTestDeleteCount = VisitedLinkMaster::kBigDeleteThreshold + 2;
[email protected]4c3d9d62013-01-09 22:37:20301 URLs urls_to_delete;
initial.commit09911bf2008-07-26 23:55:29302 for (int32 i = g_test_count; i < g_test_count + kTestDeleteCount; i++) {
303 GURL url(TestURL(i));
304 master_->AddURL(url);
[email protected]4c3d9d62013-01-09 22:37:20305 urls_to_delete.push_back(url);
initial.commit09911bf2008-07-26 23:55:29306 }
307
[email protected]4c3d9d62013-01-09 22:37:20308 TestURLIterator iterator(urls_to_delete);
309 master_->DeleteURLs(&iterator);
initial.commit09911bf2008-07-26 23:55:29310 master_->DebugValidate();
311
312 Reload();
313}
314
315TEST_F(VisitedLinkTest, DeleteAll) {
initial.commit09911bf2008-07-26 23:55:29316 ASSERT_TRUE(InitVisited(0, true));
317
318 {
319 VisitedLinkSlave slave;
[email protected]76aac1e2009-03-16 16:45:36320 base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle();
[email protected]9610ef242009-11-18 02:41:26321 master_->shared_memory()->ShareToProcess(
322 base::GetCurrentProcessHandle(), &new_handle);
[email protected]8d97ade2011-04-14 18:17:08323 slave.OnUpdateVisitedLinks(new_handle);
initial.commit09911bf2008-07-26 23:55:29324 g_slaves.push_back(&slave);
325
326 // Add the test URLs.
327 for (int i = 0; i < g_test_count; i++) {
328 master_->AddURL(TestURL(i));
329 ASSERT_EQ(i + 1, master_->GetUsedCount());
330 }
331 master_->DebugValidate();
332
333 // Make sure the slave picked up the adds.
334 for (int i = 0; i < g_test_count; i++)
335 EXPECT_TRUE(slave.IsVisited(TestURL(i)));
336
337 // Clear the table and make sure the slave picked it up.
338 master_->DeleteAllURLs();
339 EXPECT_EQ(0, master_->GetUsedCount());
340 for (int i = 0; i < g_test_count; i++) {
341 EXPECT_FALSE(master_->IsVisited(TestURL(i)));
342 EXPECT_FALSE(slave.IsVisited(TestURL(i)));
343 }
344
345 // Close the database.
346 g_slaves.clear();
347 ClearDB();
348 }
349
350 // Reopen and validate.
initial.commit09911bf2008-07-26 23:55:29351 ASSERT_TRUE(InitVisited(0, true));
352 master_->DebugValidate();
353 EXPECT_EQ(0, master_->GetUsedCount());
354 for (int i = 0; i < g_test_count; i++)
355 EXPECT_FALSE(master_->IsVisited(TestURL(i)));
356}
357
358// This tests that the master correctly resizes its tables when it gets too
359// full, notifies its slaves of the change, and updates the disk.
360TEST_F(VisitedLinkTest, Resizing) {
361 // Create a very small database.
362 const int32 initial_size = 17;
initial.commit09911bf2008-07-26 23:55:29363 ASSERT_TRUE(InitVisited(initial_size, true));
364
365 // ...and a slave
366 VisitedLinkSlave slave;
[email protected]76aac1e2009-03-16 16:45:36367 base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle();
[email protected]9610ef242009-11-18 02:41:26368 master_->shared_memory()->ShareToProcess(
369 base::GetCurrentProcessHandle(), &new_handle);
[email protected]8d97ade2011-04-14 18:17:08370 slave.OnUpdateVisitedLinks(new_handle);
initial.commit09911bf2008-07-26 23:55:29371 g_slaves.push_back(&slave);
372
373 int32 used_count = master_->GetUsedCount();
374 ASSERT_EQ(used_count, 0);
375
376 for (int i = 0; i < g_test_count; i++) {
377 master_->AddURL(TestURL(i));
378 used_count = master_->GetUsedCount();
379 ASSERT_EQ(i + 1, used_count);
380 }
381
382 // Verify that the table got resized sufficiently.
383 int32 table_size;
384 VisitedLinkCommon::Fingerprint* table;
385 master_->GetUsageStatistics(&table_size, &table);
386 used_count = master_->GetUsedCount();
387 ASSERT_GT(table_size, used_count);
388 ASSERT_EQ(used_count, g_test_count) <<
389 "table count doesn't match the # of things we added";
390
391 // Verify that the slave got the resize message and has the same
392 // table information.
393 int32 child_table_size;
394 VisitedLinkCommon::Fingerprint* child_table;
395 slave.GetUsageStatistics(&child_table_size, &child_table);
396 ASSERT_EQ(table_size, child_table_size);
397 for (int32 i = 0; i < table_size; i++) {
398 ASSERT_EQ(table[i], child_table[i]);
399 }
400
401 master_->DebugValidate();
402 g_slaves.clear();
403
404 // This tests that the file is written correctly by reading it in using
405 // a new database.
406 Reload();
407}
408
409// Tests that if the database doesn't exist, it will be rebuilt from history.
410TEST_F(VisitedLinkTest, Rebuild) {
initial.commit09911bf2008-07-26 23:55:29411 // Add half of our URLs to history. This needs to be done before we
412 // initialize the visited link DB.
413 int history_count = g_test_count / 2;
414 for (int i = 0; i < history_count; i++)
[email protected]4c3d9d62013-01-09 22:37:20415 delegate_.AddURLForRebuild(TestURL(i));
initial.commit09911bf2008-07-26 23:55:29416
417 // Initialize the visited link DB. Since the visited links file doesn't exist
418 // and we don't suppress history rebuilding, this will load from history.
419 ASSERT_TRUE(InitVisited(0, false));
420
421 // While the table is rebuilding, add the rest of the URLs to the visited
422 // link system. This isn't guaranteed to happen during the rebuild, so we
423 // can't be 100% sure we're testing the right thing, but in practice is.
424 // All the adds above will generally take some time queuing up on the
425 // history thread, and it will take a while to catch up to actually
426 // processing the rebuild that has queued behind it. We will generally
427 // finish adding all of the URLs before it has even found the first URL.
428 for (int i = history_count; i < g_test_count; i++)
429 master_->AddURL(TestURL(i));
430
431 // Add one more and then delete it.
432 master_->AddURL(TestURL(g_test_count));
[email protected]4c3d9d62013-01-09 22:37:20433 URLs urls_to_delete;
434 urls_to_delete.push_back(TestURL(g_test_count));
435 TestURLIterator iterator(urls_to_delete);
436 master_->DeleteURLs(&iterator);
initial.commit09911bf2008-07-26 23:55:29437
438 // Wait for the rebuild to complete. The task will terminate the message
439 // loop when the rebuild is done. There's no chance that the rebuild will
440 // complete before we set the task because the rebuild completion message
441 // is posted to the message loop; until we Run() it, rebuild can not
442 // complete.
[email protected]1cb1a242011-12-10 18:36:51443 master_->set_rebuild_complete_task(MessageLoop::QuitClosure());
initial.commit09911bf2008-07-26 23:55:29444 MessageLoop::current()->Run();
445
446 // Test that all URLs were written to the database properly.
447 Reload();
448
449 // Make sure the extra one was *not* written (Reload won't test this).
450 EXPECT_FALSE(master_->IsVisited(TestURL(g_test_count)));
451}
[email protected]3e90d4a2009-07-03 17:38:39452
[email protected]aed132ed2009-08-19 22:44:12453// Test that importing a large number of URLs will work
454TEST_F(VisitedLinkTest, BigImport) {
[email protected]aed132ed2009-08-19 22:44:12455 ASSERT_TRUE(InitVisited(0, false));
456
457 // Before the table rebuilds, add a large number of URLs
458 int total_count = VisitedLinkMaster::kDefaultTableSize + 10;
459 for (int i = 0; i < total_count; i++)
460 master_->AddURL(TestURL(i));
461
462 // Wait for the rebuild to complete.
[email protected]1cb1a242011-12-10 18:36:51463 master_->set_rebuild_complete_task(MessageLoop::QuitClosure());
[email protected]aed132ed2009-08-19 22:44:12464 MessageLoop::current()->Run();
465
466 // Ensure that the right number of URLs are present
467 int used_count = master_->GetUsedCount();
468 ASSERT_EQ(used_count, total_count);
469}
470
[email protected]3e90d4a2009-07-03 17:38:39471TEST_F(VisitedLinkTest, Listener) {
[email protected]3e90d4a2009-07-03 17:38:39472 ASSERT_TRUE(InitVisited(0, true));
473
474 // Add test URLs.
475 for (int i = 0; i < g_test_count; i++) {
476 master_->AddURL(TestURL(i));
477 ASSERT_EQ(i + 1, master_->GetUsedCount());
478 }
479
[email protected]3e90d4a2009-07-03 17:38:39480 // Delete an URL.
[email protected]4c3d9d62013-01-09 22:37:20481 URLs urls_to_delete;
482 urls_to_delete.push_back(TestURL(0));
483 TestURLIterator iterator(urls_to_delete);
484 master_->DeleteURLs(&iterator);
485
[email protected]3e90d4a2009-07-03 17:38:39486 // ... and all of the remaining ones.
487 master_->DeleteAllURLs();
488
[email protected]b42e6d82012-11-02 02:44:56489 TrackingVisitedLinkEventListener* listener =
490 static_cast<TrackingVisitedLinkEventListener*>(master_->GetListener());
491
[email protected]3e90d4a2009-07-03 17:38:39492 // Verify that VisitedLinkMaster::Listener::Add was called for each added URL.
[email protected]b42e6d82012-11-02 02:44:56493 EXPECT_EQ(g_test_count, listener->add_count());
[email protected]3e90d4a2009-07-03 17:38:39494 // Verify that VisitedLinkMaster::Listener::Reset was called both when one and
495 // all URLs are deleted.
[email protected]b42e6d82012-11-02 02:44:56496 EXPECT_EQ(2, listener->reset_count());
[email protected]3e90d4a2009-07-03 17:38:39497}
498
[email protected]4c3d9d62013-01-09 22:37:20499// TODO(boliu): Inherit content::TestBrowserContext when componentized.
[email protected]3e90d4a2009-07-03 17:38:39500class VisitCountingProfile : public TestingProfile {
501 public:
[email protected]2d66488c2011-10-14 21:10:00502 VisitCountingProfile()
[email protected]3e90d4a2009-07-03 17:38:39503 : add_count_(0),
504 add_event_count_(0),
[email protected]c2134fb2013-01-23 04:28:52505 reset_event_count_(0),
506 new_table_count_(0) {}
[email protected]3e90d4a2009-07-03 17:38:39507
508 void CountAddEvent(int by) {
509 add_count_ += by;
510 add_event_count_++;
511 }
512
513 void CountResetEvent() {
514 reset_event_count_++;
515 }
516
[email protected]c2134fb2013-01-23 04:28:52517 void CountNewTable() {
518 new_table_count_++;
519 }
520
[email protected]3e90d4a2009-07-03 17:38:39521 int add_count() const { return add_count_; }
522 int add_event_count() const { return add_event_count_; }
523 int reset_event_count() const { return reset_event_count_; }
[email protected]c2134fb2013-01-23 04:28:52524 int new_table_count() const { return new_table_count_; }
[email protected]3e90d4a2009-07-03 17:38:39525
526 private:
527 int add_count_;
528 int add_event_count_;
529 int reset_event_count_;
[email protected]c2134fb2013-01-23 04:28:52530 int new_table_count_;
[email protected]3e90d4a2009-07-03 17:38:39531};
532
[email protected]f3b1a082011-11-18 00:34:30533// Stub out as little as possible, borrowing from RenderProcessHost.
[email protected]b6a2f8de2012-01-31 17:28:49534class VisitRelayingRenderProcessHost : public MockRenderProcessHost {
[email protected]3e90d4a2009-07-03 17:38:39535 public:
[email protected]3d7474ff2011-07-27 17:47:37536 explicit VisitRelayingRenderProcessHost(
537 content::BrowserContext* browser_context)
[email protected]b6a2f8de2012-01-31 17:28:49538 : MockRenderProcessHost(browser_context), widgets_(0) {
[email protected]ad50def52011-10-19 23:17:07539 content::NotificationService::current()->Notify(
[email protected]432115822011-07-10 15:52:27540 content::NOTIFICATION_RENDERER_PROCESS_CREATED,
[email protected]6c2381d2011-10-19 02:52:53541 content::Source<RenderProcessHost>(this),
[email protected]ad50def52011-10-19 23:17:07542 content::NotificationService::NoDetails());
[email protected]3e90d4a2009-07-03 17:38:39543 }
544 virtual ~VisitRelayingRenderProcessHost() {
[email protected]ad50def52011-10-19 23:17:07545 content::NotificationService::current()->Notify(
[email protected]432115822011-07-10 15:52:27546 content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
[email protected]f3b1a082011-11-18 00:34:30547 content::Source<content::RenderProcessHost>(this),
[email protected]ad50def52011-10-19 23:17:07548 content::NotificationService::NoDetails());
[email protected]3e90d4a2009-07-03 17:38:39549 }
550
[email protected]b6a2f8de2012-01-31 17:28:49551 virtual void WidgetRestored() OVERRIDE { widgets_++; }
552 virtual void WidgetHidden() OVERRIDE { widgets_--; }
553 virtual int VisibleWidgetCount() const OVERRIDE { return widgets_; }
[email protected]3e90d4a2009-07-03 17:38:39554
[email protected]b6a2f8de2012-01-31 17:28:49555 virtual bool Send(IPC::Message* msg) OVERRIDE {
[email protected]3e90d4a2009-07-03 17:38:39556 VisitCountingProfile* counting_profile =
[email protected]9b62ecf2011-07-27 20:23:08557 static_cast<VisitCountingProfile*>(
[email protected]4c3d9d62013-01-09 22:37:20558 GetBrowserContext());
[email protected]3e90d4a2009-07-03 17:38:39559
[email protected]2ccf45c2011-08-19 23:35:50560 if (msg->type() == ChromeViewMsg_VisitedLink_Add::ID) {
[email protected]ce208f872012-03-07 20:42:56561 PickleIterator iter(*msg);
[email protected]7fa7dd52011-04-24 01:09:42562 std::vector<uint64> fingerprints;
563 CHECK(IPC::ReadParam(msg, &iter, &fingerprints));
564 counting_profile->CountAddEvent(fingerprints.size());
[email protected]2ccf45c2011-08-19 23:35:50565 } else if (msg->type() == ChromeViewMsg_VisitedLink_Reset::ID) {
[email protected]3e90d4a2009-07-03 17:38:39566 counting_profile->CountResetEvent();
[email protected]c2134fb2013-01-23 04:28:52567 } else if (msg->type() == ChromeViewMsg_VisitedLink_NewTable::ID) {
568 counting_profile->CountNewTable();
[email protected]7fa7dd52011-04-24 01:09:42569 }
[email protected]3e90d4a2009-07-03 17:38:39570
571 delete msg;
572 return true;
573 }
574
[email protected]3e90d4a2009-07-03 17:38:39575 private:
[email protected]b6a2f8de2012-01-31 17:28:49576 int widgets_;
577
[email protected]3e90d4a2009-07-03 17:38:39578 DISALLOW_COPY_AND_ASSIGN(VisitRelayingRenderProcessHost);
579};
580
581class VisitedLinkRenderProcessHostFactory
[email protected]f3b1a082011-11-18 00:34:30582 : public content::RenderProcessHostFactory {
[email protected]3e90d4a2009-07-03 17:38:39583 public:
584 VisitedLinkRenderProcessHostFactory()
[email protected]f3b1a082011-11-18 00:34:30585 : content::RenderProcessHostFactory() {}
586 virtual content::RenderProcessHost* CreateRenderProcessHost(
[email protected]3d7474ff2011-07-27 17:47:37587 content::BrowserContext* browser_context) const OVERRIDE {
588 return new VisitRelayingRenderProcessHost(browser_context);
[email protected]3e90d4a2009-07-03 17:38:39589 }
590
[email protected]3e90d4a2009-07-03 17:38:39591 private:
[email protected]3e90d4a2009-07-03 17:38:39592
593 DISALLOW_COPY_AND_ASSIGN(VisitedLinkRenderProcessHostFactory);
594};
595
[email protected]4c3d9d62013-01-09 22:37:20596// TODO(boliu): Inherit content::RenderViewHostTestHarness when componentized.
[email protected]93ab5932011-09-14 07:38:17597class VisitedLinkEventsTest : public ChromeRenderViewHostTestHarness {
[email protected]3e90d4a2009-07-03 17:38:39598 public:
[email protected]6fad2632009-11-02 05:59:37599 VisitedLinkEventsTest()
[email protected]93ab5932011-09-14 07:38:17600 : ui_thread_(BrowserThread::UI, &message_loop_),
[email protected]0c7d74f2010-10-11 11:55:26601 file_thread_(BrowserThread::FILE, &message_loop_) {}
[email protected]93ab5932011-09-14 07:38:17602 virtual ~VisitedLinkEventsTest() {}
[email protected]3e90d4a2009-07-03 17:38:39603 virtual void SetUp() {
[email protected]2d66488c2011-10-14 21:10:00604 browser_context_.reset(new VisitCountingProfile());
[email protected]bff706b2013-01-25 00:15:01605 master_.reset(new VisitedLinkMaster(profile(), &delegate_, true));
[email protected]4c3d9d62013-01-09 22:37:20606 master_->Init();
[email protected]9a46725f2012-10-24 18:25:48607 SetRenderProcessHostFactory(&vc_rph_factory_);
[email protected]4c3d9d62013-01-09 22:37:20608 content::RenderViewHostTestHarness::SetUp();
[email protected]3e90d4a2009-07-03 17:38:39609 }
610
611 VisitCountingProfile* profile() const {
[email protected]93ab5932011-09-14 07:38:17612 return static_cast<VisitCountingProfile*>(browser_context_.get());
[email protected]3e90d4a2009-07-03 17:38:39613 }
614
[email protected]5016ee12012-10-26 23:56:31615 VisitedLinkMaster* master() const {
[email protected]4c3d9d62013-01-09 22:37:20616 return master_.get();
[email protected]5016ee12012-10-26 23:56:31617 }
618
[email protected]3e90d4a2009-07-03 17:38:39619 void WaitForCoalescense() {
620 // Let the timer fire.
[email protected]02798a982012-01-27 00:45:33621 MessageLoop::current()->PostDelayedTask(
622 FROM_HERE,
623 MessageLoop::QuitClosure(),
624 base::TimeDelta::FromMilliseconds(110));
[email protected]3e90d4a2009-07-03 17:38:39625 MessageLoop::current()->Run();
626 }
627
628 protected:
629 VisitedLinkRenderProcessHostFactory vc_rph_factory_;
630
631 private:
[email protected]4c3d9d62013-01-09 22:37:20632 TestVisitedLinkDelegate delegate_;
633 scoped_ptr<VisitedLinkMaster> master_;
[email protected]c38831a12011-10-28 12:44:49634 content::TestBrowserThread ui_thread_;
635 content::TestBrowserThread file_thread_;
[email protected]3e90d4a2009-07-03 17:38:39636
637 DISALLOW_COPY_AND_ASSIGN(VisitedLinkEventsTest);
638};
639
[email protected]3e90d4a2009-07-03 17:38:39640TEST_F(VisitedLinkEventsTest, Coalescense) {
641 // add some URLs to master.
[email protected]3e90d4a2009-07-03 17:38:39642 // Add a few URLs.
[email protected]5016ee12012-10-26 23:56:31643 master()->AddURL(GURL("http://acidtests.org/"));
644 master()->AddURL(GURL("http://google.com/"));
645 master()->AddURL(GURL("http://chromium.org/"));
[email protected]3e90d4a2009-07-03 17:38:39646 // Just for kicks, add a duplicate URL. This shouldn't increase the resulting
[email protected]5016ee12012-10-26 23:56:31647 master()->AddURL(GURL("http://acidtests.org/"));
[email protected]3e90d4a2009-07-03 17:38:39648
649 // Make sure that coalescing actually occurs. There should be no links or
650 // events received by the renderer.
651 EXPECT_EQ(0, profile()->add_count());
652 EXPECT_EQ(0, profile()->add_event_count());
653
654 WaitForCoalescense();
655
656 // We now should have 3 entries added in 1 event.
657 EXPECT_EQ(3, profile()->add_count());
658 EXPECT_EQ(1, profile()->add_event_count());
659
660 // Test whether the coalescing continues by adding a few more URLs.
[email protected]5016ee12012-10-26 23:56:31661 master()->AddURL(GURL("http://google.com/chrome/"));
662 master()->AddURL(GURL("http://webkit.org/"));
663 master()->AddURL(GURL("http://acid3.acidtests.org/"));
[email protected]3e90d4a2009-07-03 17:38:39664
665 WaitForCoalescense();
666
667 // We should have 6 entries added in 2 events.
668 EXPECT_EQ(6, profile()->add_count());
669 EXPECT_EQ(2, profile()->add_event_count());
670
671 // Test whether duplicate entries produce add events.
[email protected]5016ee12012-10-26 23:56:31672 master()->AddURL(GURL("http://acidtests.org/"));
[email protected]3e90d4a2009-07-03 17:38:39673
674 WaitForCoalescense();
675
676 // We should have no change in results.
677 EXPECT_EQ(6, profile()->add_count());
678 EXPECT_EQ(2, profile()->add_event_count());
679
680 // Ensure that the coalescing does not resume after resetting.
[email protected]5016ee12012-10-26 23:56:31681 master()->AddURL(GURL("http://build.chromium.org/"));
682 master()->DeleteAllURLs();
[email protected]3e90d4a2009-07-03 17:38:39683
684 WaitForCoalescense();
685
686 // We should have no change in results except for one new reset event.
687 EXPECT_EQ(6, profile()->add_count());
688 EXPECT_EQ(2, profile()->add_event_count());
689 EXPECT_EQ(1, profile()->reset_event_count());
690}
691
[email protected]7fa7dd52011-04-24 01:09:42692TEST_F(VisitedLinkEventsTest, Basics) {
[email protected]4c3d9d62013-01-09 22:37:20693 RenderViewHostTester::For(rvh())->CreateRenderView(string16(),
[email protected]7900bfdb2012-05-24 19:31:24694 MSG_ROUTING_NONE,
[email protected]7900bfdb2012-05-24 19:31:24695 -1);
[email protected]6e8d64642009-08-10 15:27:19696
[email protected]3e90d4a2009-07-03 17:38:39697 // Add a few URLs.
[email protected]5016ee12012-10-26 23:56:31698 master()->AddURL(GURL("http://acidtests.org/"));
699 master()->AddURL(GURL("http://google.com/"));
700 master()->AddURL(GURL("http://chromium.org/"));
[email protected]3e90d4a2009-07-03 17:38:39701
702 WaitForCoalescense();
703
704 // We now should have 1 add event.
705 EXPECT_EQ(1, profile()->add_event_count());
706 EXPECT_EQ(0, profile()->reset_event_count());
707
[email protected]5016ee12012-10-26 23:56:31708 master()->DeleteAllURLs();
[email protected]3e90d4a2009-07-03 17:38:39709
710 WaitForCoalescense();
711
712 // We should have no change in add results, plus one new reset event.
713 EXPECT_EQ(1, profile()->add_event_count());
714 EXPECT_EQ(1, profile()->reset_event_count());
715}
716
[email protected]7fa7dd52011-04-24 01:09:42717TEST_F(VisitedLinkEventsTest, TabVisibility) {
[email protected]4c3d9d62013-01-09 22:37:20718 RenderViewHostTester::For(rvh())->CreateRenderView(string16(),
[email protected]7900bfdb2012-05-24 19:31:24719 MSG_ROUTING_NONE,
[email protected]7900bfdb2012-05-24 19:31:24720 -1);
[email protected]3e90d4a2009-07-03 17:38:39721
722 // Simulate tab becoming inactive.
[email protected]4c3d9d62013-01-09 22:37:20723 RenderViewHostTester::For(rvh())->SimulateWasHidden();
[email protected]3e90d4a2009-07-03 17:38:39724
725 // Add a few URLs.
[email protected]5016ee12012-10-26 23:56:31726 master()->AddURL(GURL("http://acidtests.org/"));
727 master()->AddURL(GURL("http://google.com/"));
728 master()->AddURL(GURL("http://chromium.org/"));
[email protected]3e90d4a2009-07-03 17:38:39729
730 WaitForCoalescense();
731
732 // We shouldn't have any events.
733 EXPECT_EQ(0, profile()->add_event_count());
734 EXPECT_EQ(0, profile()->reset_event_count());
735
736 // Simulate the tab becoming active.
[email protected]4c3d9d62013-01-09 22:37:20737 RenderViewHostTester::For(rvh())->SimulateWasShown();
[email protected]3e90d4a2009-07-03 17:38:39738
739 // We should now have 3 add events, still no reset events.
740 EXPECT_EQ(1, profile()->add_event_count());
741 EXPECT_EQ(0, profile()->reset_event_count());
742
743 // Deactivate the tab again.
[email protected]4c3d9d62013-01-09 22:37:20744 RenderViewHostTester::For(rvh())->SimulateWasHidden();
[email protected]3e90d4a2009-07-03 17:38:39745
746 // Add a bunch of URLs (over 50) to exhaust the link event buffer.
747 for (int i = 0; i < 100; i++)
[email protected]5016ee12012-10-26 23:56:31748 master()->AddURL(TestURL(i));
[email protected]3e90d4a2009-07-03 17:38:39749
750 WaitForCoalescense();
751
752 // Again, no change in events until tab is active.
753 EXPECT_EQ(1, profile()->add_event_count());
754 EXPECT_EQ(0, profile()->reset_event_count());
755
756 // Activate the tab.
[email protected]4c3d9d62013-01-09 22:37:20757 RenderViewHostTester::For(rvh())->SimulateWasShown();
[email protected]3e90d4a2009-07-03 17:38:39758
759 // We should have only one more reset event.
760 EXPECT_EQ(1, profile()->add_event_count());
761 EXPECT_EQ(1, profile()->reset_event_count());
762}
[email protected]1f371fa2013-01-23 00:35:14763
[email protected]c2134fb2013-01-23 04:28:52764// Tests that VisitedLink ignores renderer process creation notification for a
765// different profile.
766TEST_F(VisitedLinkEventsTest, IgnoreRendererCreationFromDifferentContext) {
767 VisitCountingProfile different_context;
768 VisitRelayingRenderProcessHost different_process_host(&different_context);
769
770 content::NotificationService::current()->Notify(
771 content::NOTIFICATION_RENDERER_PROCESS_CREATED,
772 content::Source<content::RenderProcessHost>(&different_process_host),
773 content::NotificationService::NoDetails());
774 WaitForCoalescense();
775
776 EXPECT_EQ(0, different_context.new_table_count());
777
778}
779
[email protected]1f371fa2013-01-23 00:35:14780} // namespace components