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/file_util.h"
10 #include "base/memory/shared_memory.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/path_service.h"
13 #include "base/process/process_handle.h"
14 #include "base/run_loop.h"
15 #include "base/strings/string_util.h"
16 #include "base/time/time.h"
17 #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"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/notification_service.h"
24 #include "content/public/browser/notification_types.h"
25 #include "content/public/test/mock_render_process_host.h"
26 #include "content/public/test/test_browser_context.h"
27 #include "content/public/test/test_browser_thread_bundle.h"
28 #include "content/public/test/test_renderer_host.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 virtual void RebuildTable(
57 const scoped_refptr
<URLEnumerator
>& enumerator
) OVERRIDE
;
59 void AddURLForRebuild(const GURL
& url
);
66 void TestVisitedLinkDelegate::RebuildTable(
67 const scoped_refptr
<URLEnumerator
>& enumerator
) {
68 for (URLs::const_iterator itr
= rebuild_urls_
.begin();
69 itr
!= rebuild_urls_
.end();
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
{
81 explicit TestURLIterator(const URLs
& urls
);
83 virtual const GURL
& NextURL() OVERRIDE
;
84 virtual bool HasNextURL() const OVERRIDE
;
87 URLs::const_iterator iterator_
;
88 URLs::const_iterator end_
;
91 TestURLIterator::TestURLIterator(const URLs
& urls
)
92 : iterator_(urls
.begin()),
96 const GURL
& TestURLIterator::NextURL() {
97 return *(iterator_
++);
100 bool TestURLIterator::HasNextURL() const {
101 return iterator_
!= end_
;
106 class TrackingVisitedLinkEventListener
: public VisitedLinkMaster::Listener
{
108 TrackingVisitedLinkEventListener()
112 virtual void NewTable(base::SharedMemory
* table
) OVERRIDE
{
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 virtual void Add(VisitedLinkCommon::Fingerprint
) OVERRIDE
{ add_count_
++; }
123 virtual void Reset() OVERRIDE
{ reset_count_
++; }
130 int reset_count() const { return reset_count_
; }
131 int add_count() const { return add_count_
; }
138 class VisitedLinkTest
: public testing::Test
{
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(),
150 suppress_rebuild
, visited_file_
,
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.
161 // Wait for all pending file I/O to be completed.
162 BrowserThread::GetBlockingPool()->FlushForTesting();
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.
169 // Clean up after our caller, who may have left the database open.
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
);
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/"));
200 found
= slave
.IsVisited(GURL("http://unfound.site/"));
203 master_
->DebugValidate();
209 virtual void SetUp() {
210 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
212 history_dir_
= temp_dir_
.path().AppendASCII("VisitedLinkTest");
213 ASSERT_TRUE(file_util::CreateDirectory(history_dir_
));
215 visited_file_
= history_dir_
.Append(FILE_PATH_LITERAL("VisitedLinks"));
218 virtual void TearDown() {
222 base::ScopedTempDir temp_dir_
;
224 // Filenames for the services;
225 base::FilePath history_dir_
;
226 base::FilePath visited_file_
;
228 scoped_ptr
<VisitedLinkMaster
> master_
;
229 TestVisitedLinkDelegate delegate_
;
230 content::TestBrowserThreadBundle thread_bundle_
;
233 // This test creates and reads some databases to make sure the data is
234 // preserved throughout those operations.
235 TEST_F(VisitedLinkTest
, DatabaseIO
) {
236 ASSERT_TRUE(InitVisited(0, true));
238 for (int i
= 0; i
< g_test_count
; i
++)
239 master_
->AddURL(TestURL(i
));
241 // Test that the database was written properly
245 // Checks that we can delete things properly when there are collisions.
246 TEST_F(VisitedLinkTest
, Delete
) {
247 static const int32 kInitialSize
= 17;
248 ASSERT_TRUE(InitVisited(kInitialSize
, true));
250 // Add a cluster from 14-17 wrapping around to 0. These will all hash to the
252 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;
257 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
263 // Deleting 14 should move the next value up one slot (we do not specify an
265 EXPECT_EQ(kFingerprint3
, master_
->hash_table_
[0]);
266 master_
->DeleteFingerprint(kFingerprint3
, false);
267 VisitedLinkCommon::Fingerprint zero_fingerprint
= 0;
268 EXPECT_EQ(zero_fingerprint
, master_
->hash_table_
[1]);
269 EXPECT_NE(zero_fingerprint
, master_
->hash_table_
[0]);
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);
277 EXPECT_EQ(0, master_
->used_items_
);
278 for (int i
= 0; i
< kInitialSize
; i
++)
279 EXPECT_EQ(zero_fingerprint
, master_
->hash_table_
[i
]) <<
280 "Hash table has values in it.";
283 // When we delete more than kBigDeleteThreshold we trigger different behavior
284 // where the entire file is rewritten.
285 TEST_F(VisitedLinkTest
, BigDelete
) {
286 ASSERT_TRUE(InitVisited(16381, true));
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
));
293 // Add more URLs than necessary to trigger this case.
294 const int kTestDeleteCount
= VisitedLinkMaster::kBigDeleteThreshold
+ 2;
296 for (int32 i
= g_test_count
; i
< g_test_count
+ kTestDeleteCount
; i
++) {
297 GURL
url(TestURL(i
));
298 master_
->AddURL(url
);
299 urls_to_delete
.push_back(url
);
302 TestURLIterator
iterator(urls_to_delete
);
303 master_
->DeleteURLs(&iterator
);
304 master_
->DebugValidate();
309 TEST_F(VisitedLinkTest
, DeleteAll
) {
310 ASSERT_TRUE(InitVisited(0, true));
313 VisitedLinkSlave slave
;
314 base::SharedMemoryHandle new_handle
= base::SharedMemory::NULLHandle();
315 master_
->shared_memory()->ShareToProcess(
316 base::GetCurrentProcessHandle(), &new_handle
);
317 slave
.OnUpdateVisitedLinks(new_handle
);
318 g_slaves
.push_back(&slave
);
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());
325 master_
->DebugValidate();
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
)));
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
)));
339 // Close the database.
344 // Reopen and validate.
345 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
)));
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.
354 TEST_F(VisitedLinkTest
, Resizing
) {
355 // Create a very small database.
356 const int32 initial_size
= 17;
357 ASSERT_TRUE(InitVisited(initial_size
, true));
360 VisitedLinkSlave slave
;
361 base::SharedMemoryHandle new_handle
= base::SharedMemory::NULLHandle();
362 master_
->shared_memory()->ShareToProcess(
363 base::GetCurrentProcessHandle(), &new_handle
);
364 slave
.OnUpdateVisitedLinks(new_handle
);
365 g_slaves
.push_back(&slave
);
367 int32 used_count
= master_
->GetUsedCount();
368 ASSERT_EQ(used_count
, 0);
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
);
376 // Verify that the table got resized sufficiently.
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";
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
]);
395 master_
->DebugValidate();
398 // This tests that the file is written correctly by reading it in using
403 // Tests that if the database doesn't exist, it will be rebuilt from history.
404 TEST_F(VisitedLinkTest
, Rebuild
) {
405 // 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
++)
409 delegate_
.AddURLForRebuild(TestURL(i
));
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));
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
));
425 // Add one more and then delete it.
426 master_
->AddURL(TestURL(g_test_count
));
428 urls_to_delete
.push_back(TestURL(g_test_count
));
429 TestURLIterator
iterator(urls_to_delete
);
430 master_
->DeleteURLs(&iterator
);
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
437 base::RunLoop run_loop
;
438 master_
->set_rebuild_complete_task(run_loop
.QuitClosure());
441 // Test that all URLs were written to the database properly.
444 // Make sure the extra one was *not* written (Reload won't test this).
445 EXPECT_FALSE(master_
->IsVisited(TestURL(g_test_count
)));
448 // Test that importing a large number of URLs will work
449 TEST_F(VisitedLinkTest
, BigImport
) {
450 ASSERT_TRUE(InitVisited(0, false));
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
));
457 // Wait for the rebuild to complete.
458 base::RunLoop run_loop
;
459 master_
->set_rebuild_complete_task(run_loop
.QuitClosure());
462 // Ensure that the right number of URLs are present
463 int used_count
= master_
->GetUsedCount();
464 ASSERT_EQ(used_count
, total_count
);
467 TEST_F(VisitedLinkTest
, Listener
) {
468 ASSERT_TRUE(InitVisited(0, true));
471 for (int i
= 0; i
< g_test_count
; i
++) {
472 master_
->AddURL(TestURL(i
));
473 ASSERT_EQ(i
+ 1, master_
->GetUsedCount());
478 urls_to_delete
.push_back(TestURL(0));
479 TestURLIterator
iterator(urls_to_delete
);
480 master_
->DeleteURLs(&iterator
);
482 // ... and all of the remaining ones.
483 master_
->DeleteAllURLs();
485 TrackingVisitedLinkEventListener
* listener
=
486 static_cast<TrackingVisitedLinkEventListener
*>(master_
->GetListener());
488 // Verify that VisitedLinkMaster::Listener::Add was called for each added URL.
489 EXPECT_EQ(g_test_count
, listener
->add_count());
490 // Verify that VisitedLinkMaster::Listener::Reset was called both when one and
491 // all URLs are deleted.
492 EXPECT_EQ(2, listener
->reset_count());
495 class VisitCountingContext
: public content::TestBrowserContext
{
497 VisitCountingContext()
500 reset_event_count_(0),
501 new_table_count_(0) {}
503 void CountAddEvent(int by
) {
508 void CountResetEvent() {
509 reset_event_count_
++;
512 void CountNewTable() {
516 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_
; }
519 int new_table_count() const { return new_table_count_
; }
523 int add_event_count_
;
524 int reset_event_count_
;
525 int new_table_count_
;
528 // Stub out as little as possible, borrowing from RenderProcessHost.
529 class VisitRelayingRenderProcessHost
: public MockRenderProcessHost
{
531 explicit VisitRelayingRenderProcessHost(
532 content::BrowserContext
* browser_context
)
533 : MockRenderProcessHost(browser_context
), widgets_(0) {
534 content::NotificationService::current()->Notify(
535 content::NOTIFICATION_RENDERER_PROCESS_CREATED
,
536 content::Source
<RenderProcessHost
>(this),
537 content::NotificationService::NoDetails());
539 virtual ~VisitRelayingRenderProcessHost() {
540 content::NotificationService::current()->Notify(
541 content::NOTIFICATION_RENDERER_PROCESS_TERMINATED
,
542 content::Source
<content::RenderProcessHost
>(this),
543 content::NotificationService::NoDetails());
546 virtual void WidgetRestored() OVERRIDE
{ widgets_
++; }
547 virtual void WidgetHidden() OVERRIDE
{ widgets_
--; }
548 virtual int VisibleWidgetCount() const OVERRIDE
{ return widgets_
; }
550 virtual bool Send(IPC::Message
* msg
) OVERRIDE
{
551 VisitCountingContext
* counting_context
=
552 static_cast<VisitCountingContext
*>(
553 GetBrowserContext());
555 if (msg
->type() == ChromeViewMsg_VisitedLink_Add::ID
) {
556 PickleIterator
iter(*msg
);
557 std::vector
<uint64
> fingerprints
;
558 CHECK(IPC::ReadParam(msg
, &iter
, &fingerprints
));
559 counting_context
->CountAddEvent(fingerprints
.size());
560 } else if (msg
->type() == ChromeViewMsg_VisitedLink_Reset::ID
) {
561 counting_context
->CountResetEvent();
562 } else if (msg
->type() == ChromeViewMsg_VisitedLink_NewTable::ID
) {
563 counting_context
->CountNewTable();
573 DISALLOW_COPY_AND_ASSIGN(VisitRelayingRenderProcessHost
);
576 class VisitedLinkRenderProcessHostFactory
577 : public content::RenderProcessHostFactory
{
579 VisitedLinkRenderProcessHostFactory()
580 : content::RenderProcessHostFactory() {}
581 virtual content::RenderProcessHost
* CreateRenderProcessHost(
582 content::BrowserContext
* browser_context
,
583 content::SiteInstance
* site_instance
) const OVERRIDE
{
584 return new VisitRelayingRenderProcessHost(browser_context
);
589 DISALLOW_COPY_AND_ASSIGN(VisitedLinkRenderProcessHostFactory
);
592 class VisitedLinkEventsTest
: public content::RenderViewHostTestHarness
{
594 virtual void SetUp() {
595 SetRenderProcessHostFactory(&vc_rph_factory_
);
596 content::RenderViewHostTestHarness::SetUp();
599 virtual content::BrowserContext
* CreateBrowserContext() OVERRIDE
{
600 VisitCountingContext
* context
= new VisitCountingContext();
601 master_
.reset(new VisitedLinkMaster(context
, &delegate_
, true));
606 VisitCountingContext
* context() {
607 return static_cast<VisitCountingContext
*>(browser_context());
610 VisitedLinkMaster
* master() const {
611 return master_
.get();
614 void WaitForCoalescense() {
615 // Let the timer fire.
617 // TODO(ajwong): This is horrid! What is the right synchronization method?
618 base::RunLoop run_loop
;
619 base::MessageLoop::current()->PostDelayedTask(
621 run_loop
.QuitClosure(),
622 base::TimeDelta::FromMilliseconds(110));
627 VisitedLinkRenderProcessHostFactory vc_rph_factory_
;
630 TestVisitedLinkDelegate delegate_
;
631 scoped_ptr
<VisitedLinkMaster
> master_
;
634 TEST_F(VisitedLinkEventsTest
, Coalescense
) {
635 // add some URLs to master.
637 master()->AddURL(GURL("http://acidtests.org/"));
638 master()->AddURL(GURL("http://google.com/"));
639 master()->AddURL(GURL("http://chromium.org/"));
640 // Just for kicks, add a duplicate URL. This shouldn't increase the resulting
641 master()->AddURL(GURL("http://acidtests.org/"));
643 // Make sure that coalescing actually occurs. There should be no links or
644 // events received by the renderer.
645 EXPECT_EQ(0, context()->add_count());
646 EXPECT_EQ(0, context()->add_event_count());
648 WaitForCoalescense();
650 // We now should have 3 entries added in 1 event.
651 EXPECT_EQ(3, context()->add_count());
652 EXPECT_EQ(1, context()->add_event_count());
654 // Test whether the coalescing continues by adding a few more URLs.
655 master()->AddURL(GURL("http://google.com/chrome/"));
656 master()->AddURL(GURL("http://webkit.org/"));
657 master()->AddURL(GURL("http://acid3.acidtests.org/"));
659 WaitForCoalescense();
661 // We should have 6 entries added in 2 events.
662 EXPECT_EQ(6, context()->add_count());
663 EXPECT_EQ(2, context()->add_event_count());
665 // Test whether duplicate entries produce add events.
666 master()->AddURL(GURL("http://acidtests.org/"));
668 WaitForCoalescense();
670 // We should have no change in results.
671 EXPECT_EQ(6, context()->add_count());
672 EXPECT_EQ(2, context()->add_event_count());
674 // Ensure that the coalescing does not resume after resetting.
675 master()->AddURL(GURL("http://build.chromium.org/"));
676 master()->DeleteAllURLs();
678 WaitForCoalescense();
680 // We should have no change in results except for one new reset event.
681 EXPECT_EQ(6, context()->add_count());
682 EXPECT_EQ(2, context()->add_event_count());
683 EXPECT_EQ(1, context()->reset_event_count());
686 TEST_F(VisitedLinkEventsTest
, Basics
) {
687 RenderViewHostTester::For(rvh())->CreateRenderView(base::string16(),
692 master()->AddURL(GURL("http://acidtests.org/"));
693 master()->AddURL(GURL("http://google.com/"));
694 master()->AddURL(GURL("http://chromium.org/"));
696 WaitForCoalescense();
698 // We now should have 1 add event.
699 EXPECT_EQ(1, context()->add_event_count());
700 EXPECT_EQ(0, context()->reset_event_count());
702 master()->DeleteAllURLs();
704 WaitForCoalescense();
706 // We should have no change in add results, plus one new reset event.
707 EXPECT_EQ(1, context()->add_event_count());
708 EXPECT_EQ(1, context()->reset_event_count());
711 TEST_F(VisitedLinkEventsTest
, TabVisibility
) {
712 RenderViewHostTester::For(rvh())->CreateRenderView(base::string16(),
716 // Simulate tab becoming inactive.
717 RenderViewHostTester::For(rvh())->SimulateWasHidden();
720 master()->AddURL(GURL("http://acidtests.org/"));
721 master()->AddURL(GURL("http://google.com/"));
722 master()->AddURL(GURL("http://chromium.org/"));
724 WaitForCoalescense();
726 // We shouldn't have any events.
727 EXPECT_EQ(0, context()->add_event_count());
728 EXPECT_EQ(0, context()->reset_event_count());
730 // Simulate the tab becoming active.
731 RenderViewHostTester::For(rvh())->SimulateWasShown();
733 // We should now have 3 add events, still no reset events.
734 EXPECT_EQ(1, context()->add_event_count());
735 EXPECT_EQ(0, context()->reset_event_count());
737 // Deactivate the tab again.
738 RenderViewHostTester::For(rvh())->SimulateWasHidden();
740 // Add a bunch of URLs (over 50) to exhaust the link event buffer.
741 for (int i
= 0; i
< 100; i
++)
742 master()->AddURL(TestURL(i
));
744 WaitForCoalescense();
746 // Again, no change in events until tab is active.
747 EXPECT_EQ(1, context()->add_event_count());
748 EXPECT_EQ(0, context()->reset_event_count());
751 RenderViewHostTester::For(rvh())->SimulateWasShown();
753 // We should have only one more reset event.
754 EXPECT_EQ(1, context()->add_event_count());
755 EXPECT_EQ(1, context()->reset_event_count());
758 // Tests that VisitedLink ignores renderer process creation notification for a
759 // different context.
760 TEST_F(VisitedLinkEventsTest
, IgnoreRendererCreationFromDifferentContext
) {
761 VisitCountingContext different_context
;
762 VisitRelayingRenderProcessHost
different_process_host(&different_context
);
764 content::NotificationService::current()->Notify(
765 content::NOTIFICATION_RENDERER_PROCESS_CREATED
,
766 content::Source
<content::RenderProcessHost
>(&different_process_host
),
767 content::NotificationService::NoDetails());
768 WaitForCoalescense();
770 EXPECT_EQ(0, different_context
.new_table_count());
774 } // namespace visitedlink