blob: 2e38f1314924005daae6c40be2dc50a892a68868 [file] [log] [blame]
// Copyright 2015 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/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/environment/environment.h"
#include "mojo/public/cpp/utility/run_loop.h"
#include "mojo/public/interfaces/bindings/tests/sample_service.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace mojo {
namespace {
class ServiceImpl : public sample::Service {
public:
ServiceImpl() {}
~ServiceImpl() override {}
private:
// sample::Service implementation
void Frobinate(sample::FooPtr foo,
BazOptions options,
sample::PortPtr port,
const FrobinateCallback& callback) override {
callback.Run(1);
}
void GetPort(InterfaceRequest<sample::Port> port) override {}
};
class RecordingErrorHandler : public ErrorHandler {
public:
RecordingErrorHandler() : error_(false) {}
~RecordingErrorHandler() override {}
bool encountered_error() const { return error_; }
private:
// ErrorHandler implementation.
void OnConnectionError() override { error_ = true; }
bool error_;
};
class BindingTest : public testing::Test {
public:
BindingTest() {}
~BindingTest() override {}
protected:
RecordingErrorHandler handler_;
ServiceImpl impl_;
Environment env_;
RunLoop loop_;
};
// Tests that destroying a mojo::Binding closes the bound message pipe handle.
TEST_F(BindingTest, DestroyClosesMessagePipe) {
sample::ServicePtr ptr;
auto request = GetProxy(&ptr);
ptr.set_error_handler(&handler_);
bool called = false;
auto called_cb = [&called](int32_t result) { called = true; };
{
Binding<sample::Service> binding(&impl_, request.Pass());
ptr->Frobinate(nullptr, sample::Service::BAZ_OPTIONS_REGULAR, nullptr,
called_cb);
loop_.RunUntilIdle();
EXPECT_TRUE(called);
EXPECT_FALSE(handler_.encountered_error());
}
// Now that the Binding is out of scope we should detect an error on the other
// end of the pipe.
loop_.RunUntilIdle();
EXPECT_TRUE(handler_.encountered_error());
// And calls should fail.
called = false;
ptr->Frobinate(nullptr, sample::Service::BAZ_OPTIONS_REGULAR, nullptr,
called_cb);
loop_.RunUntilIdle();
EXPECT_FALSE(called);
}
// Tests that explicitly calling Unbind followed by rebinding works.
TEST_F(BindingTest, Unbind) {
sample::ServicePtr ptr;
Binding<sample::Service> binding(&impl_, GetProxy(&ptr));
bool called = false;
auto called_cb = [&called](int32_t result) { called = true; };
ptr->Frobinate(nullptr, sample::Service::BAZ_OPTIONS_REGULAR, nullptr,
called_cb);
loop_.RunUntilIdle();
EXPECT_TRUE(called);
called = false;
auto request = binding.Unbind();
EXPECT_FALSE(binding.is_bound());
// All calls should fail when not bound...
ptr->Frobinate(nullptr, sample::Service::BAZ_OPTIONS_REGULAR, nullptr,
called_cb);
loop_.RunUntilIdle();
EXPECT_FALSE(called);
called = false;
binding.Bind(request.Pass());
EXPECT_TRUE(binding.is_bound());
// ...and should succeed again when the rebound.
ptr->Frobinate(nullptr, sample::Service::BAZ_OPTIONS_REGULAR, nullptr,
called_cb);
loop_.RunUntilIdle();
EXPECT_TRUE(called);
}
} // namespace
} // mojo