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. 4 5 #include "chrome/browser/profiles/profile_destroyer.h" 6 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" 11 12 class TestingOffTheRecordDestructionProfile : public TestingProfile { 13 public: 14 TestingOffTheRecordDestructionProfile() 15 : TestingProfile(base::FilePath(), 16 NULL, 17 scoped_refptr<ExtensionSpecialStoragePolicy>() 18 scoped_ptr<PrefServiceSyncable>(), 19 true, 20 TestingFactories()), 21 destroyed_otr_profile_(false) { 22 set_incognito(true); 23 } 24 virtual void DestroyOffTheRecordProfile() OVERRIDE { 25 destroyed_otr_profile_ = true; 26 } 27 bool destroyed_otr_profile_; 28 29 DISALLOW_COPY_AND_ASSIGN(TestingOffTheRecordDestructionProfile); 30 }; 31 32 class TestingOriginalDestructionProfile : public TestingProfile { 33 public: 34 TestingOriginalDestructionProfile() : destroyed_otr_profile_(false) { 35 DCHECK_EQ(kNull, living_instance_); 36 living_instance_ = this; 37 } 38 virtual ~TestingOriginalDestructionProfile() { 39 DCHECK_EQ(this, living_instance_); 40 living_instance_ = NULL; 41 } 42 virtual void DestroyOffTheRecordProfile() OVERRIDE { 43 SetOffTheRecordProfile(NULL); 44 destroyed_otr_profile_ = true; 45 } 46 bool destroyed_otr_profile_; 47 static TestingOriginalDestructionProfile* living_instance_; 48 49 // This is to avoid type casting in DCHECK_EQ & EXPECT_NE. 50 static const TestingOriginalDestructionProfile* kNull; 51 52 DISALLOW_COPY_AND_ASSIGN(TestingOriginalDestructionProfile); 53 }; 54 const TestingOriginalDestructionProfile* 55 TestingOriginalDestructionProfile::kNull = NULL; 56 57 TestingOriginalDestructionProfile* 58 TestingOriginalDestructionProfile::living_instance_ = NULL; 59 60 class ProfileDestroyerTest : public BrowserWithTestWindowTest { 61 public: 62 ProfileDestroyerTest() : off_the_record_profile_(NULL) {} 63 64 protected: 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_; 69 } 70 TestingOffTheRecordDestructionProfile* off_the_record_profile_; 71 72 DISALLOW_COPY_AND_ASSIGN(ProfileDestroyerTest); 73 }; 74 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); 81 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); 87 88 // destroying the browser should not destroy the off the record profile... 89 set_browser(NULL); 90 EXPECT_FALSE(off_the_record_profile_->destroyed_otr_profile_); 91 92 // until we destroy the render process host holding on to it... 93 render_process_host1.release()->Cleanup(); 94 95 // And asynchronicity kicked in properly. 96 base::MessageLoop::current()->RunUntilIdle(); 97 EXPECT_FALSE(off_the_record_profile_->destroyed_otr_profile_); 98 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_); 103 } 104 105 TEST_F(ProfileDestroyerTest, DelayOriginalProfileDestruction) { 106 TestingOriginalDestructionProfile* original_profile = 107 new TestingOriginalDestructionProfile; 108 109 TestingOffTheRecordDestructionProfile* off_the_record_profile = 110 new TestingOffTheRecordDestructionProfile; 111 112 original_profile->SetOffTheRecordProfile(off_the_record_profile); 113 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); 119 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_); 126 127 render_process_host1.release()->Cleanup(); 128 base::MessageLoop::current()->RunUntilIdle(); 129 EXPECT_EQ(NULL, TestingOriginalDestructionProfile::living_instance_); 130 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); 139 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_); 145 } 146