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
23namespace mojo {
24namespace edk {
25namespace test {
26
27class 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
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.
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>
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