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.
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"
32 using content::BrowserThread
;
33 using content::MockRenderProcessHost
;
34 using content::RenderViewHostTester
;
36 namespace visitedlink
{
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|
49 return GURL(base::StringPrintf("%s%d", g_test_prefix
, i
));
52 std::vector
<VisitedLinkSlave
*> g_slaves
;
54 class TestVisitedLinkDelegate
: public VisitedLinkDelegate
{
56 void RebuildTable(const scoped_refptr
<URLEnumerator
>& enumerator
) override
;
58 void AddURLForRebuild(const GURL
& url
);
64 void TestVisitedLinkDelegate::RebuildTable(
65 const scoped_refptr
<URLEnumerator
>& enumerator
) {
66 for (URLs::const_iterator itr
= rebuild_urls_
.begin();
67 itr
!= rebuild_urls_
.end();
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
{
79 explicit TestURLIterator(const URLs
& urls
);
81 const GURL
& NextURL() override
;
82 bool HasNextURL() const override
;
85 URLs::const_iterator iterator_
;
86 URLs::const_iterator end_
;
89 TestURLIterator::TestURLIterator(const URLs
& urls
)
90 : iterator_(urls
.begin()),
94 const GURL
& TestURLIterator::NextURL() {
95 return *(iterator_
++);
98 bool TestURLIterator::HasNextURL() const {
99 return iterator_
!= end_
;
104 class TrackingVisitedLinkEventListener
: public VisitedLinkMaster::Listener
{
106 TrackingVisitedLinkEventListener()
110 void NewTable(base::SharedMemory
* table
) override
{
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_
++; }
128 int reset_count() const { return reset_count_
; }
129 int add_count() const { return add_count_
; }
136 class VisitedLinkTest
: public testing::Test
{
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(),
148 suppress_rebuild
, visited_file_
,
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.
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.
167 // Clean up after our caller, who may have left the database open.
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
);
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/"));
198 found
= slave
.IsVisited(GURL("http://unfound.site/"));
201 master_
->DebugValidate();
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
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
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
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;
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();
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.
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));
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.
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();
394 // This tests that the file is written correctly by reading it in using
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
));
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
433 base::RunLoop run_loop
;
434 master_
->set_rebuild_complete_task(run_loop
.QuitClosure());
437 // Test that all URLs were written to the database properly.
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());
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));
467 for (int i
= 0; i
< g_test_count
; i
++) {
468 master_
->AddURL(TestURL(i
));
469 ASSERT_EQ(i
+ 1, master_
->GetUsedCount());
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
{
493 VisitCountingContext()
496 reset_event_count_(0),
497 new_table_count_(0) {}
499 void CountAddEvent(int by
) {
504 void CountResetEvent() {
505 reset_event_count_
++;
508 void CountNewTable() {
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_
; }
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
{
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();
569 DISALLOW_COPY_AND_ASSIGN(VisitRelayingRenderProcessHost
);
572 class VisitedLinkRenderProcessHostFactory
573 : public content::RenderProcessHostFactory
{
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
);
584 DISALLOW_COPY_AND_ASSIGN(VisitedLinkRenderProcessHostFactory
);
587 class VisitedLinkEventsTest
: public content::RenderViewHostTestHarness
{
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));
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(
616 run_loop
.QuitClosure(),
617 base::TimeDelta::FromMilliseconds(110));
622 VisitedLinkRenderProcessHostFactory vc_rph_factory_
;
625 TestVisitedLinkDelegate delegate_
;
626 scoped_ptr
<VisitedLinkMaster
> master_
;
629 TEST_F(VisitedLinkEventsTest
, Coalescense
) {
630 // add some URLs to master.
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);
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();
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());
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