| OLD | NEW |
| 1 // Copyright 2015 The Crashpad Authors. All rights reserved. | 1 // Copyright 2015 The Crashpad Authors. All rights reserved. |
| 2 // | 2 // |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 // you may not use this file except in compliance with the License. | 4 // you may not use this file except in compliance with the License. |
| 5 // You may obtain a copy of the License at | 5 // You may obtain a copy of the License at |
| 6 // | 6 // |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 // | 8 // |
| 9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 // See the License for the specific language governing permissions and | 12 // See the License for the specific language governing permissions and |
| 13 // limitations under the License. | 13 // limitations under the License. |
| 14 | 14 |
| 15 #ifndef CRASHPAD_TEST_WIN_WIN_MULTIPROCESS_H_ | 15 #ifndef CRASHPAD_TEST_WIN_WIN_MULTIPROCESS_H_ |
| 16 #define CRASHPAD_TEST_WIN_WIN_MULTIPROCESS_H_ | 16 #define CRASHPAD_TEST_WIN_WIN_MULTIPROCESS_H_ |
| 17 | 17 |
| 18 #include <windows.h> | 18 #include <windows.h> |
| 19 | 19 |
| 20 #include "base/basictypes.h" | 20 #include "base/basictypes.h" |
| 21 #include "gtest/gtest.h" |
| 22 #include "test/win/win_child_process.h" |
| 21 #include "util/file/file_io.h" | 23 #include "util/file/file_io.h" |
| 22 #include "util/win/scoped_handle.h" | 24 #include "util/win/scoped_handle.h" |
| 23 | 25 |
| 24 namespace crashpad { | 26 namespace crashpad { |
| 25 namespace test { | 27 namespace test { |
| 26 | 28 |
| 27 //! \brief Manages a multiprocess test on Windows. | 29 //! \brief Manages a multiprocess test on Windows. |
| 28 class WinMultiprocess { | 30 class WinMultiprocess { |
| 29 public: | 31 public: |
| 30 WinMultiprocess(); | 32 WinMultiprocess(); |
| 31 | 33 |
| 32 //! \brief Runs the test. | 34 //! \brief Runs the test. |
| 33 //! | 35 //! |
| 34 //! This method establishes the testing environment by respawning the process | 36 //! This method establishes the testing environment by respawning the process |
| 35 //! as a child with additional flags. | 37 //! as a child with additional flags. |
| 36 //! | 38 //! |
| 37 //! In the parent process, WinMultiprocessParent() is run, and in the child | 39 //! In the parent process, WinMultiprocessParent() is run, and in the child |
| 38 //! WinMultiprocessChild(). | 40 //! WinMultiprocessChild(). |
| 39 void Run(); | 41 template <class T> |
| 42 static void Run() { |
| 43 ASSERT_NO_FATAL_FAILURE( |
| 44 WinChildProcess::EntryPoint<ChildProcessHelper<T>>()); |
| 45 // If WinChildProcess::EntryPoint returns, we are in the parent process. |
| 46 scoped_ptr<WinChildProcess::Handles> child_handles = |
| 47 WinChildProcess::Launch(); |
| 48 ASSERT_TRUE(child_handles.get()); |
| 49 T parent_process; |
| 50 parent_process.child_handles_ = child_handles.get(); |
| 51 static_cast<WinMultiprocess*>(&parent_process)->WinMultiprocessParent(); |
| 52 |
| 53 // Close our side of the handles now that we're done. The child can |
| 54 // use this to know when it's safe to complete. |
| 55 child_handles->read.reset(); |
| 56 child_handles->write.reset(); |
| 57 |
| 58 // Wait for the child to complete. |
| 59 ASSERT_EQ(WAIT_OBJECT_0, |
| 60 WaitForSingleObject(child_handles->process.get(), INFINITE)); |
| 61 |
| 62 DWORD exit_code; |
| 63 ASSERT_TRUE(GetExitCodeProcess(child_handles->process.get(), &exit_code)); |
| 64 ASSERT_EQ(parent_process.exit_code_, exit_code); |
| 65 } |
| 66 |
| 67 protected: |
| 68 virtual ~WinMultiprocess(); |
| 40 | 69 |
| 41 //! \brief Sets the expected exit code of the child process. | 70 //! \brief Sets the expected exit code of the child process. |
| 42 //! | 71 //! |
| 43 //! The default expected termination code is `EXIT_SUCCESS` (`0`). | 72 //! The default expected termination code is `EXIT_SUCCESS` (`0`). |
| 44 //! | 73 //! |
| 45 //! \param[in] code The expected exit status of the child. | 74 //! \param[in] code The expected exit status of the child. |
| 46 void SetExpectedChildExitCode(unsigned int exit_code); | 75 void SetExpectedChildExitCode(unsigned int exit_code); |
| 47 | 76 |
| 48 protected: | |
| 49 virtual ~WinMultiprocess(); | |
| 50 | |
| 51 //! \brief Returns the read pipe's file handle. | 77 //! \brief Returns the read pipe's file handle. |
| 52 //! | 78 //! |
| 53 //! This method may be called by either the parent or the child process. | 79 //! This method may be called by either the parent or the child process. |
| 54 //! Anything written to the write pipe in the partner process will appear | 80 //! Anything written to the write pipe in the partner process will appear |
| 55 //! on this file handle in this process. | 81 //! on this file handle in this process. |
| 56 //! | 82 //! |
| 57 //! It is an error to call this after CloseReadPipe() has been called. | 83 //! It is an error to call this after CloseReadPipe() has been called. |
| 58 //! | 84 //! |
| 59 //! \return The read pipe's file handle. | 85 //! \return The read pipe's file handle. |
| 60 FileHandle ReadPipeHandle() const; | 86 FileHandle ReadPipeHandle() const; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 82 //! attempt to read from the read pipe in the partner process will indicate | 108 //! attempt to read from the read pipe in the partner process will indicate |
| 83 //! end-of-file. WritePipeHandle() must not be called after this. | 109 //! end-of-file. WritePipeHandle() must not be called after this. |
| 84 void CloseWritePipe(); | 110 void CloseWritePipe(); |
| 85 | 111 |
| 86 //! \brief Returns a handle to the child process. | 112 //! \brief Returns a handle to the child process. |
| 87 //! | 113 //! |
| 88 //! This method may only be called by the parent process. | 114 //! This method may only be called by the parent process. |
| 89 HANDLE ChildProcess() const; | 115 HANDLE ChildProcess() const; |
| 90 | 116 |
| 91 private: | 117 private: |
| 118 // Implements an adapter to provide WinMultiprocess with access to the |
| 119 // anonymous pipe handles from WinChildProcess. |
| 120 class ChildProcessHelperBase : public WinChildProcess { |
| 121 public: |
| 122 ChildProcessHelperBase() {} |
| 123 ~ChildProcessHelperBase() override {} |
| 124 |
| 125 void CloseWritePipeForwarder() { CloseWritePipe(); } |
| 126 void CloseReadPipeForwarder() { CloseReadPipe(); } |
| 127 FileHandle ReadPipeHandleForwarder() const { return ReadPipeHandle(); } |
| 128 FileHandle WritePipeHandleForwarder() const { return WritePipeHandle(); } |
| 129 |
| 130 private: |
| 131 DISALLOW_COPY_AND_ASSIGN(ChildProcessHelperBase); |
| 132 }; |
| 133 |
| 134 // Forwards WinChildProcess::Run to T::WinMultiprocessChild. |
| 135 template <class T> |
| 136 class ChildProcessHelper : public ChildProcessHelperBase { |
| 137 public: |
| 138 ChildProcessHelper() {} |
| 139 ~ChildProcessHelper() override {} |
| 140 |
| 141 private: |
| 142 int Run() override { |
| 143 T child_process; |
| 144 child_process.child_process_helper_ = this; |
| 145 static_cast<WinMultiprocess*>(&child_process)->WinMultiprocessChild(); |
| 146 if (testing::Test::HasFailure()) |
| 147 return 255; |
| 148 return EXIT_SUCCESS; |
| 149 } |
| 150 |
| 151 DISALLOW_COPY_AND_ASSIGN(ChildProcessHelper); |
| 152 }; |
| 153 |
| 92 //! \brief The subclass-provided parent routine. | 154 //! \brief The subclass-provided parent routine. |
| 93 //! | 155 //! |
| 94 //! Test failures should be reported via gtest: `EXPECT_*()`, `ASSERT_*()`, | 156 //! Test failures should be reported via gtest: `EXPECT_*()`, `ASSERT_*()`, |
| 95 //! `FAIL()`, etc. | 157 //! `FAIL()`, etc. |
| 96 //! | 158 //! |
| 97 //! This method need not use `WaitForSingleObject()`-family call to wait for | 159 //! This method need not use `WaitForSingleObject()`-family call to wait for |
| 98 //! the child process to exit, as this is handled by this class. | 160 //! the child process to exit, as this is handled by this class. |
| 99 //! | 161 //! |
| 100 //! Subclasses must implement this method to define how the parent operates. | 162 //! Subclasses must implement this method to define how the parent operates. |
| 101 virtual void WinMultiprocessParent() = 0; | 163 virtual void WinMultiprocessParent() = 0; |
| 102 | 164 |
| 103 //! \brief The subclass-provided child routine. | 165 //! \brief The subclass-provided child routine. |
| 104 //! | 166 //! |
| 105 //! Test failures should be reported via gtest: `EXPECT_*()`, `ASSERT_*()`, | 167 //! Test failures should be reported via gtest: `EXPECT_*()`, `ASSERT_*()`, |
| 106 //! `FAIL()`, etc. | 168 //! `FAIL()`, etc. |
| 107 //! | 169 //! |
| 108 //! Subclasses must implement this method to define how the child operates. | 170 //! Subclasses must implement this method to define how the child operates. |
| 109 //! Subclasses may exit with a failure status by using `LOG(FATAL)`, | 171 //! Subclasses may exit with a failure status by using `LOG(FATAL)`, |
| 110 //! `abort()`, or similar. They may exit cleanly by returning from this | 172 //! `abort()`, or similar. They may exit cleanly by returning from this |
| 111 //! method. | 173 //! method. |
| 112 virtual void WinMultiprocessChild() = 0; | 174 virtual void WinMultiprocessChild() = 0; |
| 113 | 175 |
| 114 ScopedFileHANDLE pipe_c2p_read_; | |
| 115 ScopedFileHANDLE pipe_c2p_write_; | |
| 116 ScopedFileHANDLE pipe_p2c_read_; | |
| 117 ScopedFileHANDLE pipe_p2c_write_; | |
| 118 ScopedKernelHANDLE child_handle_; | |
| 119 unsigned int exit_code_; | 176 unsigned int exit_code_; |
| 177 WinChildProcess::Handles* child_handles_; |
| 178 ChildProcessHelperBase* child_process_helper_; |
| 120 | 179 |
| 121 DISALLOW_COPY_AND_ASSIGN(WinMultiprocess); | 180 DISALLOW_COPY_AND_ASSIGN(WinMultiprocess); |
| 122 }; | 181 }; |
| 123 | 182 |
| 124 } // namespace test | 183 } // namespace test |
| 125 } // namespace crashpad | 184 } // namespace crashpad |
| 126 | 185 |
| 127 #endif // CRASHPAD_TEST_WIN_WIN_MULTIPROCESS_H_ | 186 #endif // CRASHPAD_TEST_WIN_WIN_MULTIPROCESS_H_ |
| OLD | NEW |