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

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

Issue 717223002: Browser watcher end-end-to-end . (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git/+/lkgr
Patch Set: Address Erik's comments. 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/synchronization/waitable_event.h"
14 #include "base/test/multiprocess_test.h"
15 #include "base/test/test_reg_util_win.h"
16 #include "base/threading/platform_thread.h"
17 #include "base/time/time.h"
18 #include "base/win/scoped_handle.h"
19 #include "base/win/windows_version.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 #include "testing/multiprocess_func_list.h"
22
23 namespace browser_watcher {
24
25 namespace {
26
27 // Command line switches used to communiate to the child test.
28 const char kParentPid[] = "parent-pid";
29 const char kLeakHandle[] = "leak-handle";
30 const char kNoLeakHandle[] = "no-leak-handle";
31
32 bool IsValidParentProcessHandle(base::CommandLine& cmd_line,
33 const char* switch_name) {
34 std::string str_handle =
35 cmd_line.GetSwitchValueASCII(switch_name);
36
37 unsigned int_handle = 0;
38 if (!base::StringToUint(str_handle, &int_handle))
39 return false;
40
41 int parent_pid = 0;
42 if (!base::StringToInt(cmd_line.GetSwitchValueASCII(kParentPid),
43 &parent_pid)) {
44 return false;
45 }
46
47 base::ProcessHandle handle =
48 reinterpret_cast<base::ProcessHandle>(int_handle);
49 // Verify that we can get the associated process id.
50 base::ProcessId parent_id = base::GetProcId(handle);
51 if (parent_id == 0) {
52 // Unable to get the parent pid - perhaps insufficient permissions.
53 return false;
54 }
55
56 // Make sure the handle grants SYNCHRONIZE by waiting on it.
57 DWORD err = ::WaitForSingleObject(handle, 0);
58 if (err != WAIT_OBJECT_0 && err != WAIT_TIMEOUT) {
59 // Unable to wait on the handle - perhaps insufficient permissions.
60 return false;
61 }
62
63 return true;
64 }
65
66 MULTIPROCESS_TEST_MAIN(VerifyParentHandle) {
67 base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
68
69 // Make sure we got a valid parent process handle from the watcher client.
70 if (!IsValidParentProcessHandle(*cmd_line, "parent-handle")) {
71 LOG(ERROR) << "Invalid or missing parent-handle.";
72 return 1;
73 }
74
75 // If in the legacy mode, we expect this second handle will leak into the
76 // child process. This mainly serves to verify that the legacy mode is
77 // getting tested.
78 if (cmd_line->HasSwitch(kLeakHandle) &&
79 !IsValidParentProcessHandle(*cmd_line, kLeakHandle)) {
80 LOG(ERROR) << "Parent process handle unexpectedly didn't leak.";
81 return 1;
82 }
83
84 // If not in the legacy mode, this second handle should not leak into the
85 // child process.
86 if (cmd_line->HasSwitch(kNoLeakHandle) &&
87 IsValidParentProcessHandle(*cmd_line, kLeakHandle)) {
88 LOG(ERROR) << "Parent process handle unexpectedly leaked.";
89 return 1;
90 }
91
92 return 0;
93 }
94
95 class BrowserWatcherClientTest : public base::MultiProcessTest {
96 public:
97 virtual void SetUp() {
98 // Open an inheritable handle on our own process to test handle leakage.
99 self_.Set(::OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION,
100 TRUE, // Ineritable handle.
101 base::GetCurrentProcId()));
102
103 ASSERT_TRUE(self_.IsValid());
104 }
105
106 enum HandlePolicy {
107 LEAK_HANDLE,
108 NO_LEAK_HANDLE
109 };
110
111 // Get a base command line to launch back into this test fixture.
112 base::CommandLine GetBaseCommandLine(HandlePolicy handle_policy) {
113 base::CommandLine ret = base::GetMultiProcessTestChildBaseCommandLine();
114
115 ret.AppendSwitchASCII(switches::kTestChildProcess, "VerifyParentHandle");
116 ret.AppendSwitchASCII(kParentPid,
117 base::StringPrintf("%d", base::GetCurrentProcId()));
118
119 switch (handle_policy) {
120 case LEAK_HANDLE:
121 ret.AppendSwitchASCII(kLeakHandle,
122 base::StringPrintf("%d", self_.Get()));
123 break;
124
125 case NO_LEAK_HANDLE:
126 ret.AppendSwitchASCII(kNoLeakHandle,
127 base::StringPrintf("%d", self_.Get()));
128 break;
129
130 default:
131 EXPECT_FALSE("Impossible handle_policy");
132 }
133
134 return ret;
135 }
136
137 void AssertSuccessfulExitCode(base::ProcessHandle handle) {
138 ASSERT_NE(base::kNullProcessHandle, handle);
139
140 // Duplicate the process handle to work around the fact that
141 // WaitForExitCode closes it(!!!).
142 base::ProcessHandle dupe = NULL;
143 ASSERT_TRUE(::DuplicateHandle(base::GetCurrentProcessHandle(),
144 handle,
145 base::GetCurrentProcessHandle(),
146 &dupe,
147 SYNCHRONIZE | PROCESS_QUERY_INFORMATION,
148 FALSE,
149 0));
150 ASSERT_NE(base::kNullProcessHandle, dupe);
151 int exit_code = 0;
152 if (!base::WaitForExitCode(dupe, &exit_code)) {
153 base::CloseProcessHandle(dupe);
154 FAIL() << "WaitForExitCode failed.";
155 }
156 ASSERT_EQ(0, exit_code);
157 }
158
159 // Inheritable event handle used for testing.
160 base::win::ScopedHandle self_;
161 };
162
163 } // namespace
164
165 // TODO(siggi): More testing - test WatcherClient base implementation.
166
167 TEST_F(BrowserWatcherClientTest, LaunchWatcherSucceeds) {
168 // We can only use the non-legacy launch method on Windows Vista or better.
169 if (base::win::GetVersion() < base::win::VERSION_VISTA)
170 return;
171
172 WatcherClient client(GetBaseCommandLine(NO_LEAK_HANDLE));
173 ASSERT_FALSE(client.use_legacy_launch());
174
175 client.LaunchWatcher();
176
177 ASSERT_NO_FATAL_FAILURE(AssertSuccessfulExitCode(client.process()));
178 }
179
180 TEST_F(BrowserWatcherClientTest, LaunchWatcherLegacyModeSucceeds) {
181 // Test the XP-compatible legacy launch mode. This is expected to leak
182 // a handle to the child process.
183 WatcherClient client(GetBaseCommandLine(LEAK_HANDLE));
184
185 // USe the legacy launch mode.
186 client.set_use_legacy_launch(true);
187
188 client.LaunchWatcher();
189
190 ASSERT_NO_FATAL_FAILURE(AssertSuccessfulExitCode(client.process()));
191 }
192
193 } // namespace browser_watcher
OLDNEW
« no previous file with comments | « components/browser_watcher/watcher_client_win.cc ('k') | components/browser_watcher/watcher_main_api_win.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698