1 // Copyright 2016 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 #ifndef MOJO_EDK_TEST_MOJO_TEST_BASE_H_ 6 #define MOJO_EDK_TEST_MOJO_TEST_BASE_H_ 7 8 #include <memory> 9 #include <string> 10 #include <utility> 11 12 #include "base/bind.h" 13 #include "base/callback.h" 14 #include "base/logging.h" 15 #include "base/macros.h" 16 #include "base/memory/ref_counted.h" 17 #include "mojo/edk/embedder/embedder.h" 18 #include "mojo/edk/test/multiprocess_test_helper.h" 19 #include "mojo/public/c/system/types.h" 20 #include "mojo/public/cpp/system/message_pipe.h" 21 #include "testing/gtest/include/gtest/gtest.h" 22 23 namespace mojo { 24 namespace edk { 25 namespace test { 26 27 class MojoTestBase : public testing::Test { 28 public: 29 MojoTestBase(); 30 ~MojoTestBase() override; 31 32 using LaunchType = MultiprocessTestHelper::LaunchType; 33 34 protected: 35 using HandlerCallback = base::Callback<void(ScopedMessagePipeHandle)>; 36 37 class ClientController { 38 public: 39 ClientController(const std::string& client_name, 40 MojoTestBase* test, 41 const ProcessErrorCallback& process_error_callback, 42 LaunchType launch_type); 43 ~ClientController(); 44 45 MojoHandle pipe() const { return pipe_.get().value(); } 46 47 void ClosePeerConnection(); 48 int WaitForShutdown(); 49 50 private: 51 friend class MojoTestBase; 52 53 #if !defined(OS_IOS) 54 MultiprocessTestHelper helper_; 55 #endif 56 ScopedMessagePipeHandle pipe_; 57 bool was_shutdown_ = false; 58 59 DISALLOW_COPY_AND_ASSIGN(ClientController); 60 }; 61 62 // Set the callback to handle bad messages received from test client 63 // processes. This can be set to a different callback before starting each 64 // client. 65 void set_process_error_callback(const ProcessErrorCallback& callback) { 66 process_error_callback_ = callback; 67 } 68 69 ClientController& StartClient(const std::string& client_name); 70 71 template <typename HandlerFunc> 72 void StartClientWithHandler(const std::string& client_name, 73 HandlerFunc handler) { 74 int expected_exit_code = 0; 75 ClientController& c = StartClient(client_name); 76 handler(c.pipe(), &expected_exit_code); 77 EXPECT_EQ(expected_exit_code, c.WaitForShutdown()); 78 } 79 80 // Closes a handle and expects success. 81 static void CloseHandle(MojoHandle h); 82 83 ////// Message pipe test utilities /////// 84 85 // Creates a new pipe, returning endpoint handles in |p0| and |p1|. 86 static void CreateMessagePipe(MojoHandle* p0, MojoHandle* p1); 87 88 // Writes a string to the pipe, transferring handles in the process. 89 static void WriteMessageWithHandles(MojoHandle mp, 90 const std::string& message, 91 const MojoHandle* handles, 92 uint32_t num_handles); 93 94 // Writes a string to the pipe with no handles. 95 static void WriteMessage(MojoHandle mp, const std::string& message); 96 97 // Reads a string from the pipe, expecting to read an exact number of handles 98 // in the process. Returns the read string. 99 static std::string ReadMessageWithHandles(MojoHandle mp, 100 MojoHandle* handles, 101 uint32_t expected_num_handles); 102 103 // Reads a string from the pipe, expecting either zero or one handles. 104 // If no handle is read, |handle| will be reset. 105 static std::string ReadMessageWithOptionalHandle(MojoHandle mp, 106 MojoHandle* handle); 107 108 // Reads a string from the pipe, expecting to read no handles. 109 // Returns the string. 110 static std::string ReadMessage(MojoHandle mp); 111 112 // Reads a string from the pipe, expecting to read no handles and exactly 113 // |num_bytes| bytes, which are read into |data|. 114 static void ReadMessage(MojoHandle mp, char* data, size_t num_bytes); 115 116 // Writes |message| to |in| and expects to read it back from |out|. 117 static void VerifyTransmission(MojoHandle in, 118 MojoHandle out, 119 const std::string& message); 120 121 // Writes |message| to |mp| and expects to read it back from the same handle. 122 static void VerifyEcho(MojoHandle mp, const std::string& message); 123 124 //////// Shared buffer test utilities ///////// 125 126 // Creates a new shared buffer. 127 static MojoHandle CreateBuffer(uint64_t size); 128 129 // Duplicates a shared buffer to a new handle. 130 static MojoHandle DuplicateBuffer(MojoHandle h, bool read_only); 131 132 // Maps a buffer, writes some data into it, and unmaps it. 133 static void WriteToBuffer(MojoHandle h, 134 size_t offset, 135 const base::StringPiece& s); 136 137 // Maps a buffer, tests the value of some of its contents, and unmaps it. 138 static void ExpectBufferContents(MojoHandle h, 139 size_t offset, 140 const base::StringPiece& s); 141 142 //////// Data pipe test utilities ///////// 143 144 // Creates a new data pipe. 145 static void CreateDataPipe(MojoHandle* producer, 146 MojoHandle* consumer, 147 size_t capacity); 148 149 // Writes data to a data pipe. 150 static void WriteData(MojoHandle producer, const std::string& data); 151 152 // Reads data from a data pipe. 153 static std::string ReadData(MojoHandle consumer, size_t size); 154 155 void set_launch_type(LaunchType launch_type) { launch_type_ = launch_type; } 156 157 private: 158 friend class ClientController; 159 160 std::vector<std::unique_ptr<ClientController>> clients_; 161 162 ProcessErrorCallback process_error_callback_; 163 164 LaunchType launch_type_ = LaunchType::CHILD; 165 166 DISALLOW_COPY_AND_ASSIGN(MojoTestBase); 167 }; 168 169 // Launches a new child process running the test client |client_name| connected 170 // to a new message pipe bound to |pipe_name|. |pipe_name| is automatically 171 // closed on test teardown. 172 #define RUN_CHILD_ON_PIPE(client_name, pipe_name) \ 173 StartClientWithHandler( \ 174 #client_name, \ 175 [&](MojoHandle pipe_name, int *expected_exit_code) { { 176 177 // Waits for the client to terminate and expects a return code of zero. 178 #define END_CHILD() \ 179 } \ 180 *expected_exit_code = 0; \ 181 }); 182 183 // Wait for the client to terminate with a specific return code. 184 #define END_CHILD_AND_EXPECT_EXIT_CODE(code) \ 185 } \ 186 *expected_exit_code = code; \ 187 }); 188 189 // Use this to declare the child process's "main()" function for tests using 190 // MojoTestBase and MultiprocessTestHelper. It returns an |int|, which will 191 // will be the process's exit code (but see the comment about 192 // WaitForChildShutdown()). 193 // 194 // The function is defined as a subclass of |test_base| to facilitate shared 195 // code between test clients and to allow clients to spawn children themselves. 196 // 197 // |pipe_name| will be bound to the MojoHandle of a message pipe connected 198 // to the parent process (see RUN_CHILD_ON_PIPE above.) This pipe handle is 199 // automatically closed on test client teardown. 200 #if !defined(OS_IOS) 201 #define DEFINE_TEST_CLIENT_WITH_PIPE(client_name, test_base, pipe_name) \ 202 class client_name##_MainFixture : public test_base { \ 203 void TestBody() override {} \ 204 public: \ 205 int Main(MojoHandle); \ 206 }; \ 207 MULTIPROCESS_TEST_MAIN_WITH_SETUP( \ 208 client_name##TestChildMain, \ 209 ::mojo::edk::test::MultiprocessTestHelper::ChildSetup) { \ 210 client_name##_MainFixture test; \ 211 return ::mojo::edk::test::MultiprocessTestHelper::RunClientMain( \ 212 base::Bind(&client_name##_MainFixture::Main, \ 213 base::Unretained(&test))); \ 214 } \ 215 int client_name##_MainFixture::Main(MojoHandle pipe_name) 216 217 // This is a version of DEFINE_TEST_CLIENT_WITH_PIPE which can be used with 218 // gtest ASSERT/EXPECT macros. 219 #define DEFINE_TEST_CLIENT_TEST_WITH_PIPE(client_name, test_base, pipe_name) \ 220 class client_name##_MainFixture : public test_base { \ 221 void TestBody() override {} \ 222 public: \ 223 void Main(MojoHandle); \ 224 }; \ 225 MULTIPROCESS_TEST_MAIN_WITH_SETUP( \ 226 client_name##TestChildMain, \ 227 ::mojo::edk::test::MultiprocessTestHelper::ChildSetup) { \ 228 client_name##_MainFixture test; \ 229 return ::mojo::edk::test::MultiprocessTestHelper::RunClientTestMain( \ 230 base::Bind(&client_name##_MainFixture::Main, \ 231 base::Unretained(&test))); \ 232 } \ 233 void client_name##_MainFixture::Main(MojoHandle pipe_name) 234 #else // !defined(OS_IOS) 235 #define DEFINE_TEST_CLIENT_WITH_PIPE(client_name, test_base, pipe_name) 236 #define DEFINE_TEST_CLIENT_TEST_WITH_PIPE(client_name, test_base, pipe_name) 237 #endif // !defined(OS_IOS) 238 239 } // namespace test 240 } // namespace edk 241 } // namespace mojo 242 243 #endif // MOJO_EDK_TEST_MOJO_TEST_BASE_H_ 244