Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1768)

Side by Side Diff: components/browser_watcher/watcher_client_win_unittest.cc

Issue 743463002: Browser watcher, part deux. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@lkgr
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.
4
5 #include "components/browser_watcher/watcher_client_win.h"
6
7 #include "base/base_switches.h"
8 #include "base/command_line.h"
9 #include "base/logging.h"
10 #include "base/process/kill.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/test/multiprocess_test.h"
14 #include "base/test/test_reg_util_win.h"
15 #include "base/win/scoped_handle.h"
16 #include "base/win/windows_version.h"
17 #include "components/browser_watcher/watcher_win.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "testing/multiprocess_func_list.h"
20
21 namespace browser_watcher {
22
23 namespace {
24
25 // Command line switches used to communiate to the child test.
26 const char kParentPid[] = "parent-pid";
27 const char kLeakHandle[] = "leak-handle";
28 const char kNoLeakHandle[] = "no-leak-handle";
29
30 bool IsValidParentProcessHandle(base::CommandLine& cmd_line,
31 const char* switch_name) {
32 std::string str_handle =
erikwright (departed) 2014/11/18 20:00:06 include <string>
Sigurður Ásgeirsson 2014/11/18 21:18:57 Done.
33 cmd_line.GetSwitchValueASCII(switch_name);
34
35 unsigned int_handle = 0;
36 if (!base::StringToUint(str_handle, &int_handle))
37 return false;
38
39 int parent_pid = 0;
40 if (!base::StringToInt(cmd_line.GetSwitchValueASCII(kParentPid),
41 &parent_pid)) {
42 return false;
43 }
44
45 base::ProcessHandle handle =
erikwright (departed) 2014/11/18 20:00:06 base/process/process_handle.h
Sigurður Ásgeirsson 2014/11/18 21:18:57 Done.
46 reinterpret_cast<base::ProcessHandle>(int_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;
52 }
53
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;
59 }
60
61 return true;
62 }
63
64 MULTIPROCESS_TEST_MAIN(VerifyParentHandle) {
65 base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
66
67 // Make sure we got a valid parent process handle from the watcher client.
68 if (!IsValidParentProcessHandle(*cmd_line,
69 ExitCodeWatcher::kParenthHandleSwitch)) {
70 LOG(ERROR) << "Invalid or missing parent-handle.";
71 return 1;
72 }
73
74 // If in the legacy mode, we expect this second handle will leak into the
75 // child process. This mainly serves to verify that the legacy mode is
76 // getting tested.
77 if (cmd_line->HasSwitch(kLeakHandle) &&
78 !IsValidParentProcessHandle(*cmd_line, kLeakHandle)) {
79 LOG(ERROR) << "Parent process handle unexpectedly didn't leak.";
80 return 1;
81 }
82
83 // If not in the legacy mode, this second handle should not leak into the
84 // child process.
85 if (cmd_line->HasSwitch(kNoLeakHandle) &&
86 IsValidParentProcessHandle(*cmd_line, kLeakHandle)) {
87 LOG(ERROR) << "Parent process handle unexpectedly leaked.";
88 return 1;
89 }
90
91 return 0;
92 }
93
94 class BrowserWatcherClientTest : public base::MultiProcessTest {
95 public:
96 virtual void SetUp() {
97 // Open an inheritable handle on our own process to test handle leakage.
98 self_.Set(::OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION,
99 TRUE, // Ineritable handle.
100 base::GetCurrentProcId()));
101
102 ASSERT_TRUE(self_.IsValid());
103 }
104
105 enum HandlePolicy {
106 LEAK_HANDLE,
107 NO_LEAK_HANDLE
108 };
109
110 // Get a base command line to launch back into this test fixture.
111 base::CommandLine GetBaseCommandLine(HandlePolicy handle_policy) {
112 base::CommandLine ret = base::GetMultiProcessTestChildBaseCommandLine();
113
114 ret.AppendSwitchASCII(switches::kTestChildProcess, "VerifyParentHandle");
115 ret.AppendSwitchASCII(kParentPid,
116 base::StringPrintf("%d", base::GetCurrentProcId()));
117
118 switch (handle_policy) {
119 case LEAK_HANDLE:
120 ret.AppendSwitchASCII(kLeakHandle,
121 base::StringPrintf("%d", self_.Get()));
122 break;
123
124 case NO_LEAK_HANDLE:
125 ret.AppendSwitchASCII(kNoLeakHandle,
126 base::StringPrintf("%d", self_.Get()));
127 break;
128
129 default:
130 EXPECT_FALSE("Impossible handle_policy");
erikwright (departed) 2014/11/18 20:00:05 ADD_FAILURE() << "..."
Sigurður Ásgeirsson 2014/11/18 21:18:57 Done.
131 }
132
133 return ret;
134 }
135
136 void AssertSuccessfulExitCode(base::ProcessHandle handle) {
137 ASSERT_NE(base::kNullProcessHandle, handle);
138
139 // Duplicate the process handle to work around the fact that
140 // WaitForExitCode closes it(!!!).
141 base::ProcessHandle dupe = NULL;
142 ASSERT_TRUE(::DuplicateHandle(base::GetCurrentProcessHandle(),
143 handle,
144 base::GetCurrentProcessHandle(),
145 &dupe,
146 SYNCHRONIZE | PROCESS_QUERY_INFORMATION,
147 FALSE,
148 0));
149 ASSERT_NE(base::kNullProcessHandle, dupe);
150 int exit_code = 0;
151 if (!base::WaitForExitCode(dupe, &exit_code)) {
152 base::CloseProcessHandle(dupe);
153 FAIL() << "WaitForExitCode failed.";
154 }
155 ASSERT_EQ(0, exit_code);
156 }
157
158 // Inheritable event handle used for testing.
erikwright (departed) 2014/11/18 20:00:05 "event" ?
Sigurður Ásgeirsson 2014/11/18 21:18:57 Done.
159 base::win::ScopedHandle self_;
160 };
161
162 } // namespace
163
164 // TODO(siggi): More testing - test WatcherClient base implementation.
165
166 TEST_F(BrowserWatcherClientTest, LaunchWatcherSucceeds) {
167 // We can only use the non-legacy launch method on Windows Vista or better.
168 if (base::win::GetVersion() < base::win::VERSION_VISTA)
169 return;
170
171 WatcherClient client(GetBaseCommandLine(NO_LEAK_HANDLE));
172 ASSERT_FALSE(client.use_legacy_launch());
173
174 client.LaunchWatcher();
175
176 ASSERT_NO_FATAL_FAILURE(AssertSuccessfulExitCode(client.process()));
177 }
178
179 TEST_F(BrowserWatcherClientTest, LaunchWatcherLegacyModeSucceeds) {
erikwright (departed) 2014/11/18 20:00:06 This test uses a hack to verify that the XP-specif
Sigurður Ásgeirsson 2014/11/18 21:18:57 Good idea!
180 // Test the XP-compatible legacy launch mode. This is expected to leak
181 // a handle to the child process.
182 WatcherClient client(GetBaseCommandLine(LEAK_HANDLE));
183
184 // USe the legacy launch mode.
erikwright (departed) 2014/11/18 20:00:05 USe -> Use
Sigurður Ásgeirsson 2014/11/18 21:18:57 Done.
185 client.set_use_legacy_launch(true);
186
187 client.LaunchWatcher();
188
189 ASSERT_NO_FATAL_FAILURE(AssertSuccessfulExitCode(client.process()));
190 }
191
192 } // namespace browser_watcher
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698