blob: 224b881818dcb4c5cdc8961e4fe5d6f6c2d976c2 [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 <signal.h>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/path_service.h"
#include "build/branding_buildflags.h"
#include "chrome/browser/first_run/first_run_dialog.h"
#include "chrome/browser/first_run/first_run_internal.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "content/public/test/browser_test.h"
namespace first_run {
class FirstRunInternalPosixTest : public InProcessBrowserTest {
protected:
FirstRunInternalPosixTest() = default;
FirstRunInternalPosixTest(const FirstRunInternalPosixTest&) = delete;
FirstRunInternalPosixTest& operator=(const FirstRunInternalPosixTest&) =
delete;
// InProcessBrowserTest:
void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch(switches::kForceFirstRun);
}
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
// For Chrome, the presence of a Local State file should not influence whether
// the first run dialog is shown. See crbug.com/1221483.
bool SetUpUserDataDirectory() override {
base::FilePath user_data_dir;
base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
const base::FilePath local_state_file =
user_data_dir.Append(chrome::kLocalStateFilename);
const std::string empty_prefs = "{}";
base::WriteFile(local_state_file, empty_prefs.data());
return true;
}
#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING)
void SetUpInProcessBrowserTestFixture() override {
InProcessBrowserTest::SetUpInProcessBrowserTestFixture();
#if !BUILDFLAG(GOOGLE_CHROME_BRANDING)
// While Chromium uses ForcedShowDialogState::kForceShown, Chrome uses the
// default, ForcedShowDialogState::kNotForced, to exercise Chrome-specific
// behavior. See ShouldShowFirstRunDialog().
internal::ForceFirstRunDialogShownForTesting(true);
#endif // !BUILDFLAG(GOOGLE_CHROME_BRANDING)
// The modal dialog will spawn and spin a nested RunLoop when
// content::BrowserTestBase::SetUp() invokes content::ContentMain().
// BrowserTestBase sets ContentMainParams::ui_task before this, but the
// ui_task isn't actually Run() until after the dialog is spawned in
// ChromeBrowserMainParts::PreMainMessageLoopRunImpl(). Instead, try to
// inspect state by posting a task to run in that nested RunLoop.
// There's no MessageLoop to enqueue a task on yet, there's also no
// content::NotificationService, or anything else sensible that would allow
// us to hook in a task. So use a testing-only Closure.
GetBeforeShowFirstRunDialogHookForTesting() = base::BindOnce(
&FirstRunInternalPosixTest::SetupNestedTask, base::Unretained(this));
EXPECT_FALSE(inspected_state_);
}
void TearDownInProcessBrowserTestFixture() override {
EXPECT_TRUE(inspected_state_);
// The test closure should have run. But clear the global in case it hasn't.
EXPECT_FALSE(GetBeforeShowFirstRunDialogHookForTesting());
GetBeforeShowFirstRunDialogHookForTesting().Reset();
InProcessBrowserTest::TearDownInProcessBrowserTestFixture();
}
private:
// A task run immediately before first_run::DoPostImportPlatformSpecificTasks
// shows the first-run dialog.
void SetupNestedTask() {
EXPECT_TRUE(base::SequencedTaskRunnerHandle::Get());
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&FirstRunInternalPosixTest::InspectState,
base::Unretained(this)));
}
// A task queued up to run once the first-run dialog starts pumping messages
// in its modal loop.
void InspectState() {
// Send a signal to myself. This should post a task for the next run loop
// iteration to set browser_shutdown::IsTryingToQuit(), and interrupt the
// RunLoop.
raise(SIGINT);
inspected_state_ = true;
}
bool inspected_state_ = false;
};
// Test the first run flow for showing the modal dialog that surfaces the first
// run dialog. Ensure browser startup safely handles a signal while the modal
// RunLoop is running.
IN_PROC_BROWSER_TEST_F(FirstRunInternalPosixTest, HandleSigint) {
// Never reached. The above SIGINT should prevent the main message loop
// (and the browser test hooking it) from running.
ADD_FAILURE() << "Should never be called";
}
} // namespace first_run