blob: 8ffcab227247152cfdb3d0a0e0800fbd58d46f1a [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/profiles/profile_destroyer.h"
#include "chrome/test/base/browser_with_test_window_test.h"
#include "chrome/test/base/testing_profile.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/site_instance.h"
class TestingOffTheRecordDestructionProfile : public TestingProfile {
public:
TestingOffTheRecordDestructionProfile()
: TestingProfile(base::FilePath(),
NULL,
scoped_refptr<ExtensionSpecialStoragePolicy>()
scoped_ptr<PrefServiceSyncable>(),
true,
TestingFactories()),
destroyed_otr_profile_(false) {
set_incognito(true);
}
void DestroyOffTheRecordProfile() override {
destroyed_otr_profile_ = true;
}
bool destroyed_otr_profile_;
DISALLOW_COPY_AND_ASSIGN(TestingOffTheRecordDestructionProfile);
};
class TestingOriginalDestructionProfile : public TestingProfile {
public:
TestingOriginalDestructionProfile() : destroyed_otr_profile_(false) {
DCHECK_EQ(kNull, living_instance_);
living_instance_ = this;
}
~TestingOriginalDestructionProfile() override {
DCHECK_EQ(this, living_instance_);
living_instance_ = NULL;
}
void DestroyOffTheRecordProfile() override {
SetOffTheRecordProfile(NULL);
destroyed_otr_profile_ = true;
}
bool destroyed_otr_profile_;
static TestingOriginalDestructionProfile* living_instance_;
// This is to avoid type casting in DCHECK_EQ & EXPECT_NE.
static const TestingOriginalDestructionProfile* kNull;
DISALLOW_COPY_AND_ASSIGN(TestingOriginalDestructionProfile);
};
const TestingOriginalDestructionProfile*
TestingOriginalDestructionProfile::kNull = NULL;
TestingOriginalDestructionProfile*
TestingOriginalDestructionProfile::living_instance_ = NULL;
class ProfileDestroyerTest : public BrowserWithTestWindowTest {
public:
ProfileDestroyerTest() : off_the_record_profile_(NULL) {}
protected:
TestingProfile* CreateProfile() override {
if (off_the_record_profile_ == NULL)
off_the_record_profile_ = new TestingOffTheRecordDestructionProfile();
return off_the_record_profile_;
}
TestingOffTheRecordDestructionProfile* off_the_record_profile_;
DISALLOW_COPY_AND_ASSIGN(ProfileDestroyerTest);
};
TEST_F(ProfileDestroyerTest, DelayProfileDestruction) {
scoped_refptr<content::SiteInstance> instance1(
content::SiteInstance::Create(off_the_record_profile_));
scoped_ptr<content::RenderProcessHost> render_process_host1;
render_process_host1.reset(instance1->GetProcess());
ASSERT_TRUE(render_process_host1.get() != NULL);
scoped_refptr<content::SiteInstance> instance2(
content::SiteInstance::Create(off_the_record_profile_));
scoped_ptr<content::RenderProcessHost> render_process_host2;
render_process_host2.reset(instance2->GetProcess());
ASSERT_TRUE(render_process_host2.get() != NULL);
// destroying the browser should not destroy the off the record profile...
set_browser(NULL);
EXPECT_FALSE(off_the_record_profile_->destroyed_otr_profile_);
// until we destroy the render process host holding on to it...
render_process_host1.release()->Cleanup();
// And asynchronicity kicked in properly.
base::MessageLoop::current()->RunUntilIdle();
EXPECT_FALSE(off_the_record_profile_->destroyed_otr_profile_);
// I meant, ALL the render process hosts... :-)
render_process_host2.release()->Cleanup();
base::MessageLoop::current()->RunUntilIdle();
EXPECT_TRUE(off_the_record_profile_->destroyed_otr_profile_);
}
TEST_F(ProfileDestroyerTest, DelayOriginalProfileDestruction) {
TestingOriginalDestructionProfile* original_profile =
new TestingOriginalDestructionProfile;
TestingOffTheRecordDestructionProfile* off_the_record_profile =
new TestingOffTheRecordDestructionProfile;
original_profile->SetOffTheRecordProfile(off_the_record_profile);
scoped_refptr<content::SiteInstance> instance1(
content::SiteInstance::Create(off_the_record_profile));
scoped_ptr<content::RenderProcessHost> render_process_host1;
render_process_host1.reset(instance1->GetProcess());
ASSERT_TRUE(render_process_host1.get() != NULL);
// Trying to destroy the original profile should be delayed until associated
// off the record profile is released by all render process hosts.
ProfileDestroyer::DestroyProfileWhenAppropriate(original_profile);
EXPECT_NE(TestingOriginalDestructionProfile::kNull,
TestingOriginalDestructionProfile::living_instance_);
EXPECT_FALSE(original_profile->destroyed_otr_profile_);
render_process_host1.release()->Cleanup();
base::MessageLoop::current()->RunUntilIdle();
EXPECT_EQ(NULL, TestingOriginalDestructionProfile::living_instance_);
// And the same protection should apply to the main profile.
TestingOriginalDestructionProfile* main_profile =
new TestingOriginalDestructionProfile;
scoped_refptr<content::SiteInstance> instance2(
content::SiteInstance::Create(main_profile));
scoped_ptr<content::RenderProcessHost> render_process_host2;
render_process_host2.reset(instance2->GetProcess());
ASSERT_TRUE(render_process_host2.get() != NULL);
ProfileDestroyer::DestroyProfileWhenAppropriate(main_profile);
EXPECT_EQ(main_profile, TestingOriginalDestructionProfile::living_instance_);
render_process_host2.release()->Cleanup();
base::MessageLoop::current()->RunUntilIdle();
EXPECT_EQ(NULL, TestingOriginalDestructionProfile::living_instance_);
}