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