Roll src/third_party/WebKit 9f7fb92:f103b33 (svn 202621:202622)
[chromium-blink-merge.git] / components / visitedlink / test / visitedlink_unittest.cc
blobf663f83b0cf816e2d9f6e69505cb5933105d256d
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <cstdio>
6 #include <string>
7 #include <vector>
9 #include "base/files/file_util.h"
10 #include "base/location.h"
11 #include "base/memory/shared_memory.h"
12 #include "base/process/process_handle.h"
13 #include "base/run_loop.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/strings/string_util.h"
16 #include "base/thread_task_runner_handle.h"
17 #include "base/time/time.h"
18 #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"
23 #include "content/public/browser/browser_thread.h"
24 #include "content/public/browser/notification_service.h"
25 #include "content/public/browser/notification_types.h"
26 #include "content/public/test/mock_render_process_host.h"
27 #include "content/public/test/test_browser_context.h"
28 #include "content/public/test/test_browser_thread_bundle.h"
29 #include "content/public/test/test_renderer_host.h"
30 #include "content/public/test/test_utils.h"
31 #include "testing/gtest/include/gtest/gtest.h"
32 #include "url/gurl.h"
34 using content::BrowserThread;
35 using content::MockRenderProcessHost;
36 using content::RenderViewHostTester;
38 namespace visitedlink {
40 namespace {
42 typedef std::vector<GURL> URLs;
44 // a nice long URL that we can append numbers to to get new URLs
45 const char g_test_prefix[] =
46 "http://www.google.com/products/foo/index.html?id=45028640526508376&seq=";
47 const int g_test_count = 1000;
49 // Returns a test URL for index |i|
50 GURL TestURL(int i) {
51 return GURL(base::StringPrintf("%s%d", g_test_prefix, i));
54 std::vector<VisitedLinkSlave*> g_slaves;
56 class TestVisitedLinkDelegate : public VisitedLinkDelegate {
57 public:
58 void RebuildTable(const scoped_refptr<URLEnumerator>& enumerator) override;
60 void AddURLForRebuild(const GURL& url);
62 private:
63 URLs rebuild_urls_;
66 void 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);
75 void TestVisitedLinkDelegate::AddURLForRebuild(const GURL& url) {
76 rebuild_urls_.push_back(url);
79 class TestURLIterator : public VisitedLinkMaster::URLIterator {
80 public:
81 explicit TestURLIterator(const URLs& urls);
83 const GURL& NextURL() override;
84 bool HasNextURL() const override;
86 private:
87 URLs::const_iterator iterator_;
88 URLs::const_iterator end_;
91 TestURLIterator::TestURLIterator(const URLs& urls)
92 : iterator_(urls.begin()),
93 end_(urls.end()) {
96 const GURL& TestURLIterator::NextURL() {
97 return *(iterator_++);
100 bool TestURLIterator::HasNextURL() const {
101 return iterator_ != end_;
104 } // namespace
106 class TrackingVisitedLinkEventListener : public VisitedLinkMaster::Listener {
107 public:
108 TrackingVisitedLinkEventListener()
109 : reset_count_(0),
110 add_count_(0) {}
112 void NewTable(base::SharedMemory* table) override {
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);
118 g_slaves[i]->OnUpdateVisitedLinks(new_handle);
122 void Add(VisitedLinkCommon::Fingerprint) override { add_count_++; }
123 void Reset() override { reset_count_++; }
125 void SetUp() {
126 reset_count_ = 0;
127 add_count_ = 0;
130 int reset_count() const { return reset_count_; }
131 int add_count() const { return add_count_; }
133 private:
134 int reset_count_;
135 int add_count_;
138 class VisitedLinkTest : public testing::Test {
139 protected:
140 // Initializes the visited link objects. Pass in the size that you want a
141 // freshly created table to be. 0 means use the default.
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.
147 master_.reset(new VisitedLinkMaster(new TrackingVisitedLinkEventListener(),
148 &delegate_,
149 true,
150 suppress_rebuild, visited_file_,
151 initial_size));
152 return master_->Init();
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);
161 // Wait for all pending file I/O to be completed.
162 content::RunAllBlockingPoolTasksUntilIdle();
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();
172 ASSERT_TRUE(InitVisited(0, true));
173 master_->DebugValidate();
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);
179 // Create a slave database.
180 VisitedLinkSlave slave;
181 base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle();
182 master_->shared_memory()->ShareToProcess(
183 base::GetCurrentProcessHandle(), &new_handle);
184 slave.OnUpdateVisitedLinks(new_handle);
185 g_slaves.push_back(&slave);
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.";
193 found = slave.IsVisited(cur);
194 EXPECT_TRUE(found) << "URL " << i << "not found in slave.";
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);
203 master_->DebugValidate();
205 g_slaves.clear();
208 // testing::Test
209 void SetUp() override {
210 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
212 history_dir_ = temp_dir_.path().AppendASCII("VisitedLinkTest");
213 ASSERT_TRUE(base::CreateDirectory(history_dir_));
215 visited_file_ = history_dir_.Append(FILE_PATH_LITERAL("VisitedLinks"));
218 void TearDown() override { ClearDB(); }
220 base::ScopedTempDir temp_dir_;
222 // Filenames for the services;
223 base::FilePath history_dir_;
224 base::FilePath visited_file_;
226 scoped_ptr<VisitedLinkMaster> master_;
227 TestVisitedLinkDelegate delegate_;
228 content::TestBrowserThreadBundle thread_bundle_;
231 // This test creates and reads some databases to make sure the data is
232 // preserved throughout those operations.
233 TEST_F(VisitedLinkTest, DatabaseIO) {
234 ASSERT_TRUE(InitVisited(0, true));
236 for (int i = 0; i < g_test_count; i++)
237 master_->AddURL(TestURL(i));
239 // Test that the database was written properly
240 Reload();
243 // Checks that we can delete things properly when there are collisions.
244 TEST_F(VisitedLinkTest, Delete) {
245 static const int32 kInitialSize = 17;
246 ASSERT_TRUE(InitVisited(kInitialSize, true));
248 // Add a cluster from 14-17 wrapping around to 0. These will all hash to the
249 // same value.
250 const VisitedLinkCommon::Fingerprint kFingerprint0 = kInitialSize * 0 + 14;
251 const VisitedLinkCommon::Fingerprint kFingerprint1 = kInitialSize * 1 + 14;
252 const VisitedLinkCommon::Fingerprint kFingerprint2 = kInitialSize * 2 + 14;
253 const VisitedLinkCommon::Fingerprint kFingerprint3 = kInitialSize * 3 + 14;
254 const VisitedLinkCommon::Fingerprint kFingerprint4 = kInitialSize * 4 + 14;
255 master_->AddFingerprint(kFingerprint0, false); // @14
256 master_->AddFingerprint(kFingerprint1, false); // @15
257 master_->AddFingerprint(kFingerprint2, false); // @16
258 master_->AddFingerprint(kFingerprint3, false); // @0
259 master_->AddFingerprint(kFingerprint4, false); // @1
261 // Deleting 14 should move the next value up one slot (we do not specify an
262 // order).
263 EXPECT_EQ(kFingerprint3, master_->hash_table_[0]);
264 master_->DeleteFingerprint(kFingerprint3, false);
265 VisitedLinkCommon::Fingerprint zero_fingerprint = 0;
266 EXPECT_EQ(zero_fingerprint, master_->hash_table_[1]);
267 EXPECT_NE(zero_fingerprint, master_->hash_table_[0]);
269 // Deleting the other four should leave the table empty.
270 master_->DeleteFingerprint(kFingerprint0, false);
271 master_->DeleteFingerprint(kFingerprint1, false);
272 master_->DeleteFingerprint(kFingerprint2, false);
273 master_->DeleteFingerprint(kFingerprint4, false);
275 EXPECT_EQ(0, master_->used_items_);
276 for (int i = 0; i < kInitialSize; i++)
277 EXPECT_EQ(zero_fingerprint, master_->hash_table_[i]) <<
278 "Hash table has values in it.";
281 // When we delete more than kBigDeleteThreshold we trigger different behavior
282 // where the entire file is rewritten.
283 TEST_F(VisitedLinkTest, BigDelete) {
284 ASSERT_TRUE(InitVisited(16381, true));
286 // Add the base set of URLs that won't be deleted.
287 // Reload() will test for these.
288 for (int32 i = 0; i < g_test_count; i++)
289 master_->AddURL(TestURL(i));
291 // Add more URLs than necessary to trigger this case.
292 const int kTestDeleteCount = VisitedLinkMaster::kBigDeleteThreshold + 2;
293 URLs urls_to_delete;
294 for (int32 i = g_test_count; i < g_test_count + kTestDeleteCount; i++) {
295 GURL url(TestURL(i));
296 master_->AddURL(url);
297 urls_to_delete.push_back(url);
300 TestURLIterator iterator(urls_to_delete);
301 master_->DeleteURLs(&iterator);
302 master_->DebugValidate();
304 Reload();
307 TEST_F(VisitedLinkTest, DeleteAll) {
308 ASSERT_TRUE(InitVisited(0, true));
311 VisitedLinkSlave slave;
312 base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle();
313 master_->shared_memory()->ShareToProcess(
314 base::GetCurrentProcessHandle(), &new_handle);
315 slave.OnUpdateVisitedLinks(new_handle);
316 g_slaves.push_back(&slave);
318 // Add the test URLs.
319 for (int i = 0; i < g_test_count; i++) {
320 master_->AddURL(TestURL(i));
321 ASSERT_EQ(i + 1, master_->GetUsedCount());
323 master_->DebugValidate();
325 // Make sure the slave picked up the adds.
326 for (int i = 0; i < g_test_count; i++)
327 EXPECT_TRUE(slave.IsVisited(TestURL(i)));
329 // Clear the table and make sure the slave picked it up.
330 master_->DeleteAllURLs();
331 EXPECT_EQ(0, master_->GetUsedCount());
332 for (int i = 0; i < g_test_count; i++) {
333 EXPECT_FALSE(master_->IsVisited(TestURL(i)));
334 EXPECT_FALSE(slave.IsVisited(TestURL(i)));
337 // Close the database.
338 g_slaves.clear();
339 ClearDB();
342 // Reopen and validate.
343 ASSERT_TRUE(InitVisited(0, true));
344 master_->DebugValidate();
345 EXPECT_EQ(0, master_->GetUsedCount());
346 for (int i = 0; i < g_test_count; i++)
347 EXPECT_FALSE(master_->IsVisited(TestURL(i)));
350 // This tests that the master correctly resizes its tables when it gets too
351 // full, notifies its slaves of the change, and updates the disk.
352 TEST_F(VisitedLinkTest, Resizing) {
353 // Create a very small database.
354 const int32 initial_size = 17;
355 ASSERT_TRUE(InitVisited(initial_size, true));
357 // ...and a slave
358 VisitedLinkSlave slave;
359 base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle();
360 master_->shared_memory()->ShareToProcess(
361 base::GetCurrentProcessHandle(), &new_handle);
362 slave.OnUpdateVisitedLinks(new_handle);
363 g_slaves.push_back(&slave);
365 int32 used_count = master_->GetUsedCount();
366 ASSERT_EQ(used_count, 0);
368 for (int i = 0; i < g_test_count; i++) {
369 master_->AddURL(TestURL(i));
370 used_count = master_->GetUsedCount();
371 ASSERT_EQ(i + 1, used_count);
374 // Verify that the table got resized sufficiently.
375 int32 table_size;
376 VisitedLinkCommon::Fingerprint* table;
377 master_->GetUsageStatistics(&table_size, &table);
378 used_count = master_->GetUsedCount();
379 ASSERT_GT(table_size, used_count);
380 ASSERT_EQ(used_count, g_test_count) <<
381 "table count doesn't match the # of things we added";
383 // Verify that the slave got the resize message and has the same
384 // table information.
385 int32 child_table_size;
386 VisitedLinkCommon::Fingerprint* child_table;
387 slave.GetUsageStatistics(&child_table_size, &child_table);
388 ASSERT_EQ(table_size, child_table_size);
389 for (int32 i = 0; i < table_size; i++) {
390 ASSERT_EQ(table[i], child_table[i]);
393 master_->DebugValidate();
394 g_slaves.clear();
396 // This tests that the file is written correctly by reading it in using
397 // a new database.
398 Reload();
401 // Tests that if the database doesn't exist, it will be rebuilt from history.
402 TEST_F(VisitedLinkTest, Rebuild) {
403 // Add half of our URLs to history. This needs to be done before we
404 // initialize the visited link DB.
405 int history_count = g_test_count / 2;
406 for (int i = 0; i < history_count; i++)
407 delegate_.AddURLForRebuild(TestURL(i));
409 // Initialize the visited link DB. Since the visited links file doesn't exist
410 // and we don't suppress history rebuilding, this will load from history.
411 ASSERT_TRUE(InitVisited(0, false));
413 // While the table is rebuilding, add the rest of the URLs to the visited
414 // link system. This isn't guaranteed to happen during the rebuild, so we
415 // can't be 100% sure we're testing the right thing, but in practice is.
416 // All the adds above will generally take some time queuing up on the
417 // history thread, and it will take a while to catch up to actually
418 // processing the rebuild that has queued behind it. We will generally
419 // finish adding all of the URLs before it has even found the first URL.
420 for (int i = history_count; i < g_test_count; i++)
421 master_->AddURL(TestURL(i));
423 // Add one more and then delete it.
424 master_->AddURL(TestURL(g_test_count));
425 URLs urls_to_delete;
426 urls_to_delete.push_back(TestURL(g_test_count));
427 TestURLIterator iterator(urls_to_delete);
428 master_->DeleteURLs(&iterator);
430 // Wait for the rebuild to complete. The task will terminate the message
431 // loop when the rebuild is done. There's no chance that the rebuild will
432 // complete before we set the task because the rebuild completion message
433 // is posted to the message loop; until we Run() it, rebuild can not
434 // complete.
435 base::RunLoop run_loop;
436 master_->set_rebuild_complete_task(run_loop.QuitClosure());
437 run_loop.Run();
439 // Test that all URLs were written to the database properly.
440 Reload();
442 // Make sure the extra one was *not* written (Reload won't test this).
443 EXPECT_FALSE(master_->IsVisited(TestURL(g_test_count)));
446 // Test that importing a large number of URLs will work
447 TEST_F(VisitedLinkTest, BigImport) {
448 ASSERT_TRUE(InitVisited(0, false));
450 // Before the table rebuilds, add a large number of URLs
451 int total_count = VisitedLinkMaster::kDefaultTableSize + 10;
452 for (int i = 0; i < total_count; i++)
453 master_->AddURL(TestURL(i));
455 // Wait for the rebuild to complete.
456 base::RunLoop run_loop;
457 master_->set_rebuild_complete_task(run_loop.QuitClosure());
458 run_loop.Run();
460 // Ensure that the right number of URLs are present
461 int used_count = master_->GetUsedCount();
462 ASSERT_EQ(used_count, total_count);
465 TEST_F(VisitedLinkTest, Listener) {
466 ASSERT_TRUE(InitVisited(0, true));
468 // Add test URLs.
469 for (int i = 0; i < g_test_count; i++) {
470 master_->AddURL(TestURL(i));
471 ASSERT_EQ(i + 1, master_->GetUsedCount());
474 // Delete an URL.
475 URLs urls_to_delete;
476 urls_to_delete.push_back(TestURL(0));
477 TestURLIterator iterator(urls_to_delete);
478 master_->DeleteURLs(&iterator);
480 // ... and all of the remaining ones.
481 master_->DeleteAllURLs();
483 TrackingVisitedLinkEventListener* listener =
484 static_cast<TrackingVisitedLinkEventListener*>(master_->GetListener());
486 // Verify that VisitedLinkMaster::Listener::Add was called for each added URL.
487 EXPECT_EQ(g_test_count, listener->add_count());
488 // Verify that VisitedLinkMaster::Listener::Reset was called both when one and
489 // all URLs are deleted.
490 EXPECT_EQ(2, listener->reset_count());
493 class VisitCountingContext : public content::TestBrowserContext {
494 public:
495 VisitCountingContext()
496 : add_count_(0),
497 add_event_count_(0),
498 reset_event_count_(0),
499 new_table_count_(0) {}
501 void CountAddEvent(int by) {
502 add_count_ += by;
503 add_event_count_++;
506 void CountResetEvent() {
507 reset_event_count_++;
510 void CountNewTable() {
511 new_table_count_++;
514 int add_count() const { return add_count_; }
515 int add_event_count() const { return add_event_count_; }
516 int reset_event_count() const { return reset_event_count_; }
517 int new_table_count() const { return new_table_count_; }
519 private:
520 int add_count_;
521 int add_event_count_;
522 int reset_event_count_;
523 int new_table_count_;
526 // Stub out as little as possible, borrowing from RenderProcessHost.
527 class VisitRelayingRenderProcessHost : public MockRenderProcessHost {
528 public:
529 explicit VisitRelayingRenderProcessHost(
530 content::BrowserContext* browser_context)
531 : MockRenderProcessHost(browser_context), widgets_(0) {
532 content::NotificationService::current()->Notify(
533 content::NOTIFICATION_RENDERER_PROCESS_CREATED,
534 content::Source<RenderProcessHost>(this),
535 content::NotificationService::NoDetails());
537 ~VisitRelayingRenderProcessHost() override {
538 content::NotificationService::current()->Notify(
539 content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
540 content::Source<content::RenderProcessHost>(this),
541 content::NotificationService::NoDetails());
544 void WidgetRestored() override { widgets_++; }
545 void WidgetHidden() override { widgets_--; }
546 int VisibleWidgetCount() const override { return widgets_; }
548 bool Send(IPC::Message* msg) override {
549 VisitCountingContext* counting_context =
550 static_cast<VisitCountingContext*>(
551 GetBrowserContext());
553 if (msg->type() == ChromeViewMsg_VisitedLink_Add::ID) {
554 base::PickleIterator iter(*msg);
555 std::vector<uint64> fingerprints;
556 CHECK(IPC::ReadParam(msg, &iter, &fingerprints));
557 counting_context->CountAddEvent(fingerprints.size());
558 } else if (msg->type() == ChromeViewMsg_VisitedLink_Reset::ID) {
559 counting_context->CountResetEvent();
560 } else if (msg->type() == ChromeViewMsg_VisitedLink_NewTable::ID) {
561 counting_context->CountNewTable();
564 delete msg;
565 return true;
568 private:
569 int widgets_;
571 DISALLOW_COPY_AND_ASSIGN(VisitRelayingRenderProcessHost);
574 class VisitedLinkRenderProcessHostFactory
575 : public content::RenderProcessHostFactory {
576 public:
577 VisitedLinkRenderProcessHostFactory()
578 : content::RenderProcessHostFactory() {}
579 content::RenderProcessHost* CreateRenderProcessHost(
580 content::BrowserContext* browser_context,
581 content::SiteInstance* site_instance) const override {
582 return new VisitRelayingRenderProcessHost(browser_context);
585 private:
586 DISALLOW_COPY_AND_ASSIGN(VisitedLinkRenderProcessHostFactory);
589 class VisitedLinkEventsTest : public content::RenderViewHostTestHarness {
590 public:
591 void SetUp() override {
592 SetRenderProcessHostFactory(&vc_rph_factory_);
593 content::RenderViewHostTestHarness::SetUp();
596 content::BrowserContext* CreateBrowserContext() override {
597 VisitCountingContext* context = new VisitCountingContext();
598 master_.reset(new VisitedLinkMaster(context, &delegate_, true));
599 master_->Init();
600 return context;
603 VisitCountingContext* context() {
604 return static_cast<VisitCountingContext*>(browser_context());
607 VisitedLinkMaster* master() const {
608 return master_.get();
611 void WaitForCoalescense() {
612 // Let the timer fire.
614 // TODO(ajwong): This is horrid! What is the right synchronization method?
615 base::RunLoop run_loop;
616 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
617 FROM_HERE, run_loop.QuitClosure(),
618 base::TimeDelta::FromMilliseconds(110));
619 run_loop.Run();
622 protected:
623 VisitedLinkRenderProcessHostFactory vc_rph_factory_;
625 private:
626 TestVisitedLinkDelegate delegate_;
627 scoped_ptr<VisitedLinkMaster> master_;
630 TEST_F(VisitedLinkEventsTest, Coalescense) {
631 // add some URLs to master.
632 // Add a few URLs.
633 master()->AddURL(GURL("http://acidtests.org/"));
634 master()->AddURL(GURL("http://google.com/"));
635 master()->AddURL(GURL("http://chromium.org/"));
636 // Just for kicks, add a duplicate URL. This shouldn't increase the resulting
637 master()->AddURL(GURL("http://acidtests.org/"));
639 // Make sure that coalescing actually occurs. There should be no links or
640 // events received by the renderer.
641 EXPECT_EQ(0, context()->add_count());
642 EXPECT_EQ(0, context()->add_event_count());
644 WaitForCoalescense();
646 // We now should have 3 entries added in 1 event.
647 EXPECT_EQ(3, context()->add_count());
648 EXPECT_EQ(1, context()->add_event_count());
650 // Test whether the coalescing continues by adding a few more URLs.
651 master()->AddURL(GURL("http://google.com/chrome/"));
652 master()->AddURL(GURL("http://webkit.org/"));
653 master()->AddURL(GURL("http://acid3.acidtests.org/"));
655 WaitForCoalescense();
657 // We should have 6 entries added in 2 events.
658 EXPECT_EQ(6, context()->add_count());
659 EXPECT_EQ(2, context()->add_event_count());
661 // Test whether duplicate entries produce add events.
662 master()->AddURL(GURL("http://acidtests.org/"));
664 WaitForCoalescense();
666 // We should have no change in results.
667 EXPECT_EQ(6, context()->add_count());
668 EXPECT_EQ(2, context()->add_event_count());
670 // Ensure that the coalescing does not resume after resetting.
671 master()->AddURL(GURL("http://build.chromium.org/"));
672 master()->DeleteAllURLs();
674 WaitForCoalescense();
676 // We should have no change in results except for one new reset event.
677 EXPECT_EQ(6, context()->add_count());
678 EXPECT_EQ(2, context()->add_event_count());
679 EXPECT_EQ(1, context()->reset_event_count());
682 TEST_F(VisitedLinkEventsTest, Basics) {
683 RenderViewHostTester::For(rvh())->CreateTestRenderView(
684 base::string16(), MSG_ROUTING_NONE, MSG_ROUTING_NONE, -1, false);
686 // Add a few URLs.
687 master()->AddURL(GURL("http://acidtests.org/"));
688 master()->AddURL(GURL("http://google.com/"));
689 master()->AddURL(GURL("http://chromium.org/"));
691 WaitForCoalescense();
693 // We now should have 1 add event.
694 EXPECT_EQ(1, context()->add_event_count());
695 EXPECT_EQ(0, context()->reset_event_count());
697 master()->DeleteAllURLs();
699 WaitForCoalescense();
701 // We should have no change in add results, plus one new reset event.
702 EXPECT_EQ(1, context()->add_event_count());
703 EXPECT_EQ(1, context()->reset_event_count());
706 TEST_F(VisitedLinkEventsTest, TabVisibility) {
707 RenderViewHostTester::For(rvh())->CreateTestRenderView(
708 base::string16(), MSG_ROUTING_NONE, MSG_ROUTING_NONE, -1, false);
710 // Simulate tab becoming inactive.
711 RenderViewHostTester::For(rvh())->SimulateWasHidden();
713 // Add a few URLs.
714 master()->AddURL(GURL("http://acidtests.org/"));
715 master()->AddURL(GURL("http://google.com/"));
716 master()->AddURL(GURL("http://chromium.org/"));
718 WaitForCoalescense();
720 // We shouldn't have any events.
721 EXPECT_EQ(0, context()->add_event_count());
722 EXPECT_EQ(0, context()->reset_event_count());
724 // Simulate the tab becoming active.
725 RenderViewHostTester::For(rvh())->SimulateWasShown();
727 // We should now have 3 add events, still no reset events.
728 EXPECT_EQ(1, context()->add_event_count());
729 EXPECT_EQ(0, context()->reset_event_count());
731 // Deactivate the tab again.
732 RenderViewHostTester::For(rvh())->SimulateWasHidden();
734 // Add a bunch of URLs (over 50) to exhaust the link event buffer.
735 for (int i = 0; i < 100; i++)
736 master()->AddURL(TestURL(i));
738 WaitForCoalescense();
740 // Again, no change in events until tab is active.
741 EXPECT_EQ(1, context()->add_event_count());
742 EXPECT_EQ(0, context()->reset_event_count());
744 // Activate the tab.
745 RenderViewHostTester::For(rvh())->SimulateWasShown();
747 // We should have only one more reset event.
748 EXPECT_EQ(1, context()->add_event_count());
749 EXPECT_EQ(1, context()->reset_event_count());
752 // Tests that VisitedLink ignores renderer process creation notification for a
753 // different context.
754 TEST_F(VisitedLinkEventsTest, IgnoreRendererCreationFromDifferentContext) {
755 VisitCountingContext different_context;
756 VisitRelayingRenderProcessHost different_process_host(&different_context);
758 content::NotificationService::current()->Notify(
759 content::NOTIFICATION_RENDERER_PROCESS_CREATED,
760 content::Source<content::RenderProcessHost>(&different_process_host),
761 content::NotificationService::NoDetails());
762 WaitForCoalescense();
764 EXPECT_EQ(0, different_context.new_table_count());
767 } // namespace visitedlink