blob: cf0f14dd39cdad345f06f860623fc6a04ab275b7 [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"
[email protected]ec04d3f2013-06-06 21:31:3913#include "base/run_loop.h"
initial.commit09911bf2008-07-26 23:55:2914#include "base/shared_memory.h"
15#include "base/string_util.h"
[email protected]853e01b2012-09-21 20:14:1116#include "base/time.h"
[email protected]1f371fa2013-01-23 00:35:1417#include "components/visitedlink/browser/visitedlink_delegate.h"
18#include "components/visitedlink/browser/visitedlink_event_listener.h"
19#include "components/visitedlink/browser/visitedlink_master.h"
20#include "components/visitedlink/common/visitedlink_messages.h"
21#include "components/visitedlink/renderer/visitedlink_slave.h"
[email protected]ec04d3f2013-06-06 21:31:3922#include "content/public/browser/browser_thread.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]ec04d3f2013-06-06 21:31:3927#include "content/public/test/test_browser_thread_bundle.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]ab3eaeed2013-05-17 00:18:4436namespace visitedlink {
[email protected]1f371fa2013-01-23 00:35:1437
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) {
[email protected]7d3cbc92013-03-18 22:33:0449 return GURL(base::StringPrintf("%s%d", g_test_prefix, i));
initial.commit09911bf2008-07-26 23:55:2950}
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
[email protected]59e6b802013-02-07 13:29:33112 virtual void NewTable(base::SharedMemory* table) OVERRIDE {
[email protected]3e90d4a2009-07-03 17:38:39113 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]59e6b802013-02-07 13:29:33122 virtual void Add(VisitedLinkCommon::Fingerprint) OVERRIDE { add_count_++; }
123 virtual void Reset() OVERRIDE { 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:
initial.commit09911bf2008-07-26 23:55:29140 // Initializes the visited link objects. Pass in the size that you want a
141 // freshly created table to be. 0 means use the default.
142 //
143 // |suppress_rebuild| is set when we're not testing rebuilding, see
144 // the VisitedLinkMaster constructor.
145 bool InitVisited(int initial_size, bool suppress_rebuild) {
146 // Initialize the visited link system.
[email protected]b42e6d82012-11-02 02:44:56147 master_.reset(new VisitedLinkMaster(new TrackingVisitedLinkEventListener(),
[email protected]4c3d9d62013-01-09 22:37:20148 &delegate_,
[email protected]bff706b2013-01-25 00:15:01149 true,
[email protected]3e90d4a2009-07-03 17:38:39150 suppress_rebuild, visited_file_,
151 initial_size));
initial.commit09911bf2008-07-26 23:55:29152 return master_->Init();
153 }
154
155 // May be called multiple times (some tests will do this to clear things,
156 // and TearDown will do this to make sure eveything is shiny before quitting.
157 void ClearDB() {
158 if (master_.get())
159 master_.reset(NULL);
160
[email protected]3189013e2012-01-19 04:11:57161 // Wait for all pending file I/O to be completed.
162 BrowserThread::GetBlockingPool()->FlushForTesting();
initial.commit09911bf2008-07-26 23:55:29163 }
164
165 // Loads the database from disk and makes sure that the same URLs are present
166 // as were generated by TestIO_Create(). This also checks the URLs with a
167 // slave to make sure it reads the data properly.
168 void Reload() {
169 // Clean up after our caller, who may have left the database open.
170 ClearDB();
171
initial.commit09911bf2008-07-26 23:55:29172 ASSERT_TRUE(InitVisited(0, true));
173 master_->DebugValidate();
174
175 // check that the table has the proper number of entries
176 int used_count = master_->GetUsedCount();
177 ASSERT_EQ(used_count, g_test_count);
178
179 // Create a slave database.
180 VisitedLinkSlave slave;
[email protected]76aac1e2009-03-16 16:45:36181 base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle();
[email protected]9610ef242009-11-18 02:41:26182 master_->shared_memory()->ShareToProcess(
183 base::GetCurrentProcessHandle(), &new_handle);
[email protected]8d97ade2011-04-14 18:17:08184 slave.OnUpdateVisitedLinks(new_handle);
initial.commit09911bf2008-07-26 23:55:29185 g_slaves.push_back(&slave);
186
187 bool found;
188 for (int i = 0; i < g_test_count; i++) {
189 GURL cur = TestURL(i);
190 found = master_->IsVisited(cur);
191 EXPECT_TRUE(found) << "URL " << i << "not found in master.";
192
193 found = slave.IsVisited(cur);
194 EXPECT_TRUE(found) << "URL " << i << "not found in slave.";
195 }
196
197 // test some random URL so we know that it returns false sometimes too
198 found = master_->IsVisited(GURL("http://unfound.site/"));
199 ASSERT_FALSE(found);
200 found = slave.IsVisited(GURL("http://unfound.site/"));
201 ASSERT_FALSE(found);
202
203 master_->DebugValidate();
204
205 g_slaves.clear();
206 }
207
208 // testing::Test
209 virtual void SetUp() {
[email protected]f708ed12010-09-23 12:18:34210 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
211
212 history_dir_ = temp_dir_.path().AppendASCII("VisitedLinkTest");
213 ASSERT_TRUE(file_util::CreateDirectory(history_dir_));
initial.commit09911bf2008-07-26 23:55:29214
[email protected]c2c998c2009-01-27 19:08:39215 visited_file_ = history_dir_.Append(FILE_PATH_LITERAL("VisitedLinks"));
initial.commit09911bf2008-07-26 23:55:29216 }
217
218 virtual void TearDown() {
219 ClearDB();
initial.commit09911bf2008-07-26 23:55:29220 }
[email protected]f0a51fb52009-03-05 12:46:38221
[email protected]ea1a3f62012-11-16 20:34:23222 base::ScopedTempDir temp_dir_;
[email protected]f708ed12010-09-23 12:18:34223
initial.commit09911bf2008-07-26 23:55:29224 // Filenames for the services;
[email protected]9e275712013-02-10 19:20:14225 base::FilePath history_dir_;
226 base::FilePath visited_file_;
initial.commit09911bf2008-07-26 23:55:29227
228 scoped_ptr<VisitedLinkMaster> master_;
[email protected]4c3d9d62013-01-09 22:37:20229 TestVisitedLinkDelegate delegate_;
[email protected]ec04d3f2013-06-06 21:31:39230 content::TestBrowserThreadBundle thread_bundle_;
initial.commit09911bf2008-07-26 23:55:29231};
232
initial.commit09911bf2008-07-26 23:55:29233// This test creates and reads some databases to make sure the data is
234// preserved throughout those operations.
235TEST_F(VisitedLinkTest, DatabaseIO) {
initial.commit09911bf2008-07-26 23:55:29236 ASSERT_TRUE(InitVisited(0, true));
237
238 for (int i = 0; i < g_test_count; i++)
239 master_->AddURL(TestURL(i));
240
241 // Test that the database was written properly
242 Reload();
243}
244
245// Checks that we can delete things properly when there are collisions.
246TEST_F(VisitedLinkTest, Delete) {
247 static const int32 kInitialSize = 17;
initial.commit09911bf2008-07-26 23:55:29248 ASSERT_TRUE(InitVisited(kInitialSize, true));
249
250 // Add a cluster from 14-17 wrapping around to 0. These will all hash to the
251 // same value.
[email protected]c2c998c2009-01-27 19:08:39252 const VisitedLinkCommon::Fingerprint kFingerprint0 = kInitialSize * 0 + 14;
253 const VisitedLinkCommon::Fingerprint kFingerprint1 = kInitialSize * 1 + 14;
254 const VisitedLinkCommon::Fingerprint kFingerprint2 = kInitialSize * 2 + 14;
255 const VisitedLinkCommon::Fingerprint kFingerprint3 = kInitialSize * 3 + 14;
256 const VisitedLinkCommon::Fingerprint kFingerprint4 = kInitialSize * 4 + 14;
[email protected]f8c42c92009-07-04 17:22:08257 master_->AddFingerprint(kFingerprint0, false); // @14
258 master_->AddFingerprint(kFingerprint1, false); // @15
259 master_->AddFingerprint(kFingerprint2, false); // @16
260 master_->AddFingerprint(kFingerprint3, false); // @0
261 master_->AddFingerprint(kFingerprint4, false); // @1
initial.commit09911bf2008-07-26 23:55:29262
263 // Deleting 14 should move the next value up one slot (we do not specify an
264 // order).
265 EXPECT_EQ(kFingerprint3, master_->hash_table_[0]);
266 master_->DeleteFingerprint(kFingerprint3, false);
[email protected]c2c998c2009-01-27 19:08:39267 VisitedLinkCommon::Fingerprint zero_fingerprint = 0;
268 EXPECT_EQ(zero_fingerprint, master_->hash_table_[1]);
269 EXPECT_NE(zero_fingerprint, master_->hash_table_[0]);
initial.commit09911bf2008-07-26 23:55:29270
271 // Deleting the other four should leave the table empty.
272 master_->DeleteFingerprint(kFingerprint0, false);
273 master_->DeleteFingerprint(kFingerprint1, false);
274 master_->DeleteFingerprint(kFingerprint2, false);
275 master_->DeleteFingerprint(kFingerprint4, false);
276
277 EXPECT_EQ(0, master_->used_items_);
278 for (int i = 0; i < kInitialSize; i++)
[email protected]c2c998c2009-01-27 19:08:39279 EXPECT_EQ(zero_fingerprint, master_->hash_table_[i]) <<
280 "Hash table has values in it.";
initial.commit09911bf2008-07-26 23:55:29281}
282
283// When we delete more than kBigDeleteThreshold we trigger different behavior
284// where the entire file is rewritten.
285TEST_F(VisitedLinkTest, BigDelete) {
initial.commit09911bf2008-07-26 23:55:29286 ASSERT_TRUE(InitVisited(16381, true));
287
288 // Add the base set of URLs that won't be deleted.
289 // Reload() will test for these.
290 for (int32 i = 0; i < g_test_count; i++)
291 master_->AddURL(TestURL(i));
292
293 // Add more URLs than necessary to trigger this case.
294 const int kTestDeleteCount = VisitedLinkMaster::kBigDeleteThreshold + 2;
[email protected]4c3d9d62013-01-09 22:37:20295 URLs urls_to_delete;
initial.commit09911bf2008-07-26 23:55:29296 for (int32 i = g_test_count; i < g_test_count + kTestDeleteCount; i++) {
297 GURL url(TestURL(i));
298 master_->AddURL(url);
[email protected]4c3d9d62013-01-09 22:37:20299 urls_to_delete.push_back(url);
initial.commit09911bf2008-07-26 23:55:29300 }
301
[email protected]4c3d9d62013-01-09 22:37:20302 TestURLIterator iterator(urls_to_delete);
303 master_->DeleteURLs(&iterator);
initial.commit09911bf2008-07-26 23:55:29304 master_->DebugValidate();
305
306 Reload();
307}
308
309TEST_F(VisitedLinkTest, DeleteAll) {
initial.commit09911bf2008-07-26 23:55:29310 ASSERT_TRUE(InitVisited(0, true));
311
312 {
313 VisitedLinkSlave slave;
[email protected]76aac1e2009-03-16 16:45:36314 base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle();
[email protected]9610ef242009-11-18 02:41:26315 master_->shared_memory()->ShareToProcess(
316 base::GetCurrentProcessHandle(), &new_handle);
[email protected]8d97ade2011-04-14 18:17:08317 slave.OnUpdateVisitedLinks(new_handle);
initial.commit09911bf2008-07-26 23:55:29318 g_slaves.push_back(&slave);
319
320 // Add the test URLs.
321 for (int i = 0; i < g_test_count; i++) {
322 master_->AddURL(TestURL(i));
323 ASSERT_EQ(i + 1, master_->GetUsedCount());
324 }
325 master_->DebugValidate();
326
327 // Make sure the slave picked up the adds.
328 for (int i = 0; i < g_test_count; i++)
329 EXPECT_TRUE(slave.IsVisited(TestURL(i)));
330
331 // Clear the table and make sure the slave picked it up.
332 master_->DeleteAllURLs();
333 EXPECT_EQ(0, master_->GetUsedCount());
334 for (int i = 0; i < g_test_count; i++) {
335 EXPECT_FALSE(master_->IsVisited(TestURL(i)));
336 EXPECT_FALSE(slave.IsVisited(TestURL(i)));
337 }
338
339 // Close the database.
340 g_slaves.clear();
341 ClearDB();
342 }
343
344 // Reopen and validate.
initial.commit09911bf2008-07-26 23:55:29345 ASSERT_TRUE(InitVisited(0, true));
346 master_->DebugValidate();
347 EXPECT_EQ(0, master_->GetUsedCount());
348 for (int i = 0; i < g_test_count; i++)
349 EXPECT_FALSE(master_->IsVisited(TestURL(i)));
350}
351
352// This tests that the master correctly resizes its tables when it gets too
353// full, notifies its slaves of the change, and updates the disk.
354TEST_F(VisitedLinkTest, Resizing) {
355 // Create a very small database.
356 const int32 initial_size = 17;
initial.commit09911bf2008-07-26 23:55:29357 ASSERT_TRUE(InitVisited(initial_size, true));
358
359 // ...and a slave
360 VisitedLinkSlave slave;
[email protected]76aac1e2009-03-16 16:45:36361 base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle();
[email protected]9610ef242009-11-18 02:41:26362 master_->shared_memory()->ShareToProcess(
363 base::GetCurrentProcessHandle(), &new_handle);
[email protected]8d97ade2011-04-14 18:17:08364 slave.OnUpdateVisitedLinks(new_handle);
initial.commit09911bf2008-07-26 23:55:29365 g_slaves.push_back(&slave);
366
367 int32 used_count = master_->GetUsedCount();
368 ASSERT_EQ(used_count, 0);
369
370 for (int i = 0; i < g_test_count; i++) {
371 master_->AddURL(TestURL(i));
372 used_count = master_->GetUsedCount();
373 ASSERT_EQ(i + 1, used_count);
374 }
375
376 // Verify that the table got resized sufficiently.
377 int32 table_size;
378 VisitedLinkCommon::Fingerprint* table;
379 master_->GetUsageStatistics(&table_size, &table);
380 used_count = master_->GetUsedCount();
381 ASSERT_GT(table_size, used_count);
382 ASSERT_EQ(used_count, g_test_count) <<
383 "table count doesn't match the # of things we added";
384
385 // Verify that the slave got the resize message and has the same
386 // table information.
387 int32 child_table_size;
388 VisitedLinkCommon::Fingerprint* child_table;
389 slave.GetUsageStatistics(&child_table_size, &child_table);
390 ASSERT_EQ(table_size, child_table_size);
391 for (int32 i = 0; i < table_size; i++) {
392 ASSERT_EQ(table[i], child_table[i]);
393 }
394
395 master_->DebugValidate();
396 g_slaves.clear();
397
398 // This tests that the file is written correctly by reading it in using
399 // a new database.
400 Reload();
401}
402
403// Tests that if the database doesn't exist, it will be rebuilt from history.
404TEST_F(VisitedLinkTest, Rebuild) {
initial.commit09911bf2008-07-26 23:55:29405 // Add half of our URLs to history. This needs to be done before we
406 // initialize the visited link DB.
407 int history_count = g_test_count / 2;
408 for (int i = 0; i < history_count; i++)
[email protected]4c3d9d62013-01-09 22:37:20409 delegate_.AddURLForRebuild(TestURL(i));
initial.commit09911bf2008-07-26 23:55:29410
411 // Initialize the visited link DB. Since the visited links file doesn't exist
412 // and we don't suppress history rebuilding, this will load from history.
413 ASSERT_TRUE(InitVisited(0, false));
414
415 // While the table is rebuilding, add the rest of the URLs to the visited
416 // link system. This isn't guaranteed to happen during the rebuild, so we
417 // can't be 100% sure we're testing the right thing, but in practice is.
418 // All the adds above will generally take some time queuing up on the
419 // history thread, and it will take a while to catch up to actually
420 // processing the rebuild that has queued behind it. We will generally
421 // finish adding all of the URLs before it has even found the first URL.
422 for (int i = history_count; i < g_test_count; i++)
423 master_->AddURL(TestURL(i));
424
425 // Add one more and then delete it.
426 master_->AddURL(TestURL(g_test_count));
[email protected]4c3d9d62013-01-09 22:37:20427 URLs urls_to_delete;
428 urls_to_delete.push_back(TestURL(g_test_count));
429 TestURLIterator iterator(urls_to_delete);
430 master_->DeleteURLs(&iterator);
initial.commit09911bf2008-07-26 23:55:29431
432 // Wait for the rebuild to complete. The task will terminate the message
433 // loop when the rebuild is done. There's no chance that the rebuild will
434 // complete before we set the task because the rebuild completion message
435 // is posted to the message loop; until we Run() it, rebuild can not
436 // complete.
[email protected]ec04d3f2013-06-06 21:31:39437 base::RunLoop run_loop;
438 master_->set_rebuild_complete_task(run_loop.QuitClosure());
439 run_loop.Run();
initial.commit09911bf2008-07-26 23:55:29440
441 // Test that all URLs were written to the database properly.
442 Reload();
443
444 // Make sure the extra one was *not* written (Reload won't test this).
445 EXPECT_FALSE(master_->IsVisited(TestURL(g_test_count)));
446}
[email protected]3e90d4a2009-07-03 17:38:39447
[email protected]aed132ed2009-08-19 22:44:12448// Test that importing a large number of URLs will work
449TEST_F(VisitedLinkTest, BigImport) {
[email protected]aed132ed2009-08-19 22:44:12450 ASSERT_TRUE(InitVisited(0, false));
451
452 // Before the table rebuilds, add a large number of URLs
453 int total_count = VisitedLinkMaster::kDefaultTableSize + 10;
454 for (int i = 0; i < total_count; i++)
455 master_->AddURL(TestURL(i));
456
457 // Wait for the rebuild to complete.
[email protected]ec04d3f2013-06-06 21:31:39458 base::RunLoop run_loop;
459 master_->set_rebuild_complete_task(run_loop.QuitClosure());
460 run_loop.Run();
[email protected]aed132ed2009-08-19 22:44:12461
462 // Ensure that the right number of URLs are present
463 int used_count = master_->GetUsedCount();
464 ASSERT_EQ(used_count, total_count);
465}
466
[email protected]3e90d4a2009-07-03 17:38:39467TEST_F(VisitedLinkTest, Listener) {
[email protected]3e90d4a2009-07-03 17:38:39468 ASSERT_TRUE(InitVisited(0, true));
469
470 // Add test URLs.
471 for (int i = 0; i < g_test_count; i++) {
472 master_->AddURL(TestURL(i));
473 ASSERT_EQ(i + 1, master_->GetUsedCount());
474 }
475
[email protected]3e90d4a2009-07-03 17:38:39476 // Delete an URL.
[email protected]4c3d9d62013-01-09 22:37:20477 URLs urls_to_delete;
478 urls_to_delete.push_back(TestURL(0));
479 TestURLIterator iterator(urls_to_delete);
480 master_->DeleteURLs(&iterator);
481
[email protected]3e90d4a2009-07-03 17:38:39482 // ... and all of the remaining ones.
483 master_->DeleteAllURLs();
484
[email protected]b42e6d82012-11-02 02:44:56485 TrackingVisitedLinkEventListener* listener =
486 static_cast<TrackingVisitedLinkEventListener*>(master_->GetListener());
487
[email protected]3e90d4a2009-07-03 17:38:39488 // Verify that VisitedLinkMaster::Listener::Add was called for each added URL.
[email protected]b42e6d82012-11-02 02:44:56489 EXPECT_EQ(g_test_count, listener->add_count());
[email protected]3e90d4a2009-07-03 17:38:39490 // Verify that VisitedLinkMaster::Listener::Reset was called both when one and
491 // all URLs are deleted.
[email protected]b42e6d82012-11-02 02:44:56492 EXPECT_EQ(2, listener->reset_count());
[email protected]3e90d4a2009-07-03 17:38:39493}
494
[email protected]28a66e252013-01-25 07:54:02495class VisitCountingContext : public content::TestBrowserContext {
[email protected]3e90d4a2009-07-03 17:38:39496 public:
[email protected]28a66e252013-01-25 07:54:02497 VisitCountingContext()
[email protected]3e90d4a2009-07-03 17:38:39498 : add_count_(0),
499 add_event_count_(0),
[email protected]c2134fb2013-01-23 04:28:52500 reset_event_count_(0),
501 new_table_count_(0) {}
[email protected]3e90d4a2009-07-03 17:38:39502
503 void CountAddEvent(int by) {
504 add_count_ += by;
505 add_event_count_++;
506 }
507
508 void CountResetEvent() {
509 reset_event_count_++;
510 }
511
[email protected]c2134fb2013-01-23 04:28:52512 void CountNewTable() {
513 new_table_count_++;
514 }
515
[email protected]3e90d4a2009-07-03 17:38:39516 int add_count() const { return add_count_; }
517 int add_event_count() const { return add_event_count_; }
518 int reset_event_count() const { return reset_event_count_; }
[email protected]c2134fb2013-01-23 04:28:52519 int new_table_count() const { return new_table_count_; }
[email protected]3e90d4a2009-07-03 17:38:39520
521 private:
522 int add_count_;
523 int add_event_count_;
524 int reset_event_count_;
[email protected]c2134fb2013-01-23 04:28:52525 int new_table_count_;
[email protected]3e90d4a2009-07-03 17:38:39526};
527
[email protected]f3b1a082011-11-18 00:34:30528// Stub out as little as possible, borrowing from RenderProcessHost.
[email protected]b6a2f8de2012-01-31 17:28:49529class VisitRelayingRenderProcessHost : public MockRenderProcessHost {
[email protected]3e90d4a2009-07-03 17:38:39530 public:
[email protected]3d7474ff2011-07-27 17:47:37531 explicit VisitRelayingRenderProcessHost(
532 content::BrowserContext* browser_context)
[email protected]b6a2f8de2012-01-31 17:28:49533 : MockRenderProcessHost(browser_context), widgets_(0) {
[email protected]ad50def52011-10-19 23:17:07534 content::NotificationService::current()->Notify(
[email protected]432115822011-07-10 15:52:27535 content::NOTIFICATION_RENDERER_PROCESS_CREATED,
[email protected]6c2381d2011-10-19 02:52:53536 content::Source<RenderProcessHost>(this),
[email protected]ad50def52011-10-19 23:17:07537 content::NotificationService::NoDetails());
[email protected]3e90d4a2009-07-03 17:38:39538 }
539 virtual ~VisitRelayingRenderProcessHost() {
[email protected]ad50def52011-10-19 23:17:07540 content::NotificationService::current()->Notify(
[email protected]432115822011-07-10 15:52:27541 content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
[email protected]f3b1a082011-11-18 00:34:30542 content::Source<content::RenderProcessHost>(this),
[email protected]ad50def52011-10-19 23:17:07543 content::NotificationService::NoDetails());
[email protected]3e90d4a2009-07-03 17:38:39544 }
545
[email protected]b6a2f8de2012-01-31 17:28:49546 virtual void WidgetRestored() OVERRIDE { widgets_++; }
547 virtual void WidgetHidden() OVERRIDE { widgets_--; }
548 virtual int VisibleWidgetCount() const OVERRIDE { return widgets_; }
[email protected]3e90d4a2009-07-03 17:38:39549
[email protected]b6a2f8de2012-01-31 17:28:49550 virtual bool Send(IPC::Message* msg) OVERRIDE {
[email protected]28a66e252013-01-25 07:54:02551 VisitCountingContext* counting_context =
552 static_cast<VisitCountingContext*>(
[email protected]4c3d9d62013-01-09 22:37:20553 GetBrowserContext());
[email protected]3e90d4a2009-07-03 17:38:39554
[email protected]2ccf45c2011-08-19 23:35:50555 if (msg->type() == ChromeViewMsg_VisitedLink_Add::ID) {
[email protected]ce208f872012-03-07 20:42:56556 PickleIterator iter(*msg);
[email protected]7fa7dd52011-04-24 01:09:42557 std::vector<uint64> fingerprints;
558 CHECK(IPC::ReadParam(msg, &iter, &fingerprints));
[email protected]28a66e252013-01-25 07:54:02559 counting_context->CountAddEvent(fingerprints.size());
[email protected]2ccf45c2011-08-19 23:35:50560 } else if (msg->type() == ChromeViewMsg_VisitedLink_Reset::ID) {
[email protected]28a66e252013-01-25 07:54:02561 counting_context->CountResetEvent();
[email protected]c2134fb2013-01-23 04:28:52562 } else if (msg->type() == ChromeViewMsg_VisitedLink_NewTable::ID) {
[email protected]28a66e252013-01-25 07:54:02563 counting_context->CountNewTable();
[email protected]7fa7dd52011-04-24 01:09:42564 }
[email protected]3e90d4a2009-07-03 17:38:39565
566 delete msg;
567 return true;
568 }
569
[email protected]3e90d4a2009-07-03 17:38:39570 private:
[email protected]b6a2f8de2012-01-31 17:28:49571 int widgets_;
572
[email protected]3e90d4a2009-07-03 17:38:39573 DISALLOW_COPY_AND_ASSIGN(VisitRelayingRenderProcessHost);
574};
575
576class VisitedLinkRenderProcessHostFactory
[email protected]f3b1a082011-11-18 00:34:30577 : public content::RenderProcessHostFactory {
[email protected]3e90d4a2009-07-03 17:38:39578 public:
579 VisitedLinkRenderProcessHostFactory()
[email protected]f3b1a082011-11-18 00:34:30580 : content::RenderProcessHostFactory() {}
581 virtual content::RenderProcessHost* CreateRenderProcessHost(
[email protected]3d7474ff2011-07-27 17:47:37582 content::BrowserContext* browser_context) const OVERRIDE {
583 return new VisitRelayingRenderProcessHost(browser_context);
[email protected]3e90d4a2009-07-03 17:38:39584 }
585
[email protected]3e90d4a2009-07-03 17:38:39586 private:
[email protected]3e90d4a2009-07-03 17:38:39587
588 DISALLOW_COPY_AND_ASSIGN(VisitedLinkRenderProcessHostFactory);
589};
590
[email protected]28a66e252013-01-25 07:54:02591class VisitedLinkEventsTest : public content::RenderViewHostTestHarness {
[email protected]3e90d4a2009-07-03 17:38:39592 public:
[email protected]3e90d4a2009-07-03 17:38:39593 virtual void SetUp() {
[email protected]28a66e252013-01-25 07:54:02594 browser_context_.reset(new VisitCountingContext());
595 master_.reset(new VisitedLinkMaster(context(), &delegate_, true));
[email protected]4c3d9d62013-01-09 22:37:20596 master_->Init();
[email protected]9a46725f2012-10-24 18:25:48597 SetRenderProcessHostFactory(&vc_rph_factory_);
[email protected]4c3d9d62013-01-09 22:37:20598 content::RenderViewHostTestHarness::SetUp();
[email protected]3e90d4a2009-07-03 17:38:39599 }
600
[email protected]28a66e252013-01-25 07:54:02601 VisitCountingContext* context() const {
602 return static_cast<VisitCountingContext*>(browser_context_.get());
[email protected]3e90d4a2009-07-03 17:38:39603 }
604
[email protected]5016ee12012-10-26 23:56:31605 VisitedLinkMaster* master() const {
[email protected]4c3d9d62013-01-09 22:37:20606 return master_.get();
[email protected]5016ee12012-10-26 23:56:31607 }
608
[email protected]3e90d4a2009-07-03 17:38:39609 void WaitForCoalescense() {
610 // Let the timer fire.
[email protected]ec04d3f2013-06-06 21:31:39611 //
612 // TODO(ajwong): This is horrid! What is the right synchronization method?
613 base::RunLoop run_loop;
[email protected]d14c5b32013-05-06 05:25:11614 base::MessageLoop::current()->PostDelayedTask(
[email protected]02798a982012-01-27 00:45:33615 FROM_HERE,
[email protected]ec04d3f2013-06-06 21:31:39616 run_loop.QuitClosure(),
[email protected]02798a982012-01-27 00:45:33617 base::TimeDelta::FromMilliseconds(110));
[email protected]ec04d3f2013-06-06 21:31:39618 run_loop.Run();
[email protected]3e90d4a2009-07-03 17:38:39619 }
620
621 protected:
622 VisitedLinkRenderProcessHostFactory vc_rph_factory_;
623
624 private:
[email protected]4c3d9d62013-01-09 22:37:20625 TestVisitedLinkDelegate delegate_;
626 scoped_ptr<VisitedLinkMaster> master_;
[email protected]3e90d4a2009-07-03 17:38:39627};
628
[email protected]3e90d4a2009-07-03 17:38:39629TEST_F(VisitedLinkEventsTest, Coalescense) {
630 // add some URLs to master.
[email protected]3e90d4a2009-07-03 17:38:39631 // Add a few URLs.
[email protected]5016ee12012-10-26 23:56:31632 master()->AddURL(GURL("http://acidtests.org/"));
633 master()->AddURL(GURL("http://google.com/"));
634 master()->AddURL(GURL("http://chromium.org/"));
[email protected]3e90d4a2009-07-03 17:38:39635 // Just for kicks, add a duplicate URL. This shouldn't increase the resulting
[email protected]5016ee12012-10-26 23:56:31636 master()->AddURL(GURL("http://acidtests.org/"));
[email protected]3e90d4a2009-07-03 17:38:39637
638 // Make sure that coalescing actually occurs. There should be no links or
639 // events received by the renderer.
[email protected]28a66e252013-01-25 07:54:02640 EXPECT_EQ(0, context()->add_count());
641 EXPECT_EQ(0, context()->add_event_count());
[email protected]3e90d4a2009-07-03 17:38:39642
643 WaitForCoalescense();
644
645 // We now should have 3 entries added in 1 event.
[email protected]28a66e252013-01-25 07:54:02646 EXPECT_EQ(3, context()->add_count());
647 EXPECT_EQ(1, context()->add_event_count());
[email protected]3e90d4a2009-07-03 17:38:39648
649 // Test whether the coalescing continues by adding a few more URLs.
[email protected]5016ee12012-10-26 23:56:31650 master()->AddURL(GURL("http://google.com/chrome/"));
651 master()->AddURL(GURL("http://webkit.org/"));
652 master()->AddURL(GURL("http://acid3.acidtests.org/"));
[email protected]3e90d4a2009-07-03 17:38:39653
654 WaitForCoalescense();
655
656 // We should have 6 entries added in 2 events.
[email protected]28a66e252013-01-25 07:54:02657 EXPECT_EQ(6, context()->add_count());
658 EXPECT_EQ(2, context()->add_event_count());
[email protected]3e90d4a2009-07-03 17:38:39659
660 // Test whether duplicate entries produce add events.
[email protected]5016ee12012-10-26 23:56:31661 master()->AddURL(GURL("http://acidtests.org/"));
[email protected]3e90d4a2009-07-03 17:38:39662
663 WaitForCoalescense();
664
665 // We should have no change in results.
[email protected]28a66e252013-01-25 07:54:02666 EXPECT_EQ(6, context()->add_count());
667 EXPECT_EQ(2, context()->add_event_count());
[email protected]3e90d4a2009-07-03 17:38:39668
669 // Ensure that the coalescing does not resume after resetting.
[email protected]5016ee12012-10-26 23:56:31670 master()->AddURL(GURL("http://build.chromium.org/"));
671 master()->DeleteAllURLs();
[email protected]3e90d4a2009-07-03 17:38:39672
673 WaitForCoalescense();
674
675 // We should have no change in results except for one new reset event.
[email protected]28a66e252013-01-25 07:54:02676 EXPECT_EQ(6, context()->add_count());
677 EXPECT_EQ(2, context()->add_event_count());
678 EXPECT_EQ(1, context()->reset_event_count());
[email protected]3e90d4a2009-07-03 17:38:39679}
680
[email protected]7fa7dd52011-04-24 01:09:42681TEST_F(VisitedLinkEventsTest, Basics) {
[email protected]d5ca8fb2013-04-11 17:54:31682 RenderViewHostTester::For(rvh())->CreateRenderView(base::string16(),
[email protected]7900bfdb2012-05-24 19:31:24683 MSG_ROUTING_NONE,
[email protected]7900bfdb2012-05-24 19:31:24684 -1);
[email protected]6e8d64642009-08-10 15:27:19685
[email protected]3e90d4a2009-07-03 17:38:39686 // Add a few URLs.
[email protected]5016ee12012-10-26 23:56:31687 master()->AddURL(GURL("http://acidtests.org/"));
688 master()->AddURL(GURL("http://google.com/"));
689 master()->AddURL(GURL("http://chromium.org/"));
[email protected]3e90d4a2009-07-03 17:38:39690
691 WaitForCoalescense();
692
693 // We now should have 1 add event.
[email protected]28a66e252013-01-25 07:54:02694 EXPECT_EQ(1, context()->add_event_count());
695 EXPECT_EQ(0, context()->reset_event_count());
[email protected]3e90d4a2009-07-03 17:38:39696
[email protected]5016ee12012-10-26 23:56:31697 master()->DeleteAllURLs();
[email protected]3e90d4a2009-07-03 17:38:39698
699 WaitForCoalescense();
700
701 // We should have no change in add results, plus one new reset event.
[email protected]28a66e252013-01-25 07:54:02702 EXPECT_EQ(1, context()->add_event_count());
703 EXPECT_EQ(1, context()->reset_event_count());
[email protected]3e90d4a2009-07-03 17:38:39704}
705
[email protected]7fa7dd52011-04-24 01:09:42706TEST_F(VisitedLinkEventsTest, TabVisibility) {
[email protected]d5ca8fb2013-04-11 17:54:31707 RenderViewHostTester::For(rvh())->CreateRenderView(base::string16(),
[email protected]7900bfdb2012-05-24 19:31:24708 MSG_ROUTING_NONE,
[email protected]7900bfdb2012-05-24 19:31:24709 -1);
[email protected]3e90d4a2009-07-03 17:38:39710
711 // Simulate tab becoming inactive.
[email protected]4c3d9d62013-01-09 22:37:20712 RenderViewHostTester::For(rvh())->SimulateWasHidden();
[email protected]3e90d4a2009-07-03 17:38:39713
714 // Add a few URLs.
[email protected]5016ee12012-10-26 23:56:31715 master()->AddURL(GURL("http://acidtests.org/"));
716 master()->AddURL(GURL("http://google.com/"));
717 master()->AddURL(GURL("http://chromium.org/"));
[email protected]3e90d4a2009-07-03 17:38:39718
719 WaitForCoalescense();
720
721 // We shouldn't have any events.
[email protected]28a66e252013-01-25 07:54:02722 EXPECT_EQ(0, context()->add_event_count());
723 EXPECT_EQ(0, context()->reset_event_count());
[email protected]3e90d4a2009-07-03 17:38:39724
725 // Simulate the tab becoming active.
[email protected]4c3d9d62013-01-09 22:37:20726 RenderViewHostTester::For(rvh())->SimulateWasShown();
[email protected]3e90d4a2009-07-03 17:38:39727
728 // We should now have 3 add events, still no reset events.
[email protected]28a66e252013-01-25 07:54:02729 EXPECT_EQ(1, context()->add_event_count());
730 EXPECT_EQ(0, context()->reset_event_count());
[email protected]3e90d4a2009-07-03 17:38:39731
732 // Deactivate the tab again.
[email protected]4c3d9d62013-01-09 22:37:20733 RenderViewHostTester::For(rvh())->SimulateWasHidden();
[email protected]3e90d4a2009-07-03 17:38:39734
735 // Add a bunch of URLs (over 50) to exhaust the link event buffer.
736 for (int i = 0; i < 100; i++)
[email protected]5016ee12012-10-26 23:56:31737 master()->AddURL(TestURL(i));
[email protected]3e90d4a2009-07-03 17:38:39738
739 WaitForCoalescense();
740
741 // Again, no change in events until tab is active.
[email protected]28a66e252013-01-25 07:54:02742 EXPECT_EQ(1, context()->add_event_count());
743 EXPECT_EQ(0, context()->reset_event_count());
[email protected]3e90d4a2009-07-03 17:38:39744
745 // Activate the tab.
[email protected]4c3d9d62013-01-09 22:37:20746 RenderViewHostTester::For(rvh())->SimulateWasShown();
[email protected]3e90d4a2009-07-03 17:38:39747
748 // We should have only one more reset event.
[email protected]28a66e252013-01-25 07:54:02749 EXPECT_EQ(1, context()->add_event_count());
750 EXPECT_EQ(1, context()->reset_event_count());
[email protected]3e90d4a2009-07-03 17:38:39751}
[email protected]1f371fa2013-01-23 00:35:14752
[email protected]c2134fb2013-01-23 04:28:52753// Tests that VisitedLink ignores renderer process creation notification for a
[email protected]28a66e252013-01-25 07:54:02754// different context.
[email protected]c2134fb2013-01-23 04:28:52755TEST_F(VisitedLinkEventsTest, IgnoreRendererCreationFromDifferentContext) {
[email protected]28a66e252013-01-25 07:54:02756 VisitCountingContext different_context;
[email protected]c2134fb2013-01-23 04:28:52757 VisitRelayingRenderProcessHost different_process_host(&different_context);
758
759 content::NotificationService::current()->Notify(
760 content::NOTIFICATION_RENDERER_PROCESS_CREATED,
761 content::Source<content::RenderProcessHost>(&different_process_host),
762 content::NotificationService::NoDetails());
763 WaitForCoalescense();
764
765 EXPECT_EQ(0, different_context.new_table_count());
766
767}
768
[email protected]ab3eaeed2013-05-17 00:18:44769} // namespace visitedlink