root/mojo/public/cpp/bindings/tests/router_unittest.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. AllocRequestMessage
  2. AllocResponseMessage
  3. Accept
  4. AcceptWithResponder
  5. Accept
  6. AcceptWithResponder
  7. SendResponse
  8. request_id_
  9. AcceptWithResponder
  10. has_responder
  11. Complete
  12. SetUp
  13. TearDown
  14. PumpMessages
  15. TEST_F
  16. TEST_F
  17. TEST_F

// 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 <stdlib.h>
#include <string.h>

#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;
  }

  virtual bool AcceptWithResponder(Message* message, MessageReceiver* responder)
      MOJO_OVERRIDE {
    return false;
  }

 private:
  internal::MessageQueue* queue_;
};

class ResponseGenerator : public MessageReceiver {
 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(&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::Router router1(handle1_.Pass());

  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<const char*>(response.payload())));
}

TEST_F(RouterTest, RequestWithNoReceiver) {
  internal::Router router0(handle0_.Pass());
  internal::Router router1(handle1_.Pass());

  // 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::Router router1(handle1_.Pass());

    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

/* [<][>][^][v][top][bottom][index][help] */