Revert "Reland c91b178b07b0d - Delete dead signin code (SigninGlobalError)"
[chromium-blink-merge.git] / components / browser_watcher / exit_code_watcher_win_unittest.cc
blob118cf770a3d3b7190b0b8f807aafaef1ddb71a80
1 // Copyright (c) 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/browser_watcher/exit_code_watcher_win.h"
7 #include "base/command_line.h"
8 #include "base/process/process.h"
9 #include "base/strings/string16.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/synchronization/waitable_event.h"
13 #include "base/test/multiprocess_test.h"
14 #include "base/test/test_reg_util_win.h"
15 #include "base/threading/platform_thread.h"
16 #include "base/time/time.h"
17 #include "base/win/scoped_handle.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "testing/multiprocess_func_list.h"
21 namespace browser_watcher {
23 namespace {
25 const base::char16 kRegistryPath[] = L"Software\\ExitCodeWatcherTest";
27 MULTIPROCESS_TEST_MAIN(Sleeper) {
28 // Sleep forever - the test harness will kill this process to give it an
29 // exit code.
30 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(INFINITE));
31 return 1;
34 class ScopedSleeperProcess {
35 public:
36 ScopedSleeperProcess() : is_killed_(false) {
39 ~ScopedSleeperProcess() {
40 if (process_.IsValid()) {
41 process_.Terminate(-1, false);
42 EXPECT_TRUE(process_.WaitForExit(nullptr));
46 void Launch() {
47 ASSERT_FALSE(process_.IsValid());
49 base::CommandLine cmd_line(base::GetMultiProcessTestChildBaseCommandLine());
50 base::LaunchOptions options;
51 options.start_hidden = true;
52 process_ = base::SpawnMultiProcessTestChild("Sleeper", cmd_line, options);
53 ASSERT_TRUE(process_.IsValid());
56 void Kill(int exit_code, bool wait) {
57 ASSERT_TRUE(process_.IsValid());
58 ASSERT_FALSE(is_killed_);
59 process_.Terminate(exit_code, false);
60 int seen_exit_code = 0;
61 EXPECT_TRUE(process_.WaitForExit(&seen_exit_code));
62 EXPECT_EQ(exit_code, seen_exit_code);
63 is_killed_ = true;
66 const base::Process& process() const { return process_; }
68 private:
69 base::Process process_;
70 bool is_killed_;
73 class ExitCodeWatcherTest : public testing::Test {
74 public:
75 typedef testing::Test Super;
77 static const int kExitCode = 0xCAFEBABE;
79 ExitCodeWatcherTest() : cmd_line_(base::CommandLine::NO_PROGRAM) {}
81 void SetUp() override {
82 Super::SetUp();
84 override_manager_.OverrideRegistry(HKEY_CURRENT_USER);
87 base::Process OpenSelfWithAccess(uint32 access) {
88 return base::Process::OpenWithAccess(base::GetCurrentProcId(), access);
91 void VerifyWroteExitCode(base::ProcessId proc_id, int exit_code) {
92 base::win::RegistryValueIterator it(
93 HKEY_CURRENT_USER, kRegistryPath);
95 ASSERT_EQ(1, it.ValueCount());
96 base::win::RegKey key(HKEY_CURRENT_USER,
97 kRegistryPath,
98 KEY_QUERY_VALUE);
100 // The value name should encode the process id at the start.
101 EXPECT_TRUE(base::StartsWith(
102 it.Name(),
103 base::StringPrintf(L"%d-", proc_id),
104 base::CompareCase::SENSITIVE));
105 DWORD value = 0;
106 ASSERT_EQ(ERROR_SUCCESS, key.ReadValueDW(it.Name(), &value));
107 ASSERT_EQ(exit_code, value);
110 protected:
111 base::CommandLine cmd_line_;
112 registry_util::RegistryOverrideManager override_manager_;
115 } // namespace
117 TEST_F(ExitCodeWatcherTest, ExitCodeWatcherInvalidHandleFailsInit) {
118 ExitCodeWatcher watcher(kRegistryPath);
120 // A waitable event has a non process-handle.
121 base::Process event(::CreateEvent(NULL, false, false, NULL));
123 // A non-process handle should fail.
124 EXPECT_FALSE(watcher.Initialize(event.Pass()));
127 TEST_F(ExitCodeWatcherTest, ExitCodeWatcherNoAccessHandleFailsInit) {
128 ExitCodeWatcher watcher(kRegistryPath);
130 // Open a SYNCHRONIZE-only handle to this process.
131 base::Process self = OpenSelfWithAccess(SYNCHRONIZE);
132 ASSERT_TRUE(self.IsValid());
134 // A process handle with insufficient access should fail.
135 EXPECT_FALSE(watcher.Initialize(self.Pass()));
138 TEST_F(ExitCodeWatcherTest, ExitCodeWatcherSucceedsInit) {
139 ExitCodeWatcher watcher(kRegistryPath);
141 // Open a handle to this process with sufficient access for the watcher.
142 base::Process self =
143 OpenSelfWithAccess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION);
144 ASSERT_TRUE(self.IsValid());
146 // A process handle with sufficient access should succeed init.
147 EXPECT_TRUE(watcher.Initialize(self.Pass()));
150 TEST_F(ExitCodeWatcherTest, ExitCodeWatcherOnExitedProcess) {
151 ScopedSleeperProcess sleeper;
152 ASSERT_NO_FATAL_FAILURE(sleeper.Launch());
154 ExitCodeWatcher watcher(kRegistryPath);
156 EXPECT_TRUE(watcher.Initialize(sleeper.process().Duplicate()));
158 // Verify that the watcher wrote a sentinel for the process.
159 VerifyWroteExitCode(sleeper.process().Pid(), STILL_ACTIVE);
161 // Kill the sleeper, and make sure it's exited before we continue.
162 ASSERT_NO_FATAL_FAILURE(sleeper.Kill(kExitCode, true));
164 watcher.WaitForExit();
165 EXPECT_EQ(kExitCode, watcher.exit_code());
167 VerifyWroteExitCode(sleeper.process().Pid(), kExitCode);
170 } // namespace browser_watcher