| // Copyright (c) 2012 The Chromium OS 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 "login_manager/browser_job.h" |
| |
| #include <unistd.h> |
| |
| #include <algorithm> |
| #include <set> |
| #include <string> |
| #include <vector> |
| |
| #include <base/command_line.h> |
| #include <base/logging.h> |
| #include <base/memory/scoped_ptr.h> |
| #include <base/strings/string_util.h> |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| #include "login_manager/mock_file_checker.h" |
| #include "login_manager/mock_metrics.h" |
| #include "login_manager/mock_system_utils.h" |
| |
| namespace login_manager { |
| |
| using ::testing::AnyNumber; |
| using ::testing::Return; |
| using ::testing::StrEq; |
| using ::testing::_; |
| |
| class BrowserJobTest : public ::testing::Test { |
| public: |
| BrowserJobTest() {} |
| |
| virtual ~BrowserJobTest() {} |
| |
| virtual void SetUp() OVERRIDE; |
| |
| protected: |
| static const char* kArgv[]; |
| static const char kUser[]; |
| static const char kHash[]; |
| |
| void ExpectArgsToContainFlag(const std::vector<std::string>& argv, |
| const char name[], |
| const char value[]) { |
| std::vector<std::string>::const_iterator user_flag = |
| std::find(argv.begin(), argv.end(), |
| base::StringPrintf("%s%s", name, value)); |
| EXPECT_NE(user_flag, argv.end()) << "argv should contain " << name << value; |
| } |
| |
| void ExpectArgsNotToContainFlag(const std::vector<std::string>& argv, |
| const char name[], |
| const char value[]) { |
| std::vector<std::string>::const_iterator user_flag = |
| std::find(argv.begin(), argv.end(), |
| base::StringPrintf("%s%s", name, value)); |
| EXPECT_EQ(user_flag, argv.end()) << "argv shouldn't contain " |
| << name << value; |
| } |
| |
| void ExpectArgsToContainAll(const std::vector<std::string>& argv, |
| const std::vector<std::string>& contained) { |
| std::set<std::string> argv_set(argv.begin(), argv.end()); |
| for (std::vector<std::string>::const_iterator it = contained.begin(); |
| it != contained.end(); |
| ++it) { |
| EXPECT_EQ(argv_set.count(*it), 1) << "argv should contain " << *it; |
| } |
| } |
| |
| std::vector<std::string> argv_; |
| MockFileChecker checker_; |
| MockMetrics metrics_; |
| MockSystemUtils utils_; |
| scoped_ptr<BrowserJob> job_; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(BrowserJobTest); |
| }; |
| |
| |
| // Default argument list for a job to use in mostly all test cases. |
| const char* BrowserJobTest::kArgv[] = { |
| "zero", |
| "one", |
| "two" |
| }; |
| |
| // Normal username to test session for. |
| const char BrowserJobTest::kUser[] = "test@gmail.com"; |
| const char BrowserJobTest::kHash[] = "fake_hash"; |
| |
| void BrowserJobTest::SetUp() { |
| argv_ = std::vector<std::string>(kArgv, |
| kArgv + arraysize(BrowserJobTest::kArgv)); |
| job_.reset(new BrowserJob(argv_, false, 1, &checker_, &metrics_, &utils_)); |
| } |
| |
| TEST_F(BrowserJobTest, InitializationTest) { |
| EXPECT_FALSE(job_->removed_login_manager_flag_); |
| std::vector<std::string> job_args = job_->ExportArgv(); |
| ASSERT_EQ(argv_.size(), job_args.size()); |
| ExpectArgsToContainAll(job_args, argv_); |
| } |
| |
| TEST_F(BrowserJobTest, WaitAndAbort) { |
| pid_t kDummyPid = 4; |
| EXPECT_CALL(utils_, fork()).WillOnce(Return(kDummyPid)); |
| EXPECT_CALL(utils_, kill(-kDummyPid, _, SIGABRT)).Times(1); |
| EXPECT_CALL(utils_, time(NULL)).WillRepeatedly(Return(0)); |
| EXPECT_CALL(utils_, ChildIsGone(kDummyPid, _)).WillOnce(Return(false)); |
| |
| EXPECT_CALL(metrics_, HasRecordedChromeExec()).WillRepeatedly(Return(false)); |
| EXPECT_CALL(metrics_, RecordStats(_)).Times(AnyNumber()); |
| |
| ASSERT_TRUE(job_->RunInBackground()); |
| job_->WaitAndAbort(base::TimeDelta::FromSeconds(3)); |
| |
| // Check for termination message. |
| base::FilePath term_file(utils_.GetUniqueFilename()); |
| ASSERT_FALSE(term_file.empty()); |
| } |
| |
| TEST_F(BrowserJobTest, WaitAndAbort_AlreadyGone) { |
| pid_t kDummyPid = 4; |
| EXPECT_CALL(utils_, fork()).WillOnce(Return(kDummyPid)); |
| EXPECT_CALL(utils_, time(NULL)).WillRepeatedly(Return(0)); |
| EXPECT_CALL(utils_, ChildIsGone(kDummyPid, _)).WillOnce(Return(true)); |
| |
| EXPECT_CALL(metrics_, HasRecordedChromeExec()).WillRepeatedly(Return(false)); |
| EXPECT_CALL(metrics_, RecordStats(_)).Times(AnyNumber()); |
| |
| ASSERT_TRUE(job_->RunInBackground()); |
| job_->WaitAndAbort(base::TimeDelta::FromSeconds(3)); |
| |
| // Check for no termination message. |
| std::string sent_message; |
| base::FilePath term_file(utils_.GetUniqueFilename()); |
| ASSERT_FALSE(utils_.ReadFileToString(term_file, &sent_message)); |
| } |
| |
| TEST_F(BrowserJobTest, ShouldStopTest) { |
| EXPECT_CALL(utils_, time(NULL)) |
| .WillRepeatedly(Return(BrowserJob::kRestartWindowSeconds)); |
| for (uint i = 0; i < BrowserJob::kRestartTries - 1; ++i) |
| job_->RecordTime(); |
| // We haven't yet saturated the list of start times, so... |
| EXPECT_FALSE(job_->ShouldStop()); |
| |
| // Go ahead and saturate. |
| job_->RecordTime(); |
| EXPECT_NE(0, job_->start_times_.front()); |
| EXPECT_TRUE(job_->ShouldStop()); |
| } |
| |
| TEST_F(BrowserJobTest, ShouldNotStopTest) { |
| EXPECT_CALL(utils_, time(NULL)) |
| .WillOnce(Return(BrowserJob::kRestartWindowSeconds)) |
| .WillOnce(Return(3 * BrowserJob::kRestartWindowSeconds)); |
| job_->RecordTime(); |
| EXPECT_FALSE(job_->ShouldStop()); |
| } |
| |
| TEST_F(BrowserJobTest, ShouldNotRunTest) { |
| EXPECT_CALL(checker_, exists()).WillRepeatedly(Return(true)); |
| EXPECT_FALSE(job_->ShouldRunBrowser()); |
| } |
| |
| TEST_F(BrowserJobTest, ShouldRunTest) { |
| EXPECT_CALL(checker_, exists()).WillRepeatedly(Return(false)); |
| EXPECT_TRUE(job_->ShouldRunBrowser()); |
| } |
| |
| TEST_F(BrowserJobTest, NullFileCheckerTest) { |
| BrowserJob job(argv_, true, 1, NULL, &metrics_, &utils_); |
| EXPECT_TRUE(job.ShouldRunBrowser()); |
| } |
| |
| // On the job's first run, it should have a one-time-flag. That |
| // should get cleared and not used again. |
| TEST_F(BrowserJobTest, OneTimeBootFlags) { |
| EXPECT_CALL(utils_, fork()).WillRepeatedly(Return(1)); |
| EXPECT_CALL(utils_, time(NULL)).WillRepeatedly(Return(0)); |
| |
| EXPECT_CALL(metrics_, HasRecordedChromeExec()) |
| .WillOnce(Return(false)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(metrics_, RecordStats(StrEq(("chrome-exec")))).Times(2); |
| |
| ASSERT_TRUE(job_->RunInBackground()); |
| ExpectArgsToContainFlag(job_->ExportArgv(), |
| BrowserJob::kFirstExecAfterBootFlag, ""); |
| |
| ASSERT_TRUE(job_->RunInBackground()); |
| ExpectArgsNotToContainFlag(job_->ExportArgv(), |
| BrowserJob::kFirstExecAfterBootFlag, ""); |
| } |
| |
| TEST_F(BrowserJobTest, RunBrowserTermMessage) { |
| pid_t kDummyPid = 4; |
| int signal = SIGKILL; |
| EXPECT_CALL(utils_, fork()).WillOnce(Return(kDummyPid)); |
| EXPECT_CALL(utils_, kill(kDummyPid, _, signal)).Times(1); |
| EXPECT_CALL(utils_, time(NULL)).WillRepeatedly(Return(0)); |
| |
| EXPECT_CALL(metrics_, HasRecordedChromeExec()).WillRepeatedly(Return(false)); |
| EXPECT_CALL(metrics_, RecordStats(_)).Times(AnyNumber()); |
| |
| std::string term_message("killdya"); |
| ASSERT_TRUE(job_->RunInBackground()); |
| job_->Kill(signal, term_message); |
| |
| // Check for termination message. |
| std::string sent_message; |
| base::FilePath term_file(utils_.GetUniqueFilename()); |
| ASSERT_FALSE(term_file.empty()); |
| ASSERT_TRUE(utils_.ReadFileToString(term_file, &sent_message)); |
| EXPECT_EQ(term_message, sent_message); |
| } |
| |
| TEST_F(BrowserJobTest, StartStopSessionTest) { |
| job_->StartSession(kUser, kHash); |
| |
| std::vector<std::string> job_args = job_->ExportArgv(); |
| ASSERT_LT(argv_.size(), job_args.size()); |
| ExpectArgsToContainAll(job_args, argv_); |
| ExpectArgsToContainFlag(job_args, BrowserJob::kLoginUserFlag, kUser); |
| ExpectArgsToContainFlag(job_args, BrowserJob::kLoginProfileFlag, "user"); |
| |
| // Should remove login user flag. |
| job_->StopSession(); |
| job_args = job_->ExportArgv(); |
| ASSERT_EQ(argv_.size(), job_args.size()); |
| ExpectArgsToContainAll(job_args, argv_); |
| } |
| |
| TEST_F(BrowserJobTest, StartStopMultiSessionTest) { |
| BrowserJob job(argv_, true, 1, &checker_, &metrics_, &utils_); |
| job.StartSession(kUser, kHash); |
| |
| std::vector<std::string> job_args = job.ExportArgv(); |
| ASSERT_EQ(argv_.size() + 2, job_args.size()); |
| ExpectArgsToContainAll(job_args, argv_); |
| ExpectArgsToContainFlag(job_args, BrowserJob::kLoginUserFlag, kUser); |
| ExpectArgsToContainFlag(job_args, BrowserJob::kLoginProfileFlag, kHash); |
| |
| // Start another session, expect the args to be unchanged. |
| job.StartSession(kUser, kHash); |
| job_args = job.ExportArgv(); |
| ASSERT_EQ(argv_.size() + 2, job_args.size()); |
| ExpectArgsToContainAll(job_args, argv_); |
| ExpectArgsToContainFlag(job_args, BrowserJob::kLoginUserFlag, kUser); |
| ExpectArgsToContainFlag(job_args, BrowserJob::kLoginProfileFlag, kHash); |
| |
| |
| // Should remove login user and login profile flags. |
| job.StopSession(); |
| job_args = job.ExportArgv(); |
| ASSERT_EQ(argv_.size(), job_args.size()); |
| ExpectArgsToContainAll(job_args, argv_); |
| } |
| |
| TEST_F(BrowserJobTest, StartStopSessionFromLoginTest) { |
| const char* kArgvWithLoginFlag[] = { |
| "zero", |
| "one", |
| "two", |
| "--login-manager" |
| }; |
| std::vector<std::string> argv( |
| kArgvWithLoginFlag, kArgvWithLoginFlag + arraysize(kArgvWithLoginFlag)); |
| BrowserJob job(argv, false, 1, &checker_, &metrics_, &utils_); |
| |
| job.StartSession(kUser, kHash); |
| |
| std::vector<std::string> job_args = job.ExportArgv(); |
| ASSERT_EQ(argv.size() + 1, job_args.size()); |
| ExpectArgsToContainAll(job_args, |
| std::vector<std::string>(argv.begin(), argv.end()-1)); |
| ExpectArgsToContainFlag(job_args, BrowserJob::kLoginUserFlag, kUser); |
| |
| // Should remove login user/hash flags and append --login-manager flag back. |
| job.StopSession(); |
| job_args = job.ExportArgv(); |
| ASSERT_EQ(argv.size(), job_args.size()); |
| ExpectArgsToContainAll(job_args, argv); |
| } |
| |
| TEST_F(BrowserJobTest, SetArguments) { |
| const char* kNewArgs[] = { |
| "--ichi", |
| "--ni dfs", |
| "--san" |
| }; |
| std::vector<std::string> new_args(kNewArgs, kNewArgs + arraysize(kNewArgs)); |
| job_->SetArguments(new_args); |
| |
| std::vector<std::string> job_args = job_->ExportArgv(); |
| ASSERT_EQ(new_args.size(), job_args.size()); |
| EXPECT_EQ(kArgv[0], job_args[0]); |
| for (size_t i = 1; i < arraysize(kNewArgs); ++i) { |
| EXPECT_EQ(kNewArgs[i], job_args[i]); |
| } |
| |
| job_->StartSession(kUser, kHash); |
| job_args = job_->ExportArgv(); |
| ExpectArgsToContainFlag(job_args, BrowserJob::kLoginUserFlag, kUser); |
| } |
| |
| TEST_F(BrowserJobTest, SetExtraArguments) { |
| const char* kExtraArgs[] = { "--ichi", "--ni", "--san" }; |
| std::vector<std::string> extra_args(kExtraArgs, |
| kExtraArgs + arraysize(kExtraArgs)); |
| job_->SetExtraArguments(extra_args); |
| |
| std::vector<std::string> job_args = job_->ExportArgv(); |
| ExpectArgsToContainAll(job_args, argv_); |
| ExpectArgsToContainAll(job_args, extra_args); |
| } |
| |
| TEST_F(BrowserJobTest, CreateArgv) { |
| std::vector<std::string> argv(kArgv, kArgv + arraysize(kArgv)); |
| BrowserJob job(argv, false, -1, &checker_, &metrics_, &utils_); |
| |
| const char* kExtraArgs[] = { "--ichi", "--ni", "--san" }; |
| std::vector<std::string> extra_args(kExtraArgs, |
| kExtraArgs + arraysize(kExtraArgs)); |
| job.SetExtraArguments(extra_args); |
| |
| const char** arg_array = job.CreateArgv(); |
| |
| argv.insert(argv.end(), extra_args.begin(), extra_args.end()); |
| |
| size_t arg_array_size = 0; |
| for (const char** arr = arg_array; *arr != NULL; ++arr) |
| ++arg_array_size; |
| |
| ASSERT_EQ(argv.size(), arg_array_size); |
| for (size_t i = 0; i < argv.size(); ++i) { |
| EXPECT_EQ(argv[i], arg_array[i]); |
| delete [] arg_array[i]; |
| } |
| delete [] arg_array; |
| } |
| |
| } // namespace login_manager |