OLD | NEW |
| (Empty) |
1 // Copyright 2014 The Crashpad Authors. All rights reserved. | |
2 // | |
3 // Licensed under the Apache License, Version 2.0 (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 | |
6 // | |
7 // http://www.apache.org/licenses/LICENSE-2.0 | |
8 // | |
9 // Unless required by applicable law or agreed to in writing, software | |
10 // distributed under the License is distributed on an "AS IS" BASIS, | |
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 // See the License for the specific language governing permissions and | |
13 // limitations under the License. | |
14 | |
15 #ifndef CRASHPAD_UTIL_TEST_MULTIPROCESS_H_ | |
16 #define CRASHPAD_UTIL_TEST_MULTIPROCESS_H_ | |
17 | |
18 #include <sys/types.h> | |
19 | |
20 #include "base/basictypes.h" | |
21 #include "build/build_config.h" | |
22 #include "util/file/file_io.h" | |
23 | |
24 namespace crashpad { | |
25 namespace test { | |
26 | |
27 namespace internal { | |
28 struct MultiprocessInfo; | |
29 }; | |
30 | |
31 //! \brief Manages a multiprocess test. | |
32 //! | |
33 //! These tests are `fork()`-based. The parent and child processes are able to | |
34 //! communicate via a pair of POSIX pipes. | |
35 //! | |
36 //! Subclasses are expected to implement the parent and child by overriding the | |
37 //! appropriate methods. | |
38 //! | |
39 //! On Windows, this class is only an internal implementation detail of | |
40 //! MultiprocessExec and all tests must use that class. | |
41 class Multiprocess { | |
42 public: | |
43 //! \brief The termination type for a child process. | |
44 enum TerminationReason : bool { | |
45 //! \brief The child terminated normally. | |
46 //! | |
47 //! A normal return happens when a test returns from RunChild(), or for | |
48 //! tests that `exec()`, returns from `main()`. This also happens for tests | |
49 //! that call `exit()` or `_exit()`. | |
50 kTerminationNormal = false, | |
51 | |
52 //! \brief The child terminated by signal. | |
53 //! | |
54 //! Signal termination happens as a result of a crash, a call to `abort()`, | |
55 //! assertion failure (including gtest assertions), etc. | |
56 kTerminationSignal, | |
57 }; | |
58 | |
59 Multiprocess(); | |
60 | |
61 //! \brief Runs the test. | |
62 //! | |
63 //! This method establishes the proper testing environment by calling | |
64 //! PreFork(), then calls `fork()`. In the parent process, it calls | |
65 //! RunParent(), and in the child process, it calls RunChild(). | |
66 //! | |
67 //! This method uses gtest assertions to validate the testing environment. If | |
68 //! the testing environment cannot be set up properly, it is possible that | |
69 //! MultiprocessParent() or MultiprocessChild() will not be called. In the | |
70 //! parent process, this method also waits for the child process to exit after | |
71 //! MultiprocessParent() returns, and verifies that it exited in accordance | |
72 //! with the expectations set by SetExpectedChildTermination(). | |
73 void Run(); | |
74 | |
75 //! \brief Sets the expected termination reason and code. | |
76 //! | |
77 //! The default expected termination reasaon is | |
78 //! TerminationReason::kTerminationNormal, and the default expected | |
79 //! termination code is `EXIT_SUCCESS` (`0`). | |
80 //! | |
81 //! \param[in] reason Whether to expect the child to terminate normally or | |
82 //! as a result of a signal. | |
83 //! \param[in] code If \a reason is TerminationReason::kTerminationNormal, | |
84 //! this is the expected exit status of the child. If \a reason is | |
85 //! TerminationReason::kTerminationSignal, this is the signal that is | |
86 //! expected to kill the child. | |
87 void SetExpectedChildTermination(TerminationReason reason, int code); | |
88 | |
89 protected: | |
90 ~Multiprocess(); | |
91 | |
92 //! \brief Establishes the proper testing environment prior to forking. | |
93 //! | |
94 //! Subclasses that solely implement a test should not need to override this | |
95 //! method. Subclasses that do not implement tests but instead implement | |
96 //! additional testing features on top of this class may override this method | |
97 //! provided that they call the superclass’ implementation first as follows: | |
98 //! | |
99 //! \code | |
100 //! void PreFork() override { | |
101 //! ASSERT_NO_FATAL_FAILURE(Multiprocess::PreFork()); | |
102 //! | |
103 //! // Place subclass-specific pre-fork code here. | |
104 //! } | |
105 //! \endcode | |
106 //! | |
107 //! Subclass implementations may signal failure by raising their own fatal | |
108 //! gtest assertions. | |
109 virtual void PreFork(); | |
110 | |
111 #if !defined(OS_WIN) | |
112 //! \brief Returns the child process’ process ID. | |
113 //! | |
114 //! This method may only be called by the parent process. | |
115 pid_t ChildPID() const; | |
116 #endif // !OS_WIN | |
117 | |
118 //! \brief Returns the read pipe’s file handle. | |
119 //! | |
120 //! This method may be called by either the parent or the child process. | |
121 //! Anything written to the write pipe in the partner process will appear | |
122 //! on this file handle in this process. | |
123 //! | |
124 //! It is an error to call this after CloseReadPipe() has been called. | |
125 //! | |
126 //! \return The read pipe’s file handle. | |
127 FileHandle ReadPipeHandle() const; | |
128 | |
129 //! \brief Returns the write pipe’s file handle. | |
130 //! | |
131 //! This method may be called by either the parent or the child process. | |
132 //! Anything written to this file handle in this process will appear on | |
133 //! the read pipe in the partner process. | |
134 //! | |
135 //! It is an error to call this after CloseWritePipe() has been called. | |
136 //! | |
137 //! \return The write pipe’s file handle. | |
138 FileHandle WritePipeHandle() const; | |
139 | |
140 //! \brief Closes the read pipe. | |
141 //! | |
142 //! This method may be called by either the parent or the child process. An | |
143 //! attempt to write to the write pipe in the partner process will fail with | |
144 //! `EPIPE` or `SIGPIPE`. ReadPipeHandle() must not be called after this. | |
145 void CloseReadPipe(); | |
146 | |
147 //! \brief Closes the write pipe. | |
148 //! | |
149 //! This method may be called by either the parent or the child process. An | |
150 //! attempt to read from the read pipe in the partner process will indicate | |
151 //! end-of-file. WritePipeHandle() must not be called after this. | |
152 void CloseWritePipe(); | |
153 | |
154 void set_info(internal::MultiprocessInfo* info) { info_ = info; } | |
155 internal::MultiprocessInfo* info() { return info_; } | |
156 | |
157 private: | |
158 //! \brief Runs the parent side of the test. | |
159 //! | |
160 //! This method establishes the parent’s environment and calls | |
161 //! MultiprocessParent(). | |
162 void RunParent(); | |
163 | |
164 //! \brief Runs the child side of the test. | |
165 //! | |
166 //! This method establishes the child’s environment, calls | |
167 //! MultiprocessChild(), and exits cleanly by calling `_exit(0)`. However, if | |
168 //! any failure (via fatal or nonfatal gtest assertion) is detected, the child | |
169 //! will exit with a failure status. | |
170 void RunChild(); | |
171 | |
172 //! \brief The subclass-provided parent routine. | |
173 //! | |
174 //! Test failures should be reported via gtest: `EXPECT_*()`, `ASSERT_*()`, | |
175 //! `FAIL()`, etc. | |
176 //! | |
177 //! This method must not use a `wait()`-family system call to wait for the | |
178 //! child process to exit, as this is handled by this class. | |
179 //! | |
180 //! Subclasses must implement this method to define how the parent operates. | |
181 virtual void MultiprocessParent() = 0; | |
182 | |
183 //! \brief The subclass-provided child routine. | |
184 //! | |
185 //! Test failures should be reported via gtest: `EXPECT_*()`, `ASSERT_*()`, | |
186 //! `FAIL()`, etc. | |
187 //! | |
188 //! Subclasses must implement this method to define how the child operates. | |
189 //! Subclasses may exit with a failure status by using `LOG(FATAL)`, | |
190 //! `abort()`, or similar. They may exit cleanly by returning from this method | |
191 //! or by calling `_exit(0)`. Under no circumstances may `exit()` be called | |
192 //! by the child without having the child process `exec()`. Use | |
193 //! MultiprocessExec if the child should call `exec()`. | |
194 virtual void MultiprocessChild() = 0; | |
195 | |
196 internal::MultiprocessInfo* info_; | |
197 int code_; | |
198 TerminationReason reason_; | |
199 | |
200 DISALLOW_COPY_AND_ASSIGN(Multiprocess); | |
201 }; | |
202 | |
203 } // namespace test | |
204 } // namespace crashpad | |
205 | |
206 #endif // CRASHPAD_UTIL_TEST_MULTIPROCESS_H_ | |
OLD | NEW |