Add owners for offlinepages
[chromium-blink-merge.git] / components / browser_watcher / watcher_client_win_unittest.cc
blob45631649b7c99d9b1a600fe9c6d2d926a74616fd
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/watcher_client_win.h"
7 #include <stdint.h>
8 #include <stdlib.h>
10 #include <string>
12 #include "base/base_switches.h"
13 #include "base/bind.h"
14 #include "base/command_line.h"
15 #include "base/logging.h"
16 #include "base/process/kill.h"
17 #include "base/process/process.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/test/multiprocess_test.h"
20 #include "base/test/test_reg_util_win.h"
21 #include "base/win/scoped_handle.h"
22 #include "base/win/windows_version.h"
23 #include "components/browser_watcher/exit_code_watcher_win.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 #include "testing/multiprocess_func_list.h"
27 namespace browser_watcher {
29 namespace {
31 // Command line switches used to communiate to the child test.
32 const char kParentHandle[] = "parent-handle";
33 const char kLeakHandle[] = "leak-handle";
34 const char kNoLeakHandle[] = "no-leak-handle";
36 bool IsValidParentProcessHandle(base::CommandLine& cmd_line,
37 const char* switch_name) {
38 std::string str_handle =
39 cmd_line.GetSwitchValueASCII(switch_name);
41 size_t integer_handle = 0;
42 if (!base::StringToSizeT(str_handle, &integer_handle))
43 return false;
45 base::ProcessHandle handle =
46 reinterpret_cast<base::ProcessHandle>(integer_handle);
47 // Verify that we can get the associated process id.
48 base::ProcessId parent_id = base::GetProcId(handle);
49 if (parent_id == 0) {
50 // Unable to get the parent pid - perhaps insufficient permissions.
51 return false;
54 // Make sure the handle grants SYNCHRONIZE by waiting on it.
55 DWORD err = ::WaitForSingleObject(handle, 0);
56 if (err != WAIT_OBJECT_0 && err != WAIT_TIMEOUT) {
57 // Unable to wait on the handle - perhaps insufficient permissions.
58 return false;
61 return true;
64 std::string HandleToString(HANDLE handle) {
65 // A HANDLE is a void* pointer, which is the same size as a size_t,
66 // so we can use reinterpret_cast<> on it.
67 size_t integer_handle = reinterpret_cast<size_t>(handle);
68 return base::SizeTToString(integer_handle);
71 MULTIPROCESS_TEST_MAIN(VerifyParentHandle) {
72 base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
74 // Make sure we got a valid parent process handle from the watcher client.
75 if (!IsValidParentProcessHandle(*cmd_line, kParentHandle)) {
76 LOG(ERROR) << "Invalid or missing parent-handle.";
77 return 1;
80 // If in the legacy mode, we expect this second handle will leak into the
81 // child process. This mainly serves to verify that the legacy mode is
82 // getting tested.
83 if (cmd_line->HasSwitch(kLeakHandle) &&
84 !IsValidParentProcessHandle(*cmd_line, kLeakHandle)) {
85 LOG(ERROR) << "Parent process handle unexpectedly didn't leak.";
86 return 1;
89 // If not in the legacy mode, this second handle should not leak into the
90 // child process.
91 if (cmd_line->HasSwitch(kNoLeakHandle) &&
92 IsValidParentProcessHandle(*cmd_line, kLeakHandle)) {
93 LOG(ERROR) << "Parent process handle unexpectedly leaked.";
94 return 1;
97 return 0;
100 class WatcherClientTest : public base::MultiProcessTest {
101 public:
102 void SetUp() override {
103 // Open an inheritable handle on our own process to test handle leakage.
104 self_.Set(::OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION,
105 TRUE, // Ineritable handle.
106 base::GetCurrentProcId()));
108 ASSERT_TRUE(self_.IsValid());
111 enum HandlePolicy {
112 LEAK_HANDLE,
113 NO_LEAK_HANDLE
116 // Get a base command line to launch back into this test fixture.
117 base::CommandLine GetBaseCommandLine(HandlePolicy handle_policy,
118 HANDLE parent_handle) {
119 base::CommandLine ret = base::GetMultiProcessTestChildBaseCommandLine();
121 ret.AppendSwitchASCII(switches::kTestChildProcess, "VerifyParentHandle");
122 ret.AppendSwitchASCII(kParentHandle, HandleToString(parent_handle));
124 switch (handle_policy) {
125 case LEAK_HANDLE:
126 ret.AppendSwitchASCII(kLeakHandle, HandleToString(self_.Get()));
127 break;
129 case NO_LEAK_HANDLE:
130 ret.AppendSwitchASCII(kNoLeakHandle, HandleToString(self_.Get()));
131 break;
133 default:
134 ADD_FAILURE() << "Impossible handle_policy";
137 return ret;
140 WatcherClient::CommandLineGenerator GetBaseCommandLineGenerator(
141 HandlePolicy handle_policy) {
142 return base::Bind(&WatcherClientTest::GetBaseCommandLine,
143 base::Unretained(this), handle_policy);
146 void AssertSuccessfulExitCode(base::Process process) {
147 ASSERT_TRUE(process.IsValid());
148 int exit_code = 0;
149 if (!process.WaitForExit(&exit_code))
150 FAIL() << "Process::WaitForExit failed.";
151 ASSERT_EQ(0, exit_code);
154 // Inheritable process handle used for testing.
155 base::win::ScopedHandle self_;
158 } // namespace
160 // TODO(siggi): More testing - test WatcherClient base implementation.
162 TEST_F(WatcherClientTest, LaunchWatcherSucceeds) {
163 // We can only use the non-legacy launch method on Windows Vista or better.
164 if (base::win::GetVersion() < base::win::VERSION_VISTA)
165 return;
167 WatcherClient client(GetBaseCommandLineGenerator(NO_LEAK_HANDLE));
168 ASSERT_FALSE(client.use_legacy_launch());
170 client.LaunchWatcher();
172 ASSERT_NO_FATAL_FAILURE(
173 AssertSuccessfulExitCode(client.process().Duplicate()));
176 TEST_F(WatcherClientTest, LaunchWatcherLegacyModeSucceeds) {
177 // Test the XP-compatible legacy launch mode. This is expected to leak
178 // a handle to the child process.
179 WatcherClient client(GetBaseCommandLineGenerator(LEAK_HANDLE));
181 // Use the legacy launch mode.
182 client.set_use_legacy_launch(true);
184 client.LaunchWatcher();
186 ASSERT_NO_FATAL_FAILURE(
187 AssertSuccessfulExitCode(client.process().Duplicate()));
190 TEST_F(WatcherClientTest, LegacyModeDetectedOnXP) {
191 // This test only works on Windows XP.
192 if (base::win::GetVersion() > base::win::VERSION_XP)
193 return;
195 // Test that the client detects the need to use legacy launch mode, and that
196 // it works on Windows XP.
197 WatcherClient client(GetBaseCommandLineGenerator(LEAK_HANDLE));
198 ASSERT_TRUE(client.use_legacy_launch());
200 client.LaunchWatcher();
202 ASSERT_NO_FATAL_FAILURE(
203 AssertSuccessfulExitCode(client.process().Duplicate()));
206 } // namespace browser_watcher