blob: 41b149f23c027b844da068a951a42355edb5b322 [file] [log] [blame]
// Copyright (c) 2015 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_window.h"
#include <stddef.h>
#include <utility>
#include "base/command_line.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "build/build_config.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/history/history_service_factory.h"
#include "chrome/browser/profiles/profile_attributes_storage.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/search_engines/template_url_service_factory.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/toolbar/app_menu_model.h"
#include "chrome/browser/ui/user_manager.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/search_test_utils.h"
#include "chrome/test/base/ui_test_utils.h"
#include "chrome/test/base/web_ui_browser_test.h"
#include "components/account_id/account_id.h"
#include "components/history/core/browser/history_db_task.h"
#include "components/history/core/browser/history_service.h"
#include "components/search_engines/template_url_service.h"
#include "components/signin/core/browser/account_consistency_method.h"
#include "content/public/browser/notification_service.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "url/gurl.h"
#if defined(OS_CHROMEOS)
#error "This test verifies the Desktop implementation of Guest only."
#endif
namespace {
// Code related to history borrowed from:
// chrome/browser/history/history_browsertest.cc
// Note: WaitableEvent is not used for synchronization between the main thread
// and history backend thread because the history subsystem posts tasks back
// to the main thread. Had we tried to Signal an event in such a task
// and Wait for it on the main thread, the task would not run at all because
// the main thread would be blocked on the Wait call, resulting in a deadlock.
// A task to be scheduled on the history backend thread.
// Notifies the main thread after all history backend thread tasks have run.
class WaitForHistoryTask : public history::HistoryDBTask {
public:
WaitForHistoryTask() {}
bool RunOnDBThread(history::HistoryBackend* backend,
history::HistoryDatabase* db) override {
return true;
}
void DoneRunOnMainThread() override {
base::RunLoop::QuitCurrentWhenIdleDeprecated();
}
private:
~WaitForHistoryTask() override {}
DISALLOW_COPY_AND_ASSIGN(WaitForHistoryTask);
};
void WaitForHistoryBackendToRun(Profile* profile) {
base::CancelableTaskTracker task_tracker;
std::unique_ptr<history::HistoryDBTask> task(new WaitForHistoryTask());
history::HistoryService* history = HistoryServiceFactory::GetForProfile(
profile, ServiceAccessType::EXPLICIT_ACCESS);
history->ScheduleDBTask(FROM_HERE, std::move(task), &task_tracker);
content::RunMessageLoop();
}
class EmptyAcceleratorHandler : public ui::AcceleratorProvider {
public:
// Don't handle accelerators.
bool GetAcceleratorForCommandId(int command_id,
ui::Accelerator* accelerator) const override {
return false;
}
};
base::FilePath CreateTestingProfile(const std::string& name,
const std::string& relative_path) {
ProfileManager* manager = g_browser_process->profile_manager();
ProfileAttributesStorage& storage = manager->GetProfileAttributesStorage();
size_t starting_number_of_profiles = storage.GetNumberOfProfiles();
base::FilePath profile_path =
manager->user_data_dir().AppendASCII(relative_path);
storage.AddProfile(profile_path, base::ASCIIToUTF16(name), std::string(),
base::string16(), 0u, std::string(), EmptyAccountId());
EXPECT_EQ(starting_number_of_profiles + 1u, storage.GetNumberOfProfiles());
return profile_path;
}
} // namespace
class ProfileWindowBrowserTest : public InProcessBrowserTest {
public:
ProfileWindowBrowserTest() {}
~ProfileWindowBrowserTest() override {}
Browser* OpenGuestBrowser();
private:
DISALLOW_COPY_AND_ASSIGN(ProfileWindowBrowserTest);
};
Browser* ProfileWindowBrowserTest::OpenGuestBrowser() {
size_t num_browsers = BrowserList::GetInstance()->size();
// Create a guest browser nicely. Using CreateProfile() and CreateBrowser()
// does incomplete initialization that would lead to
// SystemUrlRequestContextGetter being leaked.
content::WindowedNotificationObserver browser_creation_observer(
chrome::NOTIFICATION_BROWSER_OPENED,
content::NotificationService::AllSources());
profiles::SwitchToGuestProfile(ProfileManager::CreateCallback());
browser_creation_observer.Wait();
DCHECK_NE(static_cast<Profile*>(nullptr),
g_browser_process->profile_manager()->GetProfileByPath(
ProfileManager::GetGuestProfilePath()));
EXPECT_EQ(num_browsers + 1, BrowserList::GetInstance()->size());
Profile* guest = g_browser_process->profile_manager()->GetProfileByPath(
ProfileManager::GetGuestProfilePath());
Browser* browser = chrome::FindAnyBrowser(guest, true);
EXPECT_TRUE(browser);
// When |browser| closes a BrowsingDataRemover will be created and executed.
// It needs a loaded TemplateUrlService or else it hangs on to a
// CallbackList::Subscription forever.
search_test_utils::WaitForTemplateURLServiceToLoad(
TemplateURLServiceFactory::GetForProfile(guest));
return browser;
}
IN_PROC_BROWSER_TEST_F(ProfileWindowBrowserTest, OpenGuestBrowser) {
EXPECT_TRUE(OpenGuestBrowser());
}
IN_PROC_BROWSER_TEST_F(ProfileWindowBrowserTest, GuestIsIncognito) {
Browser* guest_browser = OpenGuestBrowser();
EXPECT_TRUE(guest_browser->profile()->IsOffTheRecord());
}
IN_PROC_BROWSER_TEST_F(ProfileWindowBrowserTest, GuestIgnoresHistory) {
Browser* guest_browser = OpenGuestBrowser();
ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile(
guest_browser->profile(), ServiceAccessType::EXPLICIT_ACCESS));
GURL test_url = ui_test_utils::GetTestUrl(
base::FilePath(base::FilePath::kCurrentDirectory),
base::FilePath(FILE_PATH_LITERAL("title2.html")));
ui_test_utils::NavigateToURL(guest_browser, test_url);
WaitForHistoryBackendToRun(guest_browser->profile());
std::vector<GURL> urls =
ui_test_utils::HistoryEnumerator(guest_browser->profile()).urls();
ASSERT_EQ(0U, urls.size());
}
IN_PROC_BROWSER_TEST_F(ProfileWindowBrowserTest, GuestClearsCookies) {
Browser* guest_browser = OpenGuestBrowser();
Profile* guest_profile = guest_browser->profile();
ASSERT_TRUE(embedded_test_server()->Start());
GURL url(embedded_test_server()->GetURL("/set-cookie?cookie1"));
// Before navigation there are no cookies for the URL.
std::string cookie = content::GetCookies(guest_profile, url);
ASSERT_EQ("", cookie);
// After navigation there is a cookie for the URL.
ui_test_utils::NavigateToURL(guest_browser, url);
cookie = content::GetCookies(guest_profile, url);
EXPECT_EQ("cookie1", cookie);
CloseBrowserSynchronously(guest_browser);
// Closing the browser has removed the cookie.
cookie = content::GetCookies(guest_profile, url);
ASSERT_EQ("", cookie);
}
IN_PROC_BROWSER_TEST_F(ProfileWindowBrowserTest, GuestCannotSignin) {
Browser* guest_browser = OpenGuestBrowser();
SigninManager* signin_manager = SigninManagerFactory::GetForProfile(
guest_browser->profile());
// Guest profiles can't sign in without a SigninManager.
ASSERT_FALSE(signin_manager);
}
IN_PROC_BROWSER_TEST_F(ProfileWindowBrowserTest, GuestAppMenuLacksBookmarks) {
EmptyAcceleratorHandler accelerator_handler;
// Verify the normal browser has a bookmark menu.
AppMenuModel model_normal_profile(&accelerator_handler, browser());
model_normal_profile.Init();
EXPECT_NE(-1, model_normal_profile.GetIndexOfCommandId(IDC_BOOKMARKS_MENU));
// Guest browser has no bookmark menu.
Browser* guest_browser = OpenGuestBrowser();
AppMenuModel model_guest_profile(&accelerator_handler, guest_browser);
EXPECT_EQ(-1, model_guest_profile.GetIndexOfCommandId(IDC_BOOKMARKS_MENU));
}
IN_PROC_BROWSER_TEST_F(ProfileWindowBrowserTest, OpenBrowserWindowForProfile) {
Profile* profile = browser()->profile();
size_t num_browsers = BrowserList::GetInstance()->size();
profiles::OpenBrowserWindowForProfile(
ProfileManager::CreateCallback(), true, false, false, profile,
Profile::CreateStatus::CREATE_STATUS_INITIALIZED);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(num_browsers + 1, BrowserList::GetInstance()->size());
EXPECT_FALSE(UserManager::IsShowing());
}
IN_PROC_BROWSER_TEST_F(ProfileWindowBrowserTest,
OpenBrowserWindowForProfileWithSigninRequired) {
Profile* profile = browser()->profile();
ProfileAttributesEntry* entry;
ASSERT_TRUE(g_browser_process->profile_manager()
->GetProfileAttributesStorage()
.GetProfileAttributesWithPath(profile->GetPath(), &entry));
entry->SetIsSigninRequired(true);
size_t num_browsers = BrowserList::GetInstance()->size();
base::RunLoop run_loop;
UserManager::AddOnUserManagerShownCallbackForTesting(run_loop.QuitClosure());
profiles::OpenBrowserWindowForProfile(
ProfileManager::CreateCallback(), true, false, false, profile,
Profile::CreateStatus::CREATE_STATUS_INITIALIZED);
run_loop.Run();
EXPECT_EQ(num_browsers, BrowserList::GetInstance()->size());
EXPECT_TRUE(UserManager::IsShowing());
}
class ProfileWindowWebUIBrowserTest : public WebUIBrowserTest {
public:
void OnSystemProfileCreated(std::string* url_to_test,
const base::Closure& quit_loop,
Profile* profile,
const std::string& url) {
*url_to_test = url;
quit_loop.Run();
}
private:
void SetUpOnMainThread() override {
WebUIBrowserTest::SetUpOnMainThread();
AddLibrary(base::FilePath(
FILE_PATH_LITERAL("profile_window_browsertest.js")));
}
};
IN_PROC_BROWSER_TEST_F(ProfileWindowWebUIBrowserTest,
UserManagerFocusSingleProfile) {
std::string url_to_test;
base::RunLoop run_loop;
profiles::CreateSystemProfileForUserManager(
browser()->profile()->GetPath(),
profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION,
base::Bind(&ProfileWindowWebUIBrowserTest::OnSystemProfileCreated,
base::Unretained(this),
&url_to_test,
run_loop.QuitClosure()));
run_loop.Run();
ui_test_utils::NavigateToURL(browser(), GURL(url_to_test));
EXPECT_TRUE(RunJavascriptTest("testNoPodFocused"));
}
// This test is flaky, see https://crbug.com/611619.
IN_PROC_BROWSER_TEST_F(ProfileWindowWebUIBrowserTest,
DISABLED_UserManagerFocusMultipleProfiles) {
// The profile names are meant to sort differently by ICU collation and by
// naive sorting. See crbug/596280.
base::FilePath expected_path = CreateTestingProfile("#abc", "Profile 1");
CreateTestingProfile("?abc", "Profile 2");
std::string url_to_test;
base::RunLoop run_loop;
profiles::CreateSystemProfileForUserManager(
expected_path,
profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION,
base::Bind(&ProfileWindowWebUIBrowserTest::OnSystemProfileCreated,
base::Unretained(this),
&url_to_test,
run_loop.QuitClosure()));
run_loop.Run();
ui_test_utils::NavigateToURL(browser(), GURL(url_to_test));
EXPECT_TRUE(RunJavascriptTest("testPodFocused",
base::Value(expected_path.AsUTF8Unsafe())));
}