Home | History | Annotate | Download | only in win
      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