Home | History | Annotate | Download | only in test
      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