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