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