Add an UMA stat to be able to see if the User pods are show on start screen,
[chromium-blink-merge.git] / components / visitedlink / test / visitedlink_unittest.cc
blob4ce2c10795af50c0431200568463792d0ef340b2
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/memory/shared_memory.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/process/process_handle.h"
13 #include "base/run_loop.h"
14 #include "base/strings/string_util.h"
15 #include "base/time/time.h"
16 #include "components/visitedlink/browser/visitedlink_delegate.h"
17 #include "components/visitedlink/browser/visitedlink_event_listener.h"
18 #include "components/visitedlink/browser/visitedlink_master.h"
19 #include "components/visitedlink/common/visitedlink_messages.h"
20 #include "components/visitedlink/renderer/visitedlink_slave.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/browser/notification_service.h"
23 #include "content/public/browser/notification_types.h"
24 #include "content/public/test/mock_render_process_host.h"
25 #include "content/public/test/test_browser_context.h"
26 #include "content/public/test/test_browser_thread_bundle.h"
27 #include "content/public/test/test_renderer_host.h"
28 #include "content/public/test/test_utils.h"
29 #include "testing/gtest/include/gtest/gtest.h"
30 #include "url/gurl.h"
32 using content::BrowserThread;
33 using content::MockRenderProcessHost;
34 using content::RenderViewHostTester;
36 namespace visitedlink {
38 namespace {
40 typedef std::vector<GURL> URLs;
42 // a nice long URL that we can append numbers to to get new URLs
43 const char g_test_prefix[] =
44 "http://www.google.com/products/foo/index.html?id=45028640526508376&seq=";
45 const int g_test_count = 1000;
47 // Returns a test URL for index |i|
48 GURL TestURL(int i) {
49 return GURL(base::StringPrintf("%s%d", g_test_prefix, i));
52 std::vector<VisitedLinkSlave*> g_slaves;
54 class TestVisitedLinkDelegate : public VisitedLinkDelegate {
55 public:
56 void RebuildTable(const scoped_refptr<URLEnumerator>& enumerator) override;
58 void AddURLForRebuild(const GURL& url);
60 private:
61 URLs rebuild_urls_;
64 void TestVisitedLinkDelegate::RebuildTable(
65 const scoped_refptr<URLEnumerator>& enumerator) {
66 for (URLs::const_iterator itr = rebuild_urls_.begin();
67 itr != rebuild_urls_.end();
68 ++itr)
69 enumerator->OnURL(*itr);
70 enumerator->OnComplete(true);
73 void TestVisitedLinkDelegate::AddURLForRebuild(const GURL& url) {
74 rebuild_urls_.push_back(url);
77 class TestURLIterator : public VisitedLinkMaster::URLIterator {
78 public:
79 explicit TestURLIterator(const URLs& urls);
81 const GURL& NextURL() override;
82 bool HasNextURL() const override;
84 private:
85 URLs::const_iterator iterator_;
86 URLs::const_iterator end_;
89 TestURLIterator::TestURLIterator(const URLs& urls)
90 : iterator_(urls.begin()),
91 end_(urls.end()) {
94 const GURL& TestURLIterator::NextURL() {
95 return *(iterator_++);
98 bool TestURLIterator::HasNextURL() const {
99 return iterator_ != end_;
102 } // namespace
104 class TrackingVisitedLinkEventListener : public VisitedLinkMaster::Listener {
105 public:
106 TrackingVisitedLinkEventListener()
107 : reset_count_(0),
108 add_count_(0) {}
110 void NewTable(base::SharedMemory* table) override {
111 if (table) {
112 for (std::vector<VisitedLinkSlave>::size_type i = 0;
113 i < g_slaves.size(); i++) {
114 base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle();
115 table->ShareToProcess(base::GetCurrentProcessHandle(), &new_handle);
116 g_slaves[i]->OnUpdateVisitedLinks(new_handle);
120 void Add(VisitedLinkCommon::Fingerprint) override { add_count_++; }
121 void Reset() override { reset_count_++; }
123 void SetUp() {
124 reset_count_ = 0;
125 add_count_ = 0;
128 int reset_count() const { return reset_count_; }
129 int add_count() const { return add_count_; }
131 private:
132 int reset_count_;
133 int add_count_;
136 class VisitedLinkTest : public testing::Test {
137 protected:
138 // Initializes the visited link objects. Pass in the size that you want a
139 // freshly created table to be. 0 means use the default.
141 // |suppress_rebuild| is set when we're not testing rebuilding, see
142 // the VisitedLinkMaster constructor.
143 bool InitVisited(int initial_size, bool suppress_rebuild) {
144 // Initialize the visited link system.
145 master_.reset(new VisitedLinkMaster(new TrackingVisitedLinkEventListener(),
146 &delegate_,
147 true,
148 suppress_rebuild, visited_file_,
149 initial_size));
150 return master_->Init();
153 // May be called multiple times (some tests will do this to clear things,
154 // and TearDown will do this to make sure eveything is shiny before quitting.
155 void ClearDB() {
156 if (master_.get())
157 master_.reset(NULL);
159 // Wait for all pending file I/O to be completed.
160 content::RunAllBlockingPoolTasksUntilIdle();
163 // Loads the database from disk and makes sure that the same URLs are present
164 // as were generated by TestIO_Create(). This also checks the URLs with a
165 // slave to make sure it reads the data properly.
166 void Reload() {
167 // Clean up after our caller, who may have left the database open.
168 ClearDB();
170 ASSERT_TRUE(InitVisited(0, true));
171 master_->DebugValidate();
173 // check that the table has the proper number of entries
174 int used_count = master_->GetUsedCount();
175 ASSERT_EQ(used_count, g_test_count);
177 // Create a slave database.
178 VisitedLinkSlave slave;
179 base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle();
180 master_->shared_memory()->ShareToProcess(
181 base::GetCurrentProcessHandle(), &new_handle);
182 slave.OnUpdateVisitedLinks(new_handle);
183 g_slaves.push_back(&slave);
185 bool found;
186 for (int i = 0; i < g_test_count; i++) {
187 GURL cur = TestURL(i);
188 found = master_->IsVisited(cur);
189 EXPECT_TRUE(found) << "URL " << i << "not found in master.";
191 found = slave.IsVisited(cur);
192 EXPECT_TRUE(found) << "URL " << i << "not found in slave.";
195 // test some random URL so we know that it returns false sometimes too
196 found = master_->IsVisited(GURL("http://unfound.site/"));
197 ASSERT_FALSE(found);
198 found = slave.IsVisited(GURL("http://unfound.site/"));
199 ASSERT_FALSE(found);
201 master_->DebugValidate();
203 g_slaves.clear();
206 // testing::Test
207 void SetUp() override {
208 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
210 history_dir_ = temp_dir_.path().AppendASCII("VisitedLinkTest");
211 ASSERT_TRUE(base::CreateDirectory(history_dir_));
213 visited_file_ = history_dir_.Append(FILE_PATH_LITERAL("VisitedLinks"));
216 void TearDown() override { ClearDB(); }
218 base::ScopedTempDir temp_dir_;
220 // Filenames for the services;
221 base::FilePath history_dir_;
222 base::FilePath visited_file_;
224 scoped_ptr<VisitedLinkMaster> master_;
225 TestVisitedLinkDelegate delegate_;
226 content::TestBrowserThreadBundle thread_bundle_;
229 // This test creates and reads some databases to make sure the data is
230 // preserved throughout those operations.
231 TEST_F(VisitedLinkTest, DatabaseIO) {
232 ASSERT_TRUE(InitVisited(0, true));
234 for (int i = 0; i < g_test_count; i++)
235 master_->AddURL(TestURL(i));
237 // Test that the database was written properly
238 Reload();
241 // Checks that we can delete things properly when there are collisions.
242 TEST_F(VisitedLinkTest, Delete) {
243 static const int32 kInitialSize = 17;
244 ASSERT_TRUE(InitVisited(kInitialSize, true));
246 // Add a cluster from 14-17 wrapping around to 0. These will all hash to the
247 // same value.
248 const VisitedLinkCommon::Fingerprint kFingerprint0 = kInitialSize * 0 + 14;
249 const VisitedLinkCommon::Fingerprint kFingerprint1 = kInitialSize * 1 + 14;
250 const VisitedLinkCommon::Fingerprint kFingerprint2 = kInitialSize * 2 + 14;
251 const VisitedLinkCommon::Fingerprint kFingerprint3 = kInitialSize * 3 + 14;
252 const VisitedLinkCommon::Fingerprint kFingerprint4 = kInitialSize * 4 + 14;
253 master_->AddFingerprint(kFingerprint0, false); // @14
254 master_->AddFingerprint(kFingerprint1, false); // @15
255 master_->AddFingerprint(kFingerprint2, false); // @16
256 master_->AddFingerprint(kFingerprint3, false); // @0
257 master_->AddFingerprint(kFingerprint4, false); // @1
259 // Deleting 14 should move the next value up one slot (we do not specify an
260 // order).
261 EXPECT_EQ(kFingerprint3, master_->hash_table_[0]);
262 master_->DeleteFingerprint(kFingerprint3, false);
263 VisitedLinkCommon::Fingerprint zero_fingerprint = 0;
264 EXPECT_EQ(zero_fingerprint, master_->hash_table_[1]);
265 EXPECT_NE(zero_fingerprint, master_->hash_table_[0]);
267 // Deleting the other four should leave the table empty.
268 master_->DeleteFingerprint(kFingerprint0, false);
269 master_->DeleteFingerprint(kFingerprint1, false);
270 master_->DeleteFingerprint(kFingerprint2, false);
271 master_->DeleteFingerprint(kFingerprint4, false);
273 EXPECT_EQ(0, master_->used_items_);
274 for (int i = 0; i < kInitialSize; i++)
275 EXPECT_EQ(zero_fingerprint, master_->hash_table_[i]) <<
276 "Hash table has values in it.";
279 // When we delete more than kBigDeleteThreshold we trigger different behavior
280 // where the entire file is rewritten.
281 TEST_F(VisitedLinkTest, BigDelete) {
282 ASSERT_TRUE(InitVisited(16381, true));
284 // Add the base set of URLs that won't be deleted.
285 // Reload() will test for these.
286 for (int32 i = 0; i < g_test_count; i++)
287 master_->AddURL(TestURL(i));
289 // Add more URLs than necessary to trigger this case.
290 const int kTestDeleteCount = VisitedLinkMaster::kBigDeleteThreshold + 2;
291 URLs urls_to_delete;
292 for (int32 i = g_test_count; i < g_test_count + kTestDeleteCount; i++) {
293 GURL url(TestURL(i));
294 master_->AddURL(url);
295 urls_to_delete.push_back(url);
298 TestURLIterator iterator(urls_to_delete);
299 master_->DeleteURLs(&iterator);
300 master_->DebugValidate();
302 Reload();
305 TEST_F(VisitedLinkTest, DeleteAll) {
306 ASSERT_TRUE(InitVisited(0, true));
309 VisitedLinkSlave slave;
310 base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle();
311 master_->shared_memory()->ShareToProcess(
312 base::GetCurrentProcessHandle(), &new_handle);
313 slave.OnUpdateVisitedLinks(new_handle);
314 g_slaves.push_back(&slave);
316 // Add the test URLs.
317 for (int i = 0; i < g_test_count; i++) {
318 master_->AddURL(TestURL(i));
319 ASSERT_EQ(i + 1, master_->GetUsedCount());
321 master_->DebugValidate();
323 // Make sure the slave picked up the adds.
324 for (int i = 0; i < g_test_count; i++)
325 EXPECT_TRUE(slave.IsVisited(TestURL(i)));
327 // Clear the table and make sure the slave picked it up.
328 master_->DeleteAllURLs();
329 EXPECT_EQ(0, master_->GetUsedCount());
330 for (int i = 0; i < g_test_count; i++) {
331 EXPECT_FALSE(master_->IsVisited(TestURL(i)));
332 EXPECT_FALSE(slave.IsVisited(TestURL(i)));
335 // Close the database.
336 g_slaves.clear();
337 ClearDB();
340 // Reopen and validate.
341 ASSERT_TRUE(InitVisited(0, true));
342 master_->DebugValidate();
343 EXPECT_EQ(0, master_->GetUsedCount());
344 for (int i = 0; i < g_test_count; i++)
345 EXPECT_FALSE(master_->IsVisited(TestURL(i)));
348 // This tests that the master correctly resizes its tables when it gets too
349 // full, notifies its slaves of the change, and updates the disk.
350 TEST_F(VisitedLinkTest, Resizing) {
351 // Create a very small database.
352 const int32 initial_size = 17;
353 ASSERT_TRUE(InitVisited(initial_size, true));
355 // ...and a slave
356 VisitedLinkSlave slave;
357 base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle();
358 master_->shared_memory()->ShareToProcess(
359 base::GetCurrentProcessHandle(), &new_handle);
360 slave.OnUpdateVisitedLinks(new_handle);
361 g_slaves.push_back(&slave);
363 int32 used_count = master_->GetUsedCount();
364 ASSERT_EQ(used_count, 0);
366 for (int i = 0; i < g_test_count; i++) {
367 master_->AddURL(TestURL(i));
368 used_count = master_->GetUsedCount();
369 ASSERT_EQ(i + 1, used_count);
372 // Verify that the table got resized sufficiently.
373 int32 table_size;
374 VisitedLinkCommon::Fingerprint* table;
375 master_->GetUsageStatistics(&table_size, &table);
376 used_count = master_->GetUsedCount();
377 ASSERT_GT(table_size, used_count);
378 ASSERT_EQ(used_count, g_test_count) <<
379 "table count doesn't match the # of things we added";
381 // Verify that the slave got the resize message and has the same
382 // table information.
383 int32 child_table_size;
384 VisitedLinkCommon::Fingerprint* child_table;
385 slave.GetUsageStatistics(&child_table_size, &child_table);
386 ASSERT_EQ(table_size, child_table_size);
387 for (int32 i = 0; i < table_size; i++) {
388 ASSERT_EQ(table[i], child_table[i]);
391 master_->DebugValidate();
392 g_slaves.clear();
394 // This tests that the file is written correctly by reading it in using
395 // a new database.
396 Reload();
399 // Tests that if the database doesn't exist, it will be rebuilt from history.
400 TEST_F(VisitedLinkTest, Rebuild) {
401 // Add half of our URLs to history. This needs to be done before we
402 // initialize the visited link DB.
403 int history_count = g_test_count / 2;
404 for (int i = 0; i < history_count; i++)
405 delegate_.AddURLForRebuild(TestURL(i));
407 // Initialize the visited link DB. Since the visited links file doesn't exist
408 // and we don't suppress history rebuilding, this will load from history.
409 ASSERT_TRUE(InitVisited(0, false));
411 // While the table is rebuilding, add the rest of the URLs to the visited
412 // link system. This isn't guaranteed to happen during the rebuild, so we
413 // can't be 100% sure we're testing the right thing, but in practice is.
414 // All the adds above will generally take some time queuing up on the
415 // history thread, and it will take a while to catch up to actually
416 // processing the rebuild that has queued behind it. We will generally
417 // finish adding all of the URLs before it has even found the first URL.
418 for (int i = history_count; i < g_test_count; i++)
419 master_->AddURL(TestURL(i));
421 // Add one more and then delete it.
422 master_->AddURL(TestURL(g_test_count));
423 URLs urls_to_delete;
424 urls_to_delete.push_back(TestURL(g_test_count));
425 TestURLIterator iterator(urls_to_delete);
426 master_->DeleteURLs(&iterator);
428 // Wait for the rebuild to complete. The task will terminate the message
429 // loop when the rebuild is done. There's no chance that the rebuild will
430 // complete before we set the task because the rebuild completion message
431 // is posted to the message loop; until we Run() it, rebuild can not
432 // complete.
433 base::RunLoop run_loop;
434 master_->set_rebuild_complete_task(run_loop.QuitClosure());
435 run_loop.Run();
437 // Test that all URLs were written to the database properly.
438 Reload();
440 // Make sure the extra one was *not* written (Reload won't test this).
441 EXPECT_FALSE(master_->IsVisited(TestURL(g_test_count)));
444 // Test that importing a large number of URLs will work
445 TEST_F(VisitedLinkTest, BigImport) {
446 ASSERT_TRUE(InitVisited(0, false));
448 // Before the table rebuilds, add a large number of URLs
449 int total_count = VisitedLinkMaster::kDefaultTableSize + 10;
450 for (int i = 0; i < total_count; i++)
451 master_->AddURL(TestURL(i));
453 // Wait for the rebuild to complete.
454 base::RunLoop run_loop;
455 master_->set_rebuild_complete_task(run_loop.QuitClosure());
456 run_loop.Run();
458 // Ensure that the right number of URLs are present
459 int used_count = master_->GetUsedCount();
460 ASSERT_EQ(used_count, total_count);
463 TEST_F(VisitedLinkTest, Listener) {
464 ASSERT_TRUE(InitVisited(0, true));
466 // Add test URLs.
467 for (int i = 0; i < g_test_count; i++) {
468 master_->AddURL(TestURL(i));
469 ASSERT_EQ(i + 1, master_->GetUsedCount());
472 // Delete an URL.
473 URLs urls_to_delete;
474 urls_to_delete.push_back(TestURL(0));
475 TestURLIterator iterator(urls_to_delete);
476 master_->DeleteURLs(&iterator);
478 // ... and all of the remaining ones.
479 master_->DeleteAllURLs();
481 TrackingVisitedLinkEventListener* listener =
482 static_cast<TrackingVisitedLinkEventListener*>(master_->GetListener());
484 // Verify that VisitedLinkMaster::Listener::Add was called for each added URL.
485 EXPECT_EQ(g_test_count, listener->add_count());
486 // Verify that VisitedLinkMaster::Listener::Reset was called both when one and
487 // all URLs are deleted.
488 EXPECT_EQ(2, listener->reset_count());
491 class VisitCountingContext : public content::TestBrowserContext {
492 public:
493 VisitCountingContext()
494 : add_count_(0),
495 add_event_count_(0),
496 reset_event_count_(0),
497 new_table_count_(0) {}
499 void CountAddEvent(int by) {
500 add_count_ += by;
501 add_event_count_++;
504 void CountResetEvent() {
505 reset_event_count_++;
508 void CountNewTable() {
509 new_table_count_++;
512 int add_count() const { return add_count_; }
513 int add_event_count() const { return add_event_count_; }
514 int reset_event_count() const { return reset_event_count_; }
515 int new_table_count() const { return new_table_count_; }
517 private:
518 int add_count_;
519 int add_event_count_;
520 int reset_event_count_;
521 int new_table_count_;
524 // Stub out as little as possible, borrowing from RenderProcessHost.
525 class VisitRelayingRenderProcessHost : public MockRenderProcessHost {
526 public:
527 explicit VisitRelayingRenderProcessHost(
528 content::BrowserContext* browser_context)
529 : MockRenderProcessHost(browser_context), widgets_(0) {
530 content::NotificationService::current()->Notify(
531 content::NOTIFICATION_RENDERER_PROCESS_CREATED,
532 content::Source<RenderProcessHost>(this),
533 content::NotificationService::NoDetails());
535 ~VisitRelayingRenderProcessHost() override {
536 content::NotificationService::current()->Notify(
537 content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
538 content::Source<content::RenderProcessHost>(this),
539 content::NotificationService::NoDetails());
542 void WidgetRestored() override { widgets_++; }
543 void WidgetHidden() override { widgets_--; }
544 int VisibleWidgetCount() const override { return widgets_; }
546 bool Send(IPC::Message* msg) override {
547 VisitCountingContext* counting_context =
548 static_cast<VisitCountingContext*>(
549 GetBrowserContext());
551 if (msg->type() == ChromeViewMsg_VisitedLink_Add::ID) {
552 PickleIterator iter(*msg);
553 std::vector<uint64> fingerprints;
554 CHECK(IPC::ReadParam(msg, &iter, &fingerprints));
555 counting_context->CountAddEvent(fingerprints.size());
556 } else if (msg->type() == ChromeViewMsg_VisitedLink_Reset::ID) {
557 counting_context->CountResetEvent();
558 } else if (msg->type() == ChromeViewMsg_VisitedLink_NewTable::ID) {
559 counting_context->CountNewTable();
562 delete msg;
563 return true;
566 private:
567 int widgets_;
569 DISALLOW_COPY_AND_ASSIGN(VisitRelayingRenderProcessHost);
572 class VisitedLinkRenderProcessHostFactory
573 : public content::RenderProcessHostFactory {
574 public:
575 VisitedLinkRenderProcessHostFactory()
576 : content::RenderProcessHostFactory() {}
577 content::RenderProcessHost* CreateRenderProcessHost(
578 content::BrowserContext* browser_context,
579 content::SiteInstance* site_instance) const override {
580 return new VisitRelayingRenderProcessHost(browser_context);
583 private:
584 DISALLOW_COPY_AND_ASSIGN(VisitedLinkRenderProcessHostFactory);
587 class VisitedLinkEventsTest : public content::RenderViewHostTestHarness {
588 public:
589 void SetUp() override {
590 SetRenderProcessHostFactory(&vc_rph_factory_);
591 content::RenderViewHostTestHarness::SetUp();
594 content::BrowserContext* CreateBrowserContext() override {
595 VisitCountingContext* context = new VisitCountingContext();
596 master_.reset(new VisitedLinkMaster(context, &delegate_, true));
597 master_->Init();
598 return context;
601 VisitCountingContext* context() {
602 return static_cast<VisitCountingContext*>(browser_context());
605 VisitedLinkMaster* master() const {
606 return master_.get();
609 void WaitForCoalescense() {
610 // Let the timer fire.
612 // TODO(ajwong): This is horrid! What is the right synchronization method?
613 base::RunLoop run_loop;
614 base::MessageLoop::current()->PostDelayedTask(
615 FROM_HERE,
616 run_loop.QuitClosure(),
617 base::TimeDelta::FromMilliseconds(110));
618 run_loop.Run();
621 protected:
622 VisitedLinkRenderProcessHostFactory vc_rph_factory_;
624 private:
625 TestVisitedLinkDelegate delegate_;
626 scoped_ptr<VisitedLinkMaster> master_;
629 TEST_F(VisitedLinkEventsTest, Coalescense) {
630 // add some URLs to master.
631 // Add a few URLs.
632 master()->AddURL(GURL("http://acidtests.org/"));
633 master()->AddURL(GURL("http://google.com/"));
634 master()->AddURL(GURL("http://chromium.org/"));
635 // Just for kicks, add a duplicate URL. This shouldn't increase the resulting
636 master()->AddURL(GURL("http://acidtests.org/"));
638 // Make sure that coalescing actually occurs. There should be no links or
639 // events received by the renderer.
640 EXPECT_EQ(0, context()->add_count());
641 EXPECT_EQ(0, context()->add_event_count());
643 WaitForCoalescense();
645 // We now should have 3 entries added in 1 event.
646 EXPECT_EQ(3, context()->add_count());
647 EXPECT_EQ(1, context()->add_event_count());
649 // Test whether the coalescing continues by adding a few more URLs.
650 master()->AddURL(GURL("http://google.com/chrome/"));
651 master()->AddURL(GURL("http://webkit.org/"));
652 master()->AddURL(GURL("http://acid3.acidtests.org/"));
654 WaitForCoalescense();
656 // We should have 6 entries added in 2 events.
657 EXPECT_EQ(6, context()->add_count());
658 EXPECT_EQ(2, context()->add_event_count());
660 // Test whether duplicate entries produce add events.
661 master()->AddURL(GURL("http://acidtests.org/"));
663 WaitForCoalescense();
665 // We should have no change in results.
666 EXPECT_EQ(6, context()->add_count());
667 EXPECT_EQ(2, context()->add_event_count());
669 // Ensure that the coalescing does not resume after resetting.
670 master()->AddURL(GURL("http://build.chromium.org/"));
671 master()->DeleteAllURLs();
673 WaitForCoalescense();
675 // We should have no change in results except for one new reset event.
676 EXPECT_EQ(6, context()->add_count());
677 EXPECT_EQ(2, context()->add_event_count());
678 EXPECT_EQ(1, context()->reset_event_count());
681 TEST_F(VisitedLinkEventsTest, Basics) {
682 RenderViewHostTester::For(rvh())->CreateRenderView(
683 base::string16(), MSG_ROUTING_NONE, MSG_ROUTING_NONE, -1, false);
685 // Add a few URLs.
686 master()->AddURL(GURL("http://acidtests.org/"));
687 master()->AddURL(GURL("http://google.com/"));
688 master()->AddURL(GURL("http://chromium.org/"));
690 WaitForCoalescense();
692 // We now should have 1 add event.
693 EXPECT_EQ(1, context()->add_event_count());
694 EXPECT_EQ(0, context()->reset_event_count());
696 master()->DeleteAllURLs();
698 WaitForCoalescense();
700 // We should have no change in add results, plus one new reset event.
701 EXPECT_EQ(1, context()->add_event_count());
702 EXPECT_EQ(1, context()->reset_event_count());
705 TEST_F(VisitedLinkEventsTest, TabVisibility) {
706 RenderViewHostTester::For(rvh())->CreateRenderView(
707 base::string16(), MSG_ROUTING_NONE, MSG_ROUTING_NONE, -1, false);
709 // Simulate tab becoming inactive.
710 RenderViewHostTester::For(rvh())->SimulateWasHidden();
712 // Add a few URLs.
713 master()->AddURL(GURL("http://acidtests.org/"));
714 master()->AddURL(GURL("http://google.com/"));
715 master()->AddURL(GURL("http://chromium.org/"));
717 WaitForCoalescense();
719 // We shouldn't have any events.
720 EXPECT_EQ(0, context()->add_event_count());
721 EXPECT_EQ(0, context()->reset_event_count());
723 // Simulate the tab becoming active.
724 RenderViewHostTester::For(rvh())->SimulateWasShown();
726 // We should now have 3 add events, still no reset events.
727 EXPECT_EQ(1, context()->add_event_count());
728 EXPECT_EQ(0, context()->reset_event_count());
730 // Deactivate the tab again.
731 RenderViewHostTester::For(rvh())->SimulateWasHidden();
733 // Add a bunch of URLs (over 50) to exhaust the link event buffer.
734 for (int i = 0; i < 100; i++)
735 master()->AddURL(TestURL(i));
737 WaitForCoalescense();
739 // Again, no change in events until tab is active.
740 EXPECT_EQ(1, context()->add_event_count());
741 EXPECT_EQ(0, context()->reset_event_count());
743 // Activate the tab.
744 RenderViewHostTester::For(rvh())->SimulateWasShown();
746 // We should have only one more reset event.
747 EXPECT_EQ(1, context()->add_event_count());
748 EXPECT_EQ(1, context()->reset_event_count());
751 // Tests that VisitedLink ignores renderer process creation notification for a
752 // different context.
753 TEST_F(VisitedLinkEventsTest, IgnoreRendererCreationFromDifferentContext) {
754 VisitCountingContext different_context;
755 VisitRelayingRenderProcessHost different_process_host(&different_context);
757 content::NotificationService::current()->Notify(
758 content::NOTIFICATION_RENDERER_PROCESS_CREATED,
759 content::Source<content::RenderProcessHost>(&different_process_host),
760 content::NotificationService::NoDetails());
761 WaitForCoalescense();
763 EXPECT_EQ(0, different_context.new_table_count());
766 } // namespace visitedlink