// Copyright (c) 2012 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 "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "dbus/bus.h"
#include "dbus/message.h"
#include "dbus/object_path.h"
#include "dbus/object_proxy.h"
#include "dbus/test_service.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace dbus {

// The end-to-end test exercises the synchronous APIs in ObjectProxy and
// ExportedObject. The test will launch a thread for the service side
// operations (i.e. ExportedObject side).
class EndToEndSyncTest : public testing::Test {
 public:
  EndToEndSyncTest() {
  }

  virtual void SetUp() {
    // Start the test service;
    TestService::Options options;
    test_service_.reset(new TestService(options));
    ASSERT_TRUE(test_service_->StartService());
    ASSERT_TRUE(test_service_->WaitUntilServiceIsStarted());
    ASSERT_FALSE(test_service_->HasDBusThread());

    // Create the client.
    Bus::Options client_bus_options;
    client_bus_options.bus_type = Bus::SESSION;
    client_bus_options.connection_type = Bus::PRIVATE;
    client_bus_ = new Bus(client_bus_options);
    object_proxy_ = client_bus_->GetObjectProxy(
        "org.chromium.TestService",
        ObjectPath("/org/chromium/TestObject"));
    ASSERT_FALSE(client_bus_->HasDBusThread());
  }

  virtual void TearDown() {
    test_service_->ShutdownAndBlock();
    test_service_->Stop();
    client_bus_->ShutdownAndBlock();
  }

 protected:
  scoped_ptr<TestService> test_service_;
  scoped_refptr<Bus> client_bus_;
  ObjectProxy* object_proxy_;
};

TEST_F(EndToEndSyncTest, Echo) {
  const std::string kHello = "hello";

  // Create the method call.
  MethodCall method_call("org.chromium.TestInterface", "Echo");
  MessageWriter writer(&method_call);
  writer.AppendString(kHello);

  // Call the method.
  const int timeout_ms = ObjectProxy::TIMEOUT_USE_DEFAULT;
  scoped_ptr<Response> response(
      object_proxy_->CallMethodAndBlock(&method_call, timeout_ms));
  ASSERT_TRUE(response.get());

  // Check the response. kHello should be echoed back.
  MessageReader reader(response.get());
  std::string returned_message;
  ASSERT_TRUE(reader.PopString(&returned_message));
  EXPECT_EQ(kHello, returned_message);
}

TEST_F(EndToEndSyncTest, Timeout) {
  const std::string kHello = "hello";

  // Create the method call.
  MethodCall method_call("org.chromium.TestInterface", "DelayedEcho");
  MessageWriter writer(&method_call);
  writer.AppendString(kHello);

  // Call the method with timeout of 0ms.
  const int timeout_ms = 0;
  scoped_ptr<Response> response(
      object_proxy_->CallMethodAndBlock(&method_call, timeout_ms));
  // Should fail because of timeout.
  ASSERT_FALSE(response.get());
}

TEST_F(EndToEndSyncTest, NonexistentMethod) {
  MethodCall method_call("org.chromium.TestInterface", "Nonexistent");

  const int timeout_ms = ObjectProxy::TIMEOUT_USE_DEFAULT;
  scoped_ptr<Response> response(
      object_proxy_->CallMethodAndBlock(&method_call, timeout_ms));
  ASSERT_FALSE(response.get());
}

TEST_F(EndToEndSyncTest, BrokenMethod) {
  MethodCall method_call("org.chromium.TestInterface", "BrokenMethod");

  const int timeout_ms = ObjectProxy::TIMEOUT_USE_DEFAULT;
  scoped_ptr<Response> response(
      object_proxy_->CallMethodAndBlock(&method_call, timeout_ms));
  ASSERT_FALSE(response.get());
}

TEST_F(EndToEndSyncTest, InvalidObjectPath) {
  // Trailing '/' is only allowed for the root path.
  const ObjectPath invalid_object_path("/org/chromium/TestObject/");

  // Replace object proxy with new one.
  object_proxy_ = client_bus_->GetObjectProxy("org.chromium.TestService",
                                              invalid_object_path);

  MethodCall method_call("org.chromium.TestInterface", "Echo");

  const int timeout_ms = ObjectProxy::TIMEOUT_USE_DEFAULT;
  scoped_ptr<Response> response(
      object_proxy_->CallMethodAndBlock(&method_call, timeout_ms));
  ASSERT_FALSE(response.get());
}

TEST_F(EndToEndSyncTest, InvalidServiceName) {
  // Bus name cannot contain '/'.
  const std::string invalid_service_name = ":1/2";

  // Replace object proxy with new one.
  object_proxy_ = client_bus_->GetObjectProxy(
      invalid_service_name, ObjectPath("org.chromium.TestObject"));

  MethodCall method_call("org.chromium.TestInterface", "Echo");

  const int timeout_ms = ObjectProxy::TIMEOUT_USE_DEFAULT;
  scoped_ptr<Response> response(
      object_proxy_->CallMethodAndBlock(&method_call, timeout_ms));
  ASSERT_FALSE(response.get());
}

}  // namespace dbus
