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 "chrome/browser/profiles/profile_destroyer.h"
7 #include "chrome/test/base/browser_with_test_window_test.h"
8 #include "chrome/test/base/testing_profile.h"
9 #include "content/public/browser/render_process_host.h"
10 #include "content/public/browser/site_instance.h"
12 class TestingOffTheRecordDestructionProfile
: public TestingProfile
{
14 TestingOffTheRecordDestructionProfile()
15 : TestingProfile(base::FilePath(),
17 scoped_refptr
<ExtensionSpecialStoragePolicy
>()
18 scoped_ptr
<PrefServiceSyncable
>(),
21 destroyed_otr_profile_(false) {
24 virtual void DestroyOffTheRecordProfile() OVERRIDE
{
25 destroyed_otr_profile_
= true;
27 bool destroyed_otr_profile_
;
29 DISALLOW_COPY_AND_ASSIGN(TestingOffTheRecordDestructionProfile
);
32 class TestingOriginalDestructionProfile
: public TestingProfile
{
34 TestingOriginalDestructionProfile() : destroyed_otr_profile_(false) {
35 DCHECK_EQ(kNull
, living_instance_
);
36 living_instance_
= this;
38 virtual ~TestingOriginalDestructionProfile() {
39 DCHECK_EQ(this, living_instance_
);
40 living_instance_
= NULL
;
42 virtual void DestroyOffTheRecordProfile() OVERRIDE
{
43 SetOffTheRecordProfile(NULL
);
44 destroyed_otr_profile_
= true;
46 bool destroyed_otr_profile_
;
47 static TestingOriginalDestructionProfile
* living_instance_
;
49 // This is to avoid type casting in DCHECK_EQ & EXPECT_NE.
50 static const TestingOriginalDestructionProfile
* kNull
;
52 DISALLOW_COPY_AND_ASSIGN(TestingOriginalDestructionProfile
);
54 const TestingOriginalDestructionProfile
*
55 TestingOriginalDestructionProfile::kNull
= NULL
;
57 TestingOriginalDestructionProfile
*
58 TestingOriginalDestructionProfile::living_instance_
= NULL
;
60 class ProfileDestroyerTest
: public BrowserWithTestWindowTest
{
62 ProfileDestroyerTest() : off_the_record_profile_(NULL
) {}
65 virtual TestingProfile
* CreateProfile() OVERRIDE
{
66 if (off_the_record_profile_
== NULL
)
67 off_the_record_profile_
= new TestingOffTheRecordDestructionProfile();
68 return off_the_record_profile_
;
70 TestingOffTheRecordDestructionProfile
* off_the_record_profile_
;
72 DISALLOW_COPY_AND_ASSIGN(ProfileDestroyerTest
);
75 TEST_F(ProfileDestroyerTest
, DelayProfileDestruction
) {
76 scoped_refptr
<content::SiteInstance
> instance1(
77 content::SiteInstance::Create(off_the_record_profile_
));
78 scoped_ptr
<content::RenderProcessHost
> render_process_host1
;
79 render_process_host1
.reset(instance1
->GetProcess());
80 ASSERT_TRUE(render_process_host1
.get() != NULL
);
82 scoped_refptr
<content::SiteInstance
> instance2(
83 content::SiteInstance::Create(off_the_record_profile_
));
84 scoped_ptr
<content::RenderProcessHost
> render_process_host2
;
85 render_process_host2
.reset(instance2
->GetProcess());
86 ASSERT_TRUE(render_process_host2
.get() != NULL
);
88 // destroying the browser should not destroy the off the record profile...
90 EXPECT_FALSE(off_the_record_profile_
->destroyed_otr_profile_
);
92 // until we destroy the render process host holding on to it...
93 render_process_host1
.release()->Cleanup();
95 // And asynchronicity kicked in properly.
96 base::MessageLoop::current()->RunUntilIdle();
97 EXPECT_FALSE(off_the_record_profile_
->destroyed_otr_profile_
);
99 // I meant, ALL the render process hosts... :-)
100 render_process_host2
.release()->Cleanup();
101 base::MessageLoop::current()->RunUntilIdle();
102 EXPECT_TRUE(off_the_record_profile_
->destroyed_otr_profile_
);
105 TEST_F(ProfileDestroyerTest
, DelayOriginalProfileDestruction
) {
106 TestingOriginalDestructionProfile
* original_profile
=
107 new TestingOriginalDestructionProfile
;
109 TestingOffTheRecordDestructionProfile
* off_the_record_profile
=
110 new TestingOffTheRecordDestructionProfile
;
112 original_profile
->SetOffTheRecordProfile(off_the_record_profile
);
114 scoped_refptr
<content::SiteInstance
> instance1(
115 content::SiteInstance::Create(off_the_record_profile
));
116 scoped_ptr
<content::RenderProcessHost
> render_process_host1
;
117 render_process_host1
.reset(instance1
->GetProcess());
118 ASSERT_TRUE(render_process_host1
.get() != NULL
);
120 // Trying to destroy the original profile should be delayed until associated
121 // off the record profile is released by all render process hosts.
122 ProfileDestroyer::DestroyProfileWhenAppropriate(original_profile
);
123 EXPECT_NE(TestingOriginalDestructionProfile::kNull
,
124 TestingOriginalDestructionProfile::living_instance_
);
125 EXPECT_FALSE(original_profile
->destroyed_otr_profile_
);
127 render_process_host1
.release()->Cleanup();
128 base::MessageLoop::current()->RunUntilIdle();
129 EXPECT_EQ(NULL
, TestingOriginalDestructionProfile::living_instance_
);
131 // And the same protection should apply to the main profile.
132 TestingOriginalDestructionProfile
* main_profile
=
133 new TestingOriginalDestructionProfile
;
134 scoped_refptr
<content::SiteInstance
> instance2(
135 content::SiteInstance::Create(main_profile
));
136 scoped_ptr
<content::RenderProcessHost
> render_process_host2
;
137 render_process_host2
.reset(instance2
->GetProcess());
138 ASSERT_TRUE(render_process_host2
.get() != NULL
);
140 ProfileDestroyer::DestroyProfileWhenAppropriate(main_profile
);
141 EXPECT_EQ(main_profile
, TestingOriginalDestructionProfile::living_instance_
);
142 render_process_host2
.release()->Cleanup();
143 base::MessageLoop::current()->RunUntilIdle();
144 EXPECT_EQ(NULL
, TestingOriginalDestructionProfile::living_instance_
);