blob: e615979b2cd30cc627dfcb1275fcf80c813f8a08 [file] [log] [blame]
// Copyright 2017 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 <set>
#include "base/bind.h"
#include "base/files/scoped_temp_dir.h"
#include "base/run_loop.h"
#include "base/stl_util.h"
#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/media/router/presentation/independent_otr_profile_manager.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_list_observer.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/ui/browser_navigator_params.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/web_contents.h"
#include "ui/base/page_transition_types.h"
#include "ui/base/window_open_disposition.h"
namespace content {
class NotificationDetails;
} // namespace content
namespace {
class ProfileDestructionWatcher final : public content::NotificationObserver {
public:
using DestructionCallback = base::OnceClosure;
ProfileDestructionWatcher() = default;
~ProfileDestructionWatcher() override = default;
// Watches for the destruction of |profile| and sets |destroyed| to true when
// that happens. |profile| can be any Profile object, but most tests below
// use it to watch for the cleanup of an OTR profile.
void Watch(Profile* profile, bool* destroyed) {
ASSERT_FALSE(*destroyed);
profile_ = profile;
destroyed_ = destroyed;
registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
content::Source<Profile>(profile_));
}
// content::NotificationObserver overrides.
void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) override {
DCHECK_EQ(chrome::NOTIFICATION_PROFILE_DESTROYED, type);
DCHECK(content::Source<Profile>(profile_) == source);
*destroyed_ = true;
registrar_.Remove(this, chrome::NOTIFICATION_PROFILE_DESTROYED, source);
}
private:
Profile* profile_;
bool* destroyed_;
content::NotificationRegistrar registrar_;
};
// Waits for |browser| to be removed from BrowserList and then calls |callback|.
// This is used to ensure that the Browser object and its window are destroyed
// after a call to BrowserWindow::Close, since base::RunLoop::RunUntilIdle
// doesn't ensure this on Mac.
class BrowserRemovedWaiter final : public BrowserListObserver {
public:
BrowserRemovedWaiter(Browser* browser, base::OnceClosure callback)
: browser_(browser), callback_(std::move(callback)) {
BrowserList::AddObserver(this);
}
~BrowserRemovedWaiter() override = default;
void OnBrowserRemoved(Browser* browser) override {
if (browser == browser_) {
BrowserList::RemoveObserver(this);
std::move(callback_).Run();
}
}
private:
Browser* browser_;
base::OnceClosure callback_;
};
void OriginalProfileNeverDestroyed(Profile* profile) {
FAIL()
<< "Original profile unexpectedly destroyed before dependent OTR profile";
}
// This class acts as an owner of an OTRProfileRegistration and deletes the
// registration when it is notified that the original profile is being
// destroyed. This is the minimum behavior expected by owners of
// OTRProfileRegistration.
class RegistrationOwner {
public:
// |profile| is an original Profile from which we are creating a registered
// OTR profile. |this| will own the resulting OTR profile registration.
RegistrationOwner(IndependentOTRProfileManager* manager, Profile* profile)
: otr_profile_registration_(manager->CreateFromOriginalProfile(
profile,
base::BindOnce(&RegistrationOwner::OriginalProfileDestroyed,
base::Unretained(this)))) {}
Profile* profile() const { return otr_profile_registration_->profile(); }
private:
void OriginalProfileDestroyed(Profile* profile) {
DCHECK(profile == otr_profile_registration_->profile());
otr_profile_registration_.reset();
}
std::unique_ptr<IndependentOTRProfileManager::OTRProfileRegistration>
otr_profile_registration_;
};
} // namespace
class IndependentOTRProfileManagerTest : public InProcessBrowserTest {
protected:
void EnableProfileHelperTestSettings() {
chromeos::ProfileHelper::Get()->SetProfileToUserForTestingEnabled(true);
chromeos::ProfileHelper::Get()->SetAlwaysReturnPrimaryUserForTesting(true);
}
IndependentOTRProfileManager* manager_ =
IndependentOTRProfileManager::GetInstance();
};
IN_PROC_BROWSER_TEST_F(IndependentOTRProfileManagerTest, CreateAndDestroy) {
ProfileDestructionWatcher watcher;
bool destroyed = false;
{
auto profile_registration = manager_->CreateFromOriginalProfile(
browser()->profile(), base::BindOnce(&OriginalProfileNeverDestroyed));
auto* otr_profile = profile_registration->profile();
ASSERT_NE(browser()->profile(), otr_profile);
EXPECT_NE(browser()->profile()->GetOffTheRecordProfile(), otr_profile);
EXPECT_TRUE(otr_profile->IsOffTheRecord());
watcher.Watch(otr_profile, &destroyed);
}
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(destroyed);
}
IN_PROC_BROWSER_TEST_F(IndependentOTRProfileManagerTest,
DeleteWaitsForLastBrowser) {
ProfileDestructionWatcher watcher;
Profile* otr_profile = nullptr;
Browser* otr_browser1 = nullptr;
Browser* otr_browser2 = nullptr;
{
auto profile_registration = manager_->CreateFromOriginalProfile(
browser()->profile(), base::BindOnce(&OriginalProfileNeverDestroyed));
otr_profile = profile_registration->profile();
otr_browser1 = CreateBrowser(otr_profile);
otr_browser2 = CreateBrowser(otr_profile);
ASSERT_NE(otr_browser1, otr_browser2);
}
base::RunLoop run_loop1;
BrowserRemovedWaiter removed_waiter1(otr_browser1,
run_loop1.QuitWhenIdleClosure());
otr_browser1->window()->Close();
run_loop1.Run();
ASSERT_FALSE(base::ContainsValue(*BrowserList::GetInstance(), otr_browser1));
ASSERT_TRUE(base::ContainsValue(*BrowserList::GetInstance(), otr_browser2));
bool destroyed = false;
watcher.Watch(otr_profile, &destroyed);
base::RunLoop run_loop2;
BrowserRemovedWaiter removed_waiter2(otr_browser2,
run_loop2.QuitWhenIdleClosure());
otr_browser2->window()->Close();
run_loop2.Run();
ASSERT_FALSE(base::ContainsValue(*BrowserList::GetInstance(), otr_browser2));
EXPECT_TRUE(destroyed);
}
IN_PROC_BROWSER_TEST_F(IndependentOTRProfileManagerTest,
DeleteImmediatelyWhenBrowsersAlreadyClosed) {
ProfileDestructionWatcher watcher;
bool destroyed = false;
{
auto profile_registration = manager_->CreateFromOriginalProfile(
browser()->profile(), base::BindOnce(&OriginalProfileNeverDestroyed));
auto* otr_profile = profile_registration->profile();
auto* otr_browser1 = CreateBrowser(otr_profile);
auto* otr_browser2 = CreateBrowser(otr_profile);
ASSERT_NE(otr_browser1, otr_browser2);
base::RunLoop run_loop1;
BrowserRemovedWaiter removed_waiter1(otr_browser1,
run_loop1.QuitWhenIdleClosure());
base::RunLoop run_loop2;
BrowserRemovedWaiter removed_waiter2(otr_browser2,
run_loop2.QuitWhenIdleClosure());
otr_browser1->window()->Close();
otr_browser2->window()->Close();
run_loop1.Run();
run_loop2.Run();
ASSERT_FALSE(
base::ContainsValue(*BrowserList::GetInstance(), otr_browser1));
ASSERT_FALSE(
base::ContainsValue(*BrowserList::GetInstance(), otr_browser2));
watcher.Watch(otr_profile, &destroyed);
}
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(destroyed);
}
IN_PROC_BROWSER_TEST_F(IndependentOTRProfileManagerTest,
CreateTwoFromSameProfile) {
ProfileDestructionWatcher watcher1;
ProfileDestructionWatcher watcher2;
bool destroyed1 = false;
bool destroyed2 = false;
{
auto profile_registration1 = manager_->CreateFromOriginalProfile(
browser()->profile(), base::BindOnce(&OriginalProfileNeverDestroyed));
auto* otr_profile1 = profile_registration1->profile();
auto profile_registration2 = manager_->CreateFromOriginalProfile(
browser()->profile(), base::BindOnce(&OriginalProfileNeverDestroyed));
auto* otr_profile2 = profile_registration2->profile();
ASSERT_NE(otr_profile1, otr_profile2);
watcher1.Watch(otr_profile1, &destroyed1);
watcher2.Watch(otr_profile2, &destroyed2);
}
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(destroyed1);
EXPECT_TRUE(destroyed2);
}
IN_PROC_BROWSER_TEST_F(IndependentOTRProfileManagerTest,
OriginalProfileDestroyedFirst) {
ProfileDestructionWatcher watcher;
base::ScopedAllowBlockingForTesting allow_blocking;
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
#if defined(OS_CHROMEOS)
EnableProfileHelperTestSettings();
#endif
auto original_profile = base::WrapUnique(Profile::CreateProfile(
temp_dir.GetPath(), nullptr, Profile::CREATE_MODE_SYNCHRONOUS));
ASSERT_TRUE(original_profile);
auto profile_owner = RegistrationOwner(manager_, original_profile.get());
auto* otr_profile = profile_owner.profile();
ASSERT_NE(original_profile.get(), otr_profile);
EXPECT_NE(original_profile->GetOffTheRecordProfile(), otr_profile);
bool destroyed = false;
watcher.Watch(otr_profile, &destroyed);
// Run tasks to ensure that Mojo connections are created before the profile is
// destroyed.
base::RunLoop().RunUntilIdle();
original_profile.reset();
// |original_profile| being destroyed should trigger the dependent OTR
// profile to be destroyed.
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(destroyed);
}
IN_PROC_BROWSER_TEST_F(IndependentOTRProfileManagerTest,
OriginalProfileDestroyedFirstTwoOTR) {
ProfileDestructionWatcher watcher1;
ProfileDestructionWatcher watcher2;
base::ScopedAllowBlockingForTesting allow_blocking;
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
#if defined(OS_CHROMEOS)
EnableProfileHelperTestSettings();
#endif
auto original_profile = base::WrapUnique(Profile::CreateProfile(
temp_dir.GetPath(), nullptr, Profile::CREATE_MODE_SYNCHRONOUS));
ASSERT_TRUE(original_profile);
auto profile_owner1 = RegistrationOwner(manager_, original_profile.get());
auto* otr_profile1 = profile_owner1.profile();
auto profile_owner2 = RegistrationOwner(manager_, original_profile.get());
auto* otr_profile2 = profile_owner2.profile();
bool destroyed1 = false;
bool destroyed2 = false;
watcher1.Watch(otr_profile1, &destroyed1);
watcher2.Watch(otr_profile2, &destroyed2);
// Run tasks to ensure that Mojo connections are created before the profile is
// destroyed.
base::RunLoop().RunUntilIdle();
original_profile.reset();
// |original_profile| being destroyed should trigger the dependent OTR
// profiles to be destroyed.
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(destroyed1);
EXPECT_TRUE(destroyed2);
}
IN_PROC_BROWSER_TEST_F(IndependentOTRProfileManagerTest,
BrowserClosingDoesntRemoveProfileObserver) {
ProfileDestructionWatcher watcher1;
ProfileDestructionWatcher watcher2;
bool destroyed1 = false;
bool destroyed2 = false;
base::ScopedAllowBlockingForTesting allow_blocking;
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
#if defined(OS_CHROMEOS)
EnableProfileHelperTestSettings();
#endif
auto original_profile = base::WrapUnique(Profile::CreateProfile(
temp_dir.GetPath(), nullptr, Profile::CREATE_MODE_SYNCHRONOUS));
ASSERT_TRUE(original_profile);
auto profile_owner1 = RegistrationOwner(manager_, original_profile.get());
auto* otr_profile1 = profile_owner1.profile();
Browser* otr_browser = nullptr;
{
auto profile_owner2 = RegistrationOwner(manager_, original_profile.get());
auto* otr_profile2 = profile_owner2.profile();
otr_browser = CreateBrowser(otr_profile2);
watcher2.Watch(otr_profile2, &destroyed2);
}
base::RunLoop run_loop;
BrowserRemovedWaiter removed_waiter(otr_browser,
run_loop.QuitWhenIdleClosure());
otr_browser->window()->Close();
run_loop.Run();
ASSERT_FALSE(base::ContainsValue(*BrowserList::GetInstance(), otr_browser));
EXPECT_TRUE(destroyed2);
watcher1.Watch(otr_profile1, &destroyed1);
original_profile.reset();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(destroyed1);
}
IN_PROC_BROWSER_TEST_F(IndependentOTRProfileManagerTest,
CallbackNotCalledAfterUnregister) {
ProfileDestructionWatcher watcher;
Browser* otr_browser = nullptr;
Profile* otr_profile = nullptr;
{
auto profile_registration = manager_->CreateFromOriginalProfile(
browser()->profile(), base::BindOnce(&OriginalProfileNeverDestroyed));
otr_profile = profile_registration->profile();
otr_browser = CreateBrowser(otr_profile);
}
bool destroyed = false;
watcher.Watch(otr_profile, &destroyed);
base::RunLoop run_loop;
BrowserRemovedWaiter removed_waiter(otr_browser,
run_loop.QuitWhenIdleClosure());
otr_browser->window()->Close();
run_loop.Run();
ASSERT_FALSE(base::ContainsValue(*BrowserList::GetInstance(), otr_browser));
EXPECT_TRUE(destroyed);
}