// Copyright 2014 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 #include #include "mojo/public/cpp/bindings/lib/message_builder.h" #include "mojo/public/cpp/bindings/lib/message_queue.h" #include "mojo/public/cpp/bindings/lib/router.h" #include "mojo/public/cpp/environment/environment.h" #include "mojo/public/cpp/system/macros.h" #include "mojo/public/cpp/utility/run_loop.h" #include "testing/gtest/include/gtest/gtest.h" namespace mojo { namespace test { namespace { void AllocRequestMessage(uint32_t name, const char* text, Message* message) { size_t payload_size = strlen(text) + 1; // Plus null terminator. internal::RequestMessageBuilder builder(name, payload_size); memcpy(builder.buffer()->Allocate(payload_size), text, payload_size); builder.Finish(message); } void AllocResponseMessage(uint32_t name, const char* text, uint64_t request_id, Message* message) { size_t payload_size = strlen(text) + 1; // Plus null terminator. internal::ResponseMessageBuilder builder(name, payload_size, request_id); memcpy(builder.buffer()->Allocate(payload_size), text, payload_size); builder.Finish(message); } class MessageAccumulator : public MessageReceiver { public: explicit MessageAccumulator(internal::MessageQueue* queue) : queue_(queue) { } virtual bool Accept(Message* message) MOJO_OVERRIDE { queue_->Push(message); return true; } private: internal::MessageQueue* queue_; }; class ResponseGenerator : public MessageReceiverWithResponder { public: ResponseGenerator() { } virtual bool Accept(Message* message) MOJO_OVERRIDE { return false; } virtual bool AcceptWithResponder(Message* message, MessageReceiver* responder) MOJO_OVERRIDE { EXPECT_TRUE(message->has_flag(internal::kMessageExpectsResponse)); return SendResponse(message->name(), message->request_id(), responder); } bool SendResponse(uint32_t name, uint64_t request_id, MessageReceiver* responder) { Message response; AllocResponseMessage(name, "world", request_id, &response); bool result = responder->Accept(&response); delete responder; return result; } }; class LazyResponseGenerator : public ResponseGenerator { public: LazyResponseGenerator() : responder_(NULL), name_(0), request_id_(0) { } virtual ~LazyResponseGenerator() { delete responder_; } virtual bool AcceptWithResponder(Message* message, MessageReceiver* responder) MOJO_OVERRIDE { name_ = message->name(); request_id_ = message->request_id(); responder_ = responder; return true; } bool has_responder() const { return !!responder_; } void Complete() { SendResponse(name_, request_id_, responder_); responder_ = NULL; } private: MessageReceiver* responder_; uint32_t name_; uint32_t request_id_; }; class RouterTest : public testing::Test { public: RouterTest() { } virtual void SetUp() MOJO_OVERRIDE { CreateMessagePipe(NULL, &handle0_, &handle1_); } virtual void TearDown() MOJO_OVERRIDE { } void PumpMessages() { loop_.RunUntilIdle(); } protected: ScopedMessagePipeHandle handle0_; ScopedMessagePipeHandle handle1_; private: Environment env_; RunLoop loop_; }; TEST_F(RouterTest, BasicRequestResponse) { internal::Router router0(handle0_.Pass(), internal::FilterChain()); internal::Router router1(handle1_.Pass(), internal::FilterChain()); ResponseGenerator generator; router1.set_incoming_receiver(&generator); Message request; AllocRequestMessage(1, "hello", &request); internal::MessageQueue message_queue; router0.AcceptWithResponder(&request, new MessageAccumulator(&message_queue)); PumpMessages(); EXPECT_FALSE(message_queue.IsEmpty()); Message response; message_queue.Pop(&response); EXPECT_EQ(std::string("world"), std::string(reinterpret_cast(response.payload()))); } TEST_F(RouterTest, BasicRequestResponse_Synchronous) { internal::Router router0(handle0_.Pass(), internal::FilterChain()); internal::Router router1(handle1_.Pass(), internal::FilterChain()); ResponseGenerator generator; router1.set_incoming_receiver(&generator); Message request; AllocRequestMessage(1, "hello", &request); internal::MessageQueue message_queue; router0.AcceptWithResponder(&request, new MessageAccumulator(&message_queue)); router1.WaitForIncomingMessage(); router0.WaitForIncomingMessage(); EXPECT_FALSE(message_queue.IsEmpty()); Message response; message_queue.Pop(&response); EXPECT_EQ(std::string("world"), std::string(reinterpret_cast(response.payload()))); } TEST_F(RouterTest, RequestWithNoReceiver) { internal::Router router0(handle0_.Pass(), internal::FilterChain()); internal::Router router1(handle1_.Pass(), internal::FilterChain()); // Without an incoming receiver set on router1, we expect router0 to observe // an error as a result of sending a message. Message request; AllocRequestMessage(1, "hello", &request); internal::MessageQueue message_queue; router0.AcceptWithResponder(&request, new MessageAccumulator(&message_queue)); PumpMessages(); EXPECT_TRUE(router0.encountered_error()); EXPECT_TRUE(router1.encountered_error()); EXPECT_TRUE(message_queue.IsEmpty()); } TEST_F(RouterTest, LateResponse) { // Test that things won't blow up if we try to send a message to a // MessageReceiver, which was given to us via AcceptWithResponder, // after the router has gone away. LazyResponseGenerator generator; { internal::Router router0(handle0_.Pass(), internal::FilterChain()); internal::Router router1(handle1_.Pass(), internal::FilterChain()); router1.set_incoming_receiver(&generator); Message request; AllocRequestMessage(1, "hello", &request); internal::MessageQueue message_queue; router0.AcceptWithResponder(&request, new MessageAccumulator(&message_queue)); PumpMessages(); EXPECT_TRUE(generator.has_responder()); } generator.Complete(); // This should end up doing nothing. } } // namespace } // namespace test } // namespace mojo