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
15namespace {
16
17const DWORD kProcessId = 4321;
18const DWORD kThreadId = 1234;
19const HANDLE kProcessHandle = reinterpret_cast<HANDLE>(7651);
20const HANDLE kThreadHandle = reinterpret_cast<HANDLE>(1567);
21
22void 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
31class ScopedProcessInformationTest : public base::MultiProcessTest {
32 protected:
33  void DoCreateProcess(const std::string& main_id,
34                       PROCESS_INFORMATION* process_handle);
35};
36
37MULTIPROCESS_TEST_MAIN(ReturnSeven) {
38  return 7;
39}
40
41MULTIPROCESS_TEST_MAIN(ReturnNine) {
42  return 9;
43}
44
45void 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
58TEST_F(ScopedProcessInformationTest, InitiallyInvalid) {
59  base::win::ScopedProcessInformation process_info;
60  ASSERT_FALSE(process_info.IsValid());
61}
62
63TEST_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
75TEST_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
87TEST_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
99TEST_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
109TEST_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
121TEST_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
148TEST_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