• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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