Home | History | Annotate | Download | only in tests
      1 // Copyright 2014 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 #include <stdlib.h>
      6 #include <string.h>
      7 
      8 #include "mojo/public/cpp/bindings/lib/message_builder.h"
      9 #include "mojo/public/cpp/bindings/lib/message_queue.h"
     10 #include "mojo/public/cpp/bindings/lib/router.h"
     11 #include "mojo/public/cpp/environment/environment.h"
     12 #include "mojo/public/cpp/system/macros.h"
     13 #include "mojo/public/cpp/utility/run_loop.h"
     14 #include "testing/gtest/include/gtest/gtest.h"
     15 
     16 namespace mojo {
     17 namespace test {
     18 namespace {
     19 
     20 void AllocRequestMessage(uint32_t name, const char* text, Message* message) {
     21   size_t payload_size = strlen(text) + 1;  // Plus null terminator.
     22   internal::RequestMessageBuilder builder(name, payload_size);
     23   memcpy(builder.buffer()->Allocate(payload_size), text, payload_size);
     24   builder.Finish(message);
     25 }
     26 
     27 void AllocResponseMessage(uint32_t name, const char* text,
     28                           uint64_t request_id, Message* message) {
     29   size_t payload_size = strlen(text) + 1;  // Plus null terminator.
     30   internal::ResponseMessageBuilder builder(name, payload_size, request_id);
     31   memcpy(builder.buffer()->Allocate(payload_size), text, payload_size);
     32   builder.Finish(message);
     33 }
     34 
     35 class MessageAccumulator : public MessageReceiver {
     36  public:
     37   explicit MessageAccumulator(internal::MessageQueue* queue) : queue_(queue) {
     38   }
     39 
     40   virtual bool Accept(Message* message) MOJO_OVERRIDE {
     41     queue_->Push(message);
     42     return true;
     43   }
     44 
     45  private:
     46   internal::MessageQueue* queue_;
     47 };
     48 
     49 class ResponseGenerator : public MessageReceiverWithResponder {
     50  public:
     51   ResponseGenerator() {
     52   }
     53 
     54   virtual bool Accept(Message* message) MOJO_OVERRIDE {
     55     return false;
     56   }
     57 
     58   virtual bool AcceptWithResponder(Message* message, MessageReceiver* responder)
     59       MOJO_OVERRIDE {
     60     EXPECT_TRUE(message->has_flag(internal::kMessageExpectsResponse));
     61 
     62     return SendResponse(message->name(), message->request_id(), responder);
     63   }
     64 
     65   bool SendResponse(uint32_t name, uint64_t request_id,
     66                     MessageReceiver* responder) {
     67     Message response;
     68     AllocResponseMessage(name, "world", request_id, &response);
     69 
     70     bool result = responder->Accept(&response);
     71     delete responder;
     72     return result;
     73   }
     74 };
     75 
     76 class LazyResponseGenerator : public ResponseGenerator {
     77  public:
     78   LazyResponseGenerator() : responder_(NULL), name_(0), request_id_(0) {
     79   }
     80 
     81   virtual ~LazyResponseGenerator() {
     82     delete responder_;
     83   }
     84 
     85   virtual bool AcceptWithResponder(Message* message, MessageReceiver* responder)
     86       MOJO_OVERRIDE {
     87     name_ = message->name();
     88     request_id_ = message->request_id();
     89     responder_ = responder;
     90     return true;
     91   }
     92 
     93   bool has_responder() const { return !!responder_; }
     94 
     95   void Complete() {
     96     SendResponse(name_, request_id_, responder_);
     97     responder_ = NULL;
     98   }
     99 
    100  private:
    101   MessageReceiver* responder_;
    102   uint32_t name_;
    103   uint32_t request_id_;
    104 };
    105 
    106 class RouterTest : public testing::Test {
    107  public:
    108   RouterTest() {
    109   }
    110 
    111   virtual void SetUp() MOJO_OVERRIDE {
    112     CreateMessagePipe(NULL, &handle0_, &handle1_);
    113   }
    114 
    115   virtual void TearDown() MOJO_OVERRIDE {
    116   }
    117 
    118   void PumpMessages() {
    119     loop_.RunUntilIdle();
    120   }
    121 
    122  protected:
    123   ScopedMessagePipeHandle handle0_;
    124   ScopedMessagePipeHandle handle1_;
    125 
    126  private:
    127   Environment env_;
    128   RunLoop loop_;
    129 };
    130 
    131 TEST_F(RouterTest, BasicRequestResponse) {
    132   internal::Router router0(handle0_.Pass(), internal::FilterChain());
    133   internal::Router router1(handle1_.Pass(), internal::FilterChain());
    134 
    135   ResponseGenerator generator;
    136   router1.set_incoming_receiver(&generator);
    137 
    138   Message request;
    139   AllocRequestMessage(1, "hello", &request);
    140 
    141   internal::MessageQueue message_queue;
    142   router0.AcceptWithResponder(&request, new MessageAccumulator(&message_queue));
    143 
    144   PumpMessages();
    145 
    146   EXPECT_FALSE(message_queue.IsEmpty());
    147 
    148   Message response;
    149   message_queue.Pop(&response);
    150 
    151   EXPECT_EQ(std::string("world"),
    152             std::string(reinterpret_cast<const char*>(response.payload())));
    153 }
    154 
    155 TEST_F(RouterTest, BasicRequestResponse_Synchronous) {
    156   internal::Router router0(handle0_.Pass(), internal::FilterChain());
    157   internal::Router router1(handle1_.Pass(), internal::FilterChain());
    158 
    159   ResponseGenerator generator;
    160   router1.set_incoming_receiver(&generator);
    161 
    162   Message request;
    163   AllocRequestMessage(1, "hello", &request);
    164 
    165   internal::MessageQueue message_queue;
    166   router0.AcceptWithResponder(&request, new MessageAccumulator(&message_queue));
    167 
    168   router1.WaitForIncomingMessage();
    169   router0.WaitForIncomingMessage();
    170 
    171   EXPECT_FALSE(message_queue.IsEmpty());
    172 
    173   Message response;
    174   message_queue.Pop(&response);
    175 
    176   EXPECT_EQ(std::string("world"),
    177             std::string(reinterpret_cast<const char*>(response.payload())));
    178 }
    179 
    180 TEST_F(RouterTest, RequestWithNoReceiver) {
    181   internal::Router router0(handle0_.Pass(), internal::FilterChain());
    182   internal::Router router1(handle1_.Pass(), internal::FilterChain());
    183 
    184   // Without an incoming receiver set on router1, we expect router0 to observe
    185   // an error as a result of sending a message.
    186 
    187   Message request;
    188   AllocRequestMessage(1, "hello", &request);
    189 
    190   internal::MessageQueue message_queue;
    191   router0.AcceptWithResponder(&request, new MessageAccumulator(&message_queue));
    192 
    193   PumpMessages();
    194 
    195   EXPECT_TRUE(router0.encountered_error());
    196   EXPECT_TRUE(router1.encountered_error());
    197   EXPECT_TRUE(message_queue.IsEmpty());
    198 }
    199 
    200 TEST_F(RouterTest, LateResponse) {
    201   // Test that things won't blow up if we try to send a message to a
    202   // MessageReceiver, which was given to us via AcceptWithResponder,
    203   // after the router has gone away.
    204 
    205   LazyResponseGenerator generator;
    206   {
    207     internal::Router router0(handle0_.Pass(), internal::FilterChain());
    208     internal::Router router1(handle1_.Pass(), internal::FilterChain());
    209 
    210     router1.set_incoming_receiver(&generator);
    211 
    212     Message request;
    213     AllocRequestMessage(1, "hello", &request);
    214 
    215     internal::MessageQueue message_queue;
    216     router0.AcceptWithResponder(&request,
    217                                 new MessageAccumulator(&message_queue));
    218 
    219     PumpMessages();
    220 
    221     EXPECT_TRUE(generator.has_responder());
    222 
    223   }
    224 
    225   generator.Complete();  // This should end up doing nothing.
    226 }
    227 
    228 }  // namespace
    229 }  // namespace test
    230 }  // namespace mojo
    231