cc: Make ContentLayerClient subclasses create the DisplayItemList.
[chromium-blink-merge.git] / components / browser_watcher / exit_code_watcher_win_unittest.cc
blobf9d495a324b8c0db11cc3624fe1ba57aba26d4e7
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(StartsWith(it.Name(),
102 base::StringPrintf(L"%d-", proc_id),
103 false));
104 DWORD value = 0;
105 ASSERT_EQ(ERROR_SUCCESS, key.ReadValueDW(it.Name(), &value));
106 ASSERT_EQ(exit_code, value);
109 protected:
110 base::CommandLine cmd_line_;
111 registry_util::RegistryOverrideManager override_manager_;
114 } // namespace
116 TEST_F(ExitCodeWatcherTest, ExitCodeWatcherInvalidHandleFailsInit) {
117 ExitCodeWatcher watcher(kRegistryPath);
119 // A waitable event has a non process-handle.
120 base::Process event(::CreateEvent(NULL, false, false, NULL));
122 // A non-process handle should fail.
123 EXPECT_FALSE(watcher.Initialize(event.Pass()));
126 TEST_F(ExitCodeWatcherTest, ExitCodeWatcherNoAccessHandleFailsInit) {
127 ExitCodeWatcher watcher(kRegistryPath);
129 // Open a SYNCHRONIZE-only handle to this process.
130 base::Process self = OpenSelfWithAccess(SYNCHRONIZE);
131 ASSERT_TRUE(self.IsValid());
133 // A process handle with insufficient access should fail.
134 EXPECT_FALSE(watcher.Initialize(self.Pass()));
137 TEST_F(ExitCodeWatcherTest, ExitCodeWatcherSucceedsInit) {
138 ExitCodeWatcher watcher(kRegistryPath);
140 // Open a handle to this process with sufficient access for the watcher.
141 base::Process self =
142 OpenSelfWithAccess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION);
143 ASSERT_TRUE(self.IsValid());
145 // A process handle with sufficient access should succeed init.
146 EXPECT_TRUE(watcher.Initialize(self.Pass()));
149 TEST_F(ExitCodeWatcherTest, ExitCodeWatcherOnExitedProcess) {
150 ScopedSleeperProcess sleeper;
151 ASSERT_NO_FATAL_FAILURE(sleeper.Launch());
153 ExitCodeWatcher watcher(kRegistryPath);
155 EXPECT_TRUE(watcher.Initialize(sleeper.process().Duplicate()));
157 // Verify that the watcher wrote a sentinel for the process.
158 VerifyWroteExitCode(sleeper.process().Pid(), STILL_ACTIVE);
160 // Kill the sleeper, and make sure it's exited before we continue.
161 ASSERT_NO_FATAL_FAILURE(sleeper.Kill(kExitCode, true));
163 watcher.WaitForExit();
164 EXPECT_EQ(kExitCode, watcher.exit_code());
166 VerifyWroteExitCode(sleeper.process().Pid(), kExitCode);
169 } // namespace browser_watcher