forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathchrome_watcher_command_line_win_unittest.cc
175 lines (143 loc) · 6.57 KB
/
chrome_watcher_command_line_win_unittest.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
// Copyright (c) 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/app/chrome_watcher_command_line_win.h"
#include <windows.h>
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/process/process.h"
#include "base/process/process_handle.h"
#include "base/win/scoped_handle.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
base::FilePath ExampleExe() {
static const wchar_t kExampleExe[] = FILE_PATH_LITERAL("example.exe");
base::FilePath example_exe(kExampleExe);
return example_exe;
}
} // namespace
class TestChromeWatcherCommandLineGenerator
: public ChromeWatcherCommandLineGenerator {
public:
TestChromeWatcherCommandLineGenerator()
: ChromeWatcherCommandLineGenerator(ExampleExe()) {
}
// In the normal case the generator and interpreter are run in separate
// processes. However, since they are both being run in the same process in
// these tests the handle tracker will explode as they both claim ownership of
// the same handle. This function allows the generator handles to be released
// before they are subsequently claimed by an interpreter.
void ReleaseHandlesWithoutClosing() {
on_initialized_event_handle_.Take();
parent_process_handle_.Take();
}
};
// A fixture for tests that involve parsed command-lines. Contains utility
// functions for standing up a well-configured valid generator.
class ChromeWatcherCommandLineTest : public testing::Test {
public:
ChromeWatcherCommandLineTest()
: cmd_line_(base::CommandLine::NO_PROGRAM) {
}
void GenerateAndInterpretCommandLine() {
process_ = base::Process::OpenWithAccess(
base::GetCurrentProcId(), PROCESS_QUERY_INFORMATION | SYNCHRONIZE);
ASSERT_TRUE(process_.Handle());
event_.Set(::CreateEvent(nullptr, FALSE, FALSE, nullptr));
ASSERT_TRUE(event_.IsValid());
// The above handles are duplicated by the generator.
generator_.SetOnInitializedEventHandle(event_.Get());
generator_.SetParentProcessHandle(process_.Handle());
// Expect there to be two inherited handles created by the generator.
std::vector<HANDLE> handles;
generator_.GetInheritedHandles(&handles);
EXPECT_EQ(2U, handles.size());
cmd_line_ = generator_.GenerateCommandLine();
// In the normal case the generator and interpreter are run in separate
// processes. However, since they are both being run in the same process in
// this test that will lead to both the generator and the interpreter
// claiming ownership of the same handles, as far as the handle tracker is
// concerned. To prevent this the handles are first released from tracking
// by the generator.
generator_.ReleaseHandlesWithoutClosing();
interpreted_ = ChromeWatcherCommandLine::InterpretCommandLine(cmd_line_);
EXPECT_TRUE(interpreted_);
}
base::Process process_;
base::win::ScopedHandle event_;
TestChromeWatcherCommandLineGenerator generator_;
base::CommandLine cmd_line_;
std::unique_ptr<ChromeWatcherCommandLine> interpreted_;
};
// The corresponding death test fixture.
using ChromeWatcherCommandLineDeathTest = ChromeWatcherCommandLineTest;
TEST(ChromeWatcherCommandLineGeneratorTest, UseOfBadHandlesFails) {
// Handles are always machine word aligned so there is no way these are valid.
HANDLE bad_handle_1 = reinterpret_cast<HANDLE>(0x01FC00B1);
HANDLE bad_handle_2 = reinterpret_cast<HANDLE>(0x01FC00B3);
// The above handles are duplicated by the generator.
TestChromeWatcherCommandLineGenerator generator;
EXPECT_FALSE(generator.SetOnInitializedEventHandle(bad_handle_1));
EXPECT_FALSE(generator.SetParentProcessHandle(bad_handle_2));
// Expect there to be no inherited handles created by the generator.
std::vector<HANDLE> handles;
generator.GetInheritedHandles(&handles);
EXPECT_TRUE(handles.empty());
}
TEST(ChromeWatcherCommandLineGeneratorTest, BadCommandLineFailsInterpretation) {
// Create an invalid command-line that is missing several fields.
base::CommandLine cmd_line(ExampleExe());
// Parse the command line.
auto interpreted = ChromeWatcherCommandLine::InterpretCommandLine(cmd_line);
EXPECT_FALSE(interpreted);
}
TEST_F(ChromeWatcherCommandLineDeathTest, HandlesLeftUntakenCausesDeath) {
EXPECT_NO_FATAL_FAILURE(GenerateAndInterpretCommandLine());
// Leave the handles in the interpreter and expect it to explode upon
// destruction.
// String arguments aren't passed to CHECK() in official builds.
#if defined(OFFICIAL_BUILD) && defined(NDEBUG)
EXPECT_DEATH(interpreted_.reset(), "");
#else
EXPECT_DEATH(interpreted_.reset(), "Handles left untaken.");
#endif
// The above call to the destructor only runs in the context of the death test
// child process. To prevent the parent process from exploding in a similar
// fashion, release the handles so the destructor is happy.
interpreted_->TakeOnInitializedEventHandle().Close();
interpreted_->TakeParentProcessHandle().Close();
}
TEST_F(ChromeWatcherCommandLineTest, SuccessfulParse) {
EXPECT_NO_FATAL_FAILURE(GenerateAndInterpretCommandLine());
EXPECT_EQ(::GetCurrentThreadId(), interpreted_->main_thread_id());
// Explicitly take the handles from the interpreter so it doesn't explode.
base::win::ScopedHandle on_init =
interpreted_->TakeOnInitializedEventHandle();
base::win::ScopedHandle proc = interpreted_->TakeParentProcessHandle();
EXPECT_TRUE(on_init.IsValid());
EXPECT_TRUE(proc.IsValid());
}
// TODO(chrisha): Remove this test upon switching to using the new command-line
// classes.
TEST(OldChromeWatcherCommandLineTest, BasicTest) {
// Ownership of these handles is passed to the ScopedHandles below via
// InterpretChromeWatcherCommandLine().
base::ProcessHandle current =
::OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
TRUE, // Inheritable.
::GetCurrentProcessId());
ASSERT_NE(nullptr, current);
HANDLE event = ::CreateEvent(nullptr, FALSE, FALSE, nullptr);
ASSERT_NE(nullptr, event);
DWORD current_thread_id = ::GetCurrentThreadId();
base::CommandLine cmd_line = GenerateChromeWatcherCommandLine(
ExampleExe(), current, current_thread_id, event);
base::win::ScopedHandle current_result;
DWORD current_thread_id_result = 0;
base::win::ScopedHandle event_result;
ASSERT_TRUE(InterpretChromeWatcherCommandLine(
cmd_line, ¤t_result, ¤t_thread_id_result, &event_result));
ASSERT_EQ(current, current_result.Get());
ASSERT_EQ(current_thread_id, current_thread_id_result);
ASSERT_EQ(event, event_result.Get());
}