| // Copyright 2016 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "mojo/core/test/mojo_test_base.h" |
| |
| #include "base/memory/ptr_util.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/run_loop.h" |
| #include "base/synchronization/waitable_event.h" |
| #include "build/build_config.h" |
| #include "mojo/core/embedder/embedder.h" |
| #include "mojo/public/c/system/buffer.h" |
| #include "mojo/public/c/system/data_pipe.h" |
| #include "mojo/public/c/system/functions.h" |
| #include "mojo/public/c/system/trap.h" |
| #include "mojo/public/cpp/system/handle.h" |
| #include "mojo/public/cpp/system/message_pipe.h" |
| #include "mojo/public/cpp/system/wait.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace mojo { |
| namespace core { |
| namespace test { |
| |
| MojoTestBase::MojoTestBase() = default; |
| |
| MojoTestBase::~MojoTestBase() = default; |
| |
| MojoTestBase::ClientController& MojoTestBase::StartClient( |
| const std::string& client_name) { |
| clients_.push_back( |
| std::make_unique<ClientController>(client_name, this, launch_type_)); |
| return *clients_.back(); |
| } |
| |
| MojoTestBase::ClientController::ClientController(const std::string& client_name, |
| MojoTestBase* test, |
| LaunchType launch_type) { |
| #if !defined(OS_IOS) |
| pipe_ = helper_.StartChild(client_name, launch_type); |
| #endif |
| } |
| |
| MojoTestBase::ClientController::~ClientController() { |
| CHECK(was_shutdown_) |
| << "Test clients should be waited on explicitly with WaitForShutdown()."; |
| } |
| |
| int MojoTestBase::ClientController::WaitForShutdown() { |
| was_shutdown_ = true; |
| #if !defined(OS_IOS) |
| int retval = helper_.WaitForChildShutdown(); |
| return retval; |
| #else |
| NOTREACHED(); |
| return 1; |
| #endif |
| } |
| |
| // static |
| void MojoTestBase::CloseHandle(MojoHandle h) { |
| EXPECT_EQ(MOJO_RESULT_OK, MojoClose(h)); |
| } |
| |
| // static |
| void MojoTestBase::CreateMessagePipe(MojoHandle* p0, MojoHandle* p1) { |
| MojoCreateMessagePipe(nullptr, p0, p1); |
| CHECK_NE(*p0, MOJO_HANDLE_INVALID); |
| CHECK_NE(*p1, MOJO_HANDLE_INVALID); |
| } |
| |
| // static |
| void MojoTestBase::WriteMessageWithHandles(MojoHandle mp, |
| const std::string& message, |
| const MojoHandle* handles, |
| uint32_t num_handles) { |
| CHECK_EQ(WriteMessageRaw(MessagePipeHandle(mp), message.data(), |
| static_cast<uint32_t>(message.size()), handles, |
| num_handles, MOJO_WRITE_MESSAGE_FLAG_NONE), |
| MOJO_RESULT_OK); |
| } |
| |
| // static |
| void MojoTestBase::WriteMessage(MojoHandle mp, const std::string& message) { |
| WriteMessageWithHandles(mp, message, nullptr, 0); |
| } |
| |
| // static |
| std::string MojoTestBase::ReadMessageWithHandles( |
| MojoHandle mp, |
| MojoHandle* out_handles, |
| uint32_t expected_num_handles) { |
| CHECK_EQ(WaitForSignals(mp, MOJO_HANDLE_SIGNAL_READABLE), MOJO_RESULT_OK); |
| |
| std::vector<uint8_t> bytes; |
| std::vector<ScopedHandle> handles; |
| CHECK_EQ(MOJO_RESULT_OK, |
| ReadMessageRaw(MessagePipeHandle(mp), &bytes, &handles, |
| MOJO_READ_MESSAGE_FLAG_NONE)); |
| CHECK_EQ(expected_num_handles, handles.size()); |
| for (size_t i = 0; i < handles.size(); ++i) |
| out_handles[i] = handles[i].release().value(); |
| |
| return std::string(bytes.begin(), bytes.end()); |
| } |
| |
| // static |
| std::string MojoTestBase::ReadMessageWithOptionalHandle(MojoHandle mp, |
| MojoHandle* handle) { |
| CHECK_EQ(WaitForSignals(mp, MOJO_HANDLE_SIGNAL_READABLE), MOJO_RESULT_OK); |
| |
| std::vector<uint8_t> bytes; |
| std::vector<ScopedHandle> handles; |
| CHECK_EQ(MOJO_RESULT_OK, |
| ReadMessageRaw(MessagePipeHandle(mp), &bytes, &handles, |
| MOJO_READ_MESSAGE_FLAG_NONE)); |
| CHECK(handles.size() == 0 || handles.size() == 1); |
| CHECK(handle); |
| |
| if (handles.size() == 1) |
| *handle = handles[0].release().value(); |
| else |
| *handle = MOJO_HANDLE_INVALID; |
| |
| return std::string(bytes.begin(), bytes.end()); |
| } |
| |
| // static |
| std::string MojoTestBase::ReadMessage(MojoHandle mp) { |
| return ReadMessageWithHandles(mp, nullptr, 0); |
| } |
| |
| // static |
| void MojoTestBase::ReadMessage(MojoHandle mp, char* data, size_t num_bytes) { |
| CHECK_EQ(WaitForSignals(mp, MOJO_HANDLE_SIGNAL_READABLE), MOJO_RESULT_OK); |
| |
| std::vector<uint8_t> bytes; |
| std::vector<ScopedHandle> handles; |
| CHECK_EQ(MOJO_RESULT_OK, |
| ReadMessageRaw(MessagePipeHandle(mp), &bytes, &handles, |
| MOJO_READ_MESSAGE_FLAG_NONE)); |
| CHECK_EQ(0u, handles.size()); |
| CHECK_EQ(num_bytes, bytes.size()); |
| memcpy(data, bytes.data(), bytes.size()); |
| } |
| |
| // static |
| void MojoTestBase::VerifyTransmission(MojoHandle source, |
| MojoHandle dest, |
| const std::string& message) { |
| WriteMessage(source, message); |
| |
| // We don't use EXPECT_EQ; failures on really long messages make life hard. |
| EXPECT_TRUE(message == ReadMessage(dest)); |
| } |
| |
| // static |
| void MojoTestBase::VerifyEcho(MojoHandle mp, const std::string& message) { |
| VerifyTransmission(mp, mp, message); |
| } |
| |
| // static |
| MojoHandle MojoTestBase::CreateBuffer(uint64_t size) { |
| MojoHandle h; |
| EXPECT_EQ(MojoCreateSharedBuffer(size, nullptr, &h), MOJO_RESULT_OK); |
| return h; |
| } |
| |
| // static |
| MojoHandle MojoTestBase::DuplicateBuffer(MojoHandle h, bool read_only) { |
| MojoHandle new_handle; |
| MojoDuplicateBufferHandleOptions options = { |
| sizeof(MojoDuplicateBufferHandleOptions), |
| MOJO_DUPLICATE_BUFFER_HANDLE_FLAG_NONE}; |
| if (read_only) |
| options.flags |= MOJO_DUPLICATE_BUFFER_HANDLE_FLAG_READ_ONLY; |
| EXPECT_EQ(MOJO_RESULT_OK, |
| MojoDuplicateBufferHandle(h, &options, &new_handle)); |
| return new_handle; |
| } |
| |
| // static |
| void MojoTestBase::WriteToBuffer(MojoHandle h, |
| size_t offset, |
| const base::StringPiece& s) { |
| char* data; |
| EXPECT_EQ(MOJO_RESULT_OK, MojoMapBuffer(h, offset, s.size(), nullptr, |
| reinterpret_cast<void**>(&data))); |
| memcpy(data, s.data(), s.size()); |
| EXPECT_EQ(MOJO_RESULT_OK, MojoUnmapBuffer(static_cast<void*>(data))); |
| } |
| |
| // static |
| void MojoTestBase::ExpectBufferContents(MojoHandle h, |
| size_t offset, |
| const base::StringPiece& s) { |
| char* data; |
| EXPECT_EQ(MOJO_RESULT_OK, MojoMapBuffer(h, offset, s.size(), nullptr, |
| reinterpret_cast<void**>(&data))); |
| EXPECT_EQ(s, base::StringPiece(data, s.size())); |
| EXPECT_EQ(MOJO_RESULT_OK, MojoUnmapBuffer(static_cast<void*>(data))); |
| } |
| |
| // static |
| void MojoTestBase::CreateDataPipe(MojoHandle* p0, |
| MojoHandle* p1, |
| size_t capacity) { |
| MojoCreateDataPipeOptions options; |
| options.struct_size = static_cast<uint32_t>(sizeof(options)); |
| options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE; |
| options.element_num_bytes = 1; |
| options.capacity_num_bytes = static_cast<uint32_t>(capacity); |
| |
| MojoCreateDataPipe(&options, p0, p1); |
| CHECK_NE(*p0, MOJO_HANDLE_INVALID); |
| CHECK_NE(*p1, MOJO_HANDLE_INVALID); |
| } |
| |
| // static |
| void MojoTestBase::WriteData(MojoHandle producer, const std::string& data) { |
| CHECK_EQ(WaitForSignals(producer, MOJO_HANDLE_SIGNAL_WRITABLE), |
| MOJO_RESULT_OK); |
| uint32_t num_bytes = static_cast<uint32_t>(data.size()); |
| MojoWriteDataOptions options; |
| options.struct_size = sizeof(options); |
| options.flags = MOJO_WRITE_DATA_FLAG_ALL_OR_NONE; |
| CHECK_EQ(MojoWriteData(producer, data.data(), &num_bytes, &options), |
| MOJO_RESULT_OK); |
| CHECK_EQ(num_bytes, static_cast<uint32_t>(data.size())); |
| } |
| |
| // static |
| std::string MojoTestBase::ReadData(MojoHandle consumer, size_t size) { |
| CHECK_EQ(WaitForSignals(consumer, MOJO_HANDLE_SIGNAL_READABLE), |
| MOJO_RESULT_OK); |
| std::vector<char> buffer(size); |
| uint32_t num_bytes = static_cast<uint32_t>(size); |
| MojoReadDataOptions options; |
| options.struct_size = sizeof(options); |
| options.flags = MOJO_READ_DATA_FLAG_ALL_OR_NONE; |
| CHECK_EQ(MojoReadData(consumer, &options, buffer.data(), &num_bytes), |
| MOJO_RESULT_OK); |
| CHECK_EQ(num_bytes, static_cast<uint32_t>(size)); |
| |
| return std::string(buffer.begin(), buffer.end()); |
| } |
| |
| // static |
| MojoHandleSignalsState MojoTestBase::GetSignalsState(MojoHandle handle) { |
| MojoHandleSignalsState signals_state; |
| CHECK_EQ(MOJO_RESULT_OK, MojoQueryHandleSignalsState(handle, &signals_state)); |
| return signals_state; |
| } |
| |
| // static |
| MojoResult MojoTestBase::WaitForSignals(MojoHandle handle, |
| MojoHandleSignals signals, |
| MojoTriggerCondition condition, |
| MojoHandleSignalsState* state) { |
| return Wait(Handle(handle), signals, condition, state); |
| } |
| |
| // static |
| MojoResult MojoTestBase::WaitForSignals(MojoHandle handle, |
| MojoHandleSignals signals, |
| MojoHandleSignalsState* state) { |
| return Wait(Handle(handle), signals, MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, |
| state); |
| } |
| |
| } // namespace test |
| } // namespace core |
| } // namespace mojo |