1 // Copyright (c) 2012 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 <windows.h> 6 7 #include <string> 8 9 #include "base/command_line.h" 10 #include "base/process/kill.h" 11 #include "base/test/multiprocess_test.h" 12 #include "base/win/scoped_process_information.h" 13 #include "testing/multiprocess_func_list.h" 14 15 namespace { 16 17 const DWORD kProcessId = 4321; 18 const DWORD kThreadId = 1234; 19 const HANDLE kProcessHandle = reinterpret_cast<HANDLE>(7651); 20 const HANDLE kThreadHandle = reinterpret_cast<HANDLE>(1567); 21 22 void MockCreateProcess(PROCESS_INFORMATION* process_info) { 23 process_info->dwProcessId = kProcessId; 24 process_info->dwThreadId = kThreadId; 25 process_info->hProcess = kProcessHandle; 26 process_info->hThread = kThreadHandle; 27 } 28 29 } // namespace 30 31 class ScopedProcessInformationTest : public base::MultiProcessTest { 32 protected: 33 void DoCreateProcess(const std::string& main_id, 34 PROCESS_INFORMATION* process_handle); 35 }; 36 37 MULTIPROCESS_TEST_MAIN(ReturnSeven) { 38 return 7; 39 } 40 41 MULTIPROCESS_TEST_MAIN(ReturnNine) { 42 return 9; 43 } 44 45 void ScopedProcessInformationTest::DoCreateProcess( 46 const std::string& main_id, PROCESS_INFORMATION* process_handle) { 47 std::wstring cmd_line = 48 this->MakeCmdLine(main_id, false).GetCommandLineString(); 49 STARTUPINFO startup_info = {}; 50 startup_info.cb = sizeof(startup_info); 51 52 EXPECT_TRUE(::CreateProcess(NULL, 53 const_cast<wchar_t*>(cmd_line.c_str()), 54 NULL, NULL, false, 0, NULL, NULL, 55 &startup_info, process_handle)); 56 } 57 58 TEST_F(ScopedProcessInformationTest, InitiallyInvalid) { 59 base::win::ScopedProcessInformation process_info; 60 ASSERT_FALSE(process_info.IsValid()); 61 } 62 63 TEST_F(ScopedProcessInformationTest, Receive) { 64 base::win::ScopedProcessInformation process_info; 65 MockCreateProcess(process_info.Receive()); 66 67 EXPECT_TRUE(process_info.IsValid()); 68 EXPECT_EQ(kProcessId, process_info.process_id()); 69 EXPECT_EQ(kThreadId, process_info.thread_id()); 70 EXPECT_EQ(kProcessHandle, process_info.process_handle()); 71 EXPECT_EQ(kThreadHandle, process_info.thread_handle()); 72 PROCESS_INFORMATION to_discard = process_info.Take(); 73 } 74 75 TEST_F(ScopedProcessInformationTest, TakeProcess) { 76 base::win::ScopedProcessInformation process_info; 77 MockCreateProcess(process_info.Receive()); 78 79 HANDLE process = process_info.TakeProcessHandle(); 80 EXPECT_EQ(kProcessHandle, process); 81 EXPECT_EQ(NULL, process_info.process_handle()); 82 EXPECT_EQ(0, process_info.process_id()); 83 EXPECT_TRUE(process_info.IsValid()); 84 PROCESS_INFORMATION to_discard = process_info.Take(); 85 } 86 87 TEST_F(ScopedProcessInformationTest, TakeThread) { 88 base::win::ScopedProcessInformation process_info; 89 MockCreateProcess(process_info.Receive()); 90 91 HANDLE thread = process_info.TakeThreadHandle(); 92 EXPECT_EQ(kThreadHandle, thread); 93 EXPECT_EQ(NULL, process_info.thread_handle()); 94 EXPECT_EQ(0, process_info.thread_id()); 95 EXPECT_TRUE(process_info.IsValid()); 96 PROCESS_INFORMATION to_discard = process_info.Take(); 97 } 98 99 TEST_F(ScopedProcessInformationTest, TakeBoth) { 100 base::win::ScopedProcessInformation process_info; 101 MockCreateProcess(process_info.Receive()); 102 103 HANDLE process = process_info.TakeProcessHandle(); 104 HANDLE thread = process_info.TakeThreadHandle(); 105 EXPECT_FALSE(process_info.IsValid()); 106 PROCESS_INFORMATION to_discard = process_info.Take(); 107 } 108 109 TEST_F(ScopedProcessInformationTest, TakeWholeStruct) { 110 base::win::ScopedProcessInformation process_info; 111 MockCreateProcess(process_info.Receive()); 112 113 PROCESS_INFORMATION to_discard = process_info.Take(); 114 EXPECT_EQ(kProcessId, to_discard.dwProcessId); 115 EXPECT_EQ(kThreadId, to_discard.dwThreadId); 116 EXPECT_EQ(kProcessHandle, to_discard.hProcess); 117 EXPECT_EQ(kThreadHandle, to_discard.hThread); 118 EXPECT_FALSE(process_info.IsValid()); 119 } 120 121 TEST_F(ScopedProcessInformationTest, Duplicate) { 122 base::win::ScopedProcessInformation process_info; 123 DoCreateProcess("ReturnSeven", process_info.Receive()); 124 base::win::ScopedProcessInformation duplicate; 125 duplicate.DuplicateFrom(process_info); 126 127 ASSERT_TRUE(process_info.IsValid()); 128 ASSERT_NE(0u, process_info.process_id()); 129 ASSERT_EQ(duplicate.process_id(), process_info.process_id()); 130 ASSERT_NE(0u, process_info.thread_id()); 131 ASSERT_EQ(duplicate.thread_id(), process_info.thread_id()); 132 133 // Validate that we have separate handles that are good. 134 int exit_code = 0; 135 ASSERT_TRUE(base::WaitForExitCode(process_info.TakeProcessHandle(), 136 &exit_code)); 137 ASSERT_EQ(7, exit_code); 138 139 exit_code = 0; 140 ASSERT_TRUE(base::WaitForExitCode(duplicate.TakeProcessHandle(), 141 &exit_code)); 142 ASSERT_EQ(7, exit_code); 143 144 ASSERT_TRUE(::CloseHandle(process_info.TakeThreadHandle())); 145 ASSERT_TRUE(::CloseHandle(duplicate.TakeThreadHandle())); 146 } 147 148 TEST_F(ScopedProcessInformationTest, Set) { 149 PROCESS_INFORMATION base_process_info = {}; 150 MockCreateProcess(&base_process_info); 151 152 base::win::ScopedProcessInformation process_info; 153 process_info.Set(base_process_info); 154 155 EXPECT_EQ(kProcessId, process_info.process_id()); 156 EXPECT_EQ(kThreadId, process_info.thread_id()); 157 EXPECT_EQ(kProcessHandle, process_info.process_handle()); 158 EXPECT_EQ(kThreadHandle, process_info.thread_handle()); 159 base_process_info = process_info.Take(); 160 } 161