aboutsummaryrefslogtreecommitdiff
path: root/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc')
-rw-r--r--mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc309
1 files changed, 253 insertions, 56 deletions
diff --git a/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc b/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc
index aff6251..431a844 100644
--- a/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc
@@ -7,10 +7,14 @@
#include "base/bind.h"
#include "base/callback.h"
+#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/threading/thread.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/public/cpp/bindings/thread_safe_interface_ptr.h"
#include "mojo/public/interfaces/bindings/tests/math_calculator.mojom.h"
#include "mojo/public/interfaces/bindings/tests/sample_interfaces.mojom.h"
#include "mojo/public/interfaces/bindings/tests/sample_service.mojom.h"
@@ -29,10 +33,6 @@ class MathCalculatorImpl : public math::Calculator {
: total_(0.0), binding_(this, std::move(request)) {}
~MathCalculatorImpl() override {}
- void CloseMessagePipe() { binding_.Close(); }
-
- void WaitForIncomingMethodCall() { binding_.WaitForIncomingMethodCall(); }
-
void Clear(const CalcCallback& callback) override {
total_ = 0.0;
callback.Run(total_);
@@ -48,6 +48,8 @@ class MathCalculatorImpl : public math::Calculator {
callback.Run(total_);
}
+ Binding<math::Calculator>* binding() { return &binding_; }
+
private:
double total_;
Binding<math::Calculator> binding_;
@@ -78,6 +80,8 @@ class MathCalculatorUI {
double GetOutput() const { return output_; }
+ math::CalculatorPtr& GetInterfacePtr() { return calculator_; }
+
private:
void Output(const base::Closure& closure, double output) {
output_ = output;
@@ -218,13 +222,13 @@ void ExpectValueAndRunClosure(uint32_t expected_value,
TEST_F(InterfacePtrTest, IsBound) {
math::CalculatorPtr calc;
EXPECT_FALSE(calc.is_bound());
- MathCalculatorImpl calc_impl(GetProxy(&calc));
+ MathCalculatorImpl calc_impl(MakeRequest(&calc));
EXPECT_TRUE(calc.is_bound());
}
TEST_F(InterfacePtrTest, EndToEnd) {
math::CalculatorPtr calc;
- MathCalculatorImpl calc_impl(GetProxy(&calc));
+ MathCalculatorImpl calc_impl(MakeRequest(&calc));
// Suppose this is instantiated in a process that has pipe1_.
MathCalculatorUI calculator_ui(std::move(calc));
@@ -240,7 +244,7 @@ TEST_F(InterfacePtrTest, EndToEnd) {
TEST_F(InterfacePtrTest, EndToEnd_Synchronous) {
math::CalculatorPtr calc;
- MathCalculatorImpl calc_impl(GetProxy(&calc));
+ MathCalculatorImpl calc_impl(MakeRequest(&calc));
// Suppose this is instantiated in a process that has pipe1_.
MathCalculatorUI calculator_ui(std::move(calc));
@@ -250,14 +254,14 @@ TEST_F(InterfacePtrTest, EndToEnd_Synchronous) {
base::RunLoop run_loop;
calculator_ui.Add(2.0, run_loop.QuitClosure());
EXPECT_EQ(0.0, calculator_ui.GetOutput());
- calc_impl.WaitForIncomingMethodCall();
+ calc_impl.binding()->WaitForIncomingMethodCall();
run_loop.Run();
EXPECT_EQ(2.0, calculator_ui.GetOutput());
base::RunLoop run_loop2;
calculator_ui.Multiply(5.0, run_loop2.QuitClosure());
EXPECT_EQ(2.0, calculator_ui.GetOutput());
- calc_impl.WaitForIncomingMethodCall();
+ calc_impl.binding()->WaitForIncomingMethodCall();
run_loop2.Run();
EXPECT_EQ(10.0, calculator_ui.GetOutput());
}
@@ -265,7 +269,7 @@ TEST_F(InterfacePtrTest, EndToEnd_Synchronous) {
TEST_F(InterfacePtrTest, Movable) {
math::CalculatorPtr a;
math::CalculatorPtr b;
- MathCalculatorImpl calc_impl(GetProxy(&b));
+ MathCalculatorImpl calc_impl(MakeRequest(&b));
EXPECT_TRUE(!a);
EXPECT_FALSE(!b);
@@ -312,7 +316,7 @@ TEST_F(InterfacePtrTest, BindInvalidHandle) {
TEST_F(InterfacePtrTest, EncounteredError) {
math::CalculatorPtr proxy;
- MathCalculatorImpl calc_impl(GetProxy(&proxy));
+ MathCalculatorImpl calc_impl(MakeRequest(&proxy));
MathCalculatorUI calculator_ui(std::move(proxy));
@@ -326,7 +330,7 @@ TEST_F(InterfacePtrTest, EncounteredError) {
EXPECT_FALSE(calculator_ui.encountered_error());
// Close the server.
- calc_impl.CloseMessagePipe();
+ calc_impl.binding()->Close();
// The state change isn't picked up locally yet.
base::RunLoop run_loop2;
@@ -341,7 +345,7 @@ TEST_F(InterfacePtrTest, EncounteredError) {
TEST_F(InterfacePtrTest, EncounteredErrorCallback) {
math::CalculatorPtr proxy;
- MathCalculatorImpl calc_impl(GetProxy(&proxy));
+ MathCalculatorImpl calc_impl(MakeRequest(&proxy));
bool encountered_error = false;
base::RunLoop run_loop;
@@ -361,7 +365,7 @@ TEST_F(InterfacePtrTest, EncounteredErrorCallback) {
EXPECT_FALSE(calculator_ui.encountered_error());
// Close the server.
- calc_impl.CloseMessagePipe();
+ calc_impl.binding()->Close();
// The state change isn't picked up locally yet.
EXPECT_FALSE(calculator_ui.encountered_error());
@@ -378,7 +382,7 @@ TEST_F(InterfacePtrTest, EncounteredErrorCallback) {
TEST_F(InterfacePtrTest, DestroyInterfacePtrOnMethodResponse) {
math::CalculatorPtr proxy;
- MathCalculatorImpl calc_impl(GetProxy(&proxy));
+ MathCalculatorImpl calc_impl(MakeRequest(&proxy));
EXPECT_EQ(0, SelfDestructingMathCalculatorUI::num_instances());
@@ -393,7 +397,7 @@ TEST_F(InterfacePtrTest, DestroyInterfacePtrOnMethodResponse) {
TEST_F(InterfacePtrTest, NestedDestroyInterfacePtrOnMethodResponse) {
math::CalculatorPtr proxy;
- MathCalculatorImpl calc_impl(GetProxy(&proxy));
+ MathCalculatorImpl calc_impl(MakeRequest(&proxy));
EXPECT_EQ(0, SelfDestructingMathCalculatorUI::num_instances());
@@ -408,7 +412,7 @@ TEST_F(InterfacePtrTest, NestedDestroyInterfacePtrOnMethodResponse) {
TEST_F(InterfacePtrTest, ReentrantWaitForIncomingMethodCall) {
sample::ServicePtr proxy;
- ReentrantServiceImpl impl(GetProxy(&proxy));
+ ReentrantServiceImpl impl(MakeRequest(&proxy));
base::RunLoop run_loop, run_loop2;
proxy->Frobinate(nullptr, sample::Service::BazOptions::REGULAR, nullptr,
@@ -427,7 +431,7 @@ TEST_F(InterfacePtrTest, ReentrantWaitForIncomingMethodCall) {
TEST_F(InterfacePtrTest, QueryVersion) {
IntegerAccessorImpl impl;
sample::IntegerAccessorPtr ptr;
- Binding<sample::IntegerAccessor> binding(&impl, GetProxy(&ptr));
+ Binding<sample::IntegerAccessor> binding(&impl, MakeRequest(&ptr));
EXPECT_EQ(0u, ptr.version());
@@ -442,7 +446,7 @@ TEST_F(InterfacePtrTest, QueryVersion) {
TEST_F(InterfacePtrTest, RequireVersion) {
IntegerAccessorImpl impl;
sample::IntegerAccessorPtr ptr;
- Binding<sample::IntegerAccessor> binding(&impl, GetProxy(&ptr));
+ Binding<sample::IntegerAccessor> binding(&impl, MakeRequest(&ptr));
EXPECT_EQ(0u, ptr.version());
@@ -479,17 +483,7 @@ TEST_F(InterfacePtrTest, RequireVersion) {
class StrongMathCalculatorImpl : public math::Calculator {
public:
- StrongMathCalculatorImpl(ScopedMessagePipeHandle handle,
- bool* error_received,
- bool* destroyed,
- const base::Closure& closure)
- : error_received_(error_received),
- destroyed_(destroyed),
- closure_(closure),
- binding_(this, std::move(handle)) {
- binding_.set_connection_error_handler(
- base::Bind(&SetFlagAndRunClosure, error_received_, closure_));
- }
+ StrongMathCalculatorImpl(bool* destroyed) : destroyed_(destroyed) {}
~StrongMathCalculatorImpl() override { *destroyed_ = true; }
// math::Calculator implementation.
@@ -507,11 +501,7 @@ class StrongMathCalculatorImpl : public math::Calculator {
private:
double total_ = 0.0;
- bool* error_received_;
bool* destroyed_;
- base::Closure closure_;
-
- StrongBinding<math::Calculator> binding_;
};
TEST(StrongConnectorTest, Math) {
@@ -519,13 +509,14 @@ TEST(StrongConnectorTest, Math) {
bool error_received = false;
bool destroyed = false;
- MessagePipe pipe;
+ math::CalculatorPtr calc;
base::RunLoop run_loop;
- new StrongMathCalculatorImpl(std::move(pipe.handle0), &error_received,
- &destroyed, run_loop.QuitClosure());
- math::CalculatorPtr calc;
- calc.Bind(InterfacePtrInfo<math::Calculator>(std::move(pipe.handle1), 0u));
+ auto binding =
+ MakeStrongBinding(base::MakeUnique<StrongMathCalculatorImpl>(&destroyed),
+ MakeRequest(&calc));
+ binding->set_connection_error_handler(base::Bind(
+ &SetFlagAndRunClosure, &error_received, run_loop.QuitClosure()));
{
// Suppose this is instantiated in a process that has the other end of the
@@ -626,10 +617,8 @@ TEST(WeakConnectorTest, Math) {
class CImpl : public C {
public:
- CImpl(bool* d_called, InterfaceRequest<C> request,
- const base::Closure& closure)
- : d_called_(d_called), binding_(this, std::move(request)),
- closure_(closure) {}
+ CImpl(bool* d_called, const base::Closure& closure)
+ : d_called_(d_called), closure_(closure) {}
~CImpl() override {}
private:
@@ -639,25 +628,22 @@ class CImpl : public C {
}
bool* d_called_;
- StrongBinding<C> binding_;
base::Closure closure_;
};
class BImpl : public B {
public:
- BImpl(bool* d_called, InterfaceRequest<B> request,
- const base::Closure& closure)
- : d_called_(d_called), binding_(this, std::move(request)),
- closure_(closure) {}
+ BImpl(bool* d_called, const base::Closure& closure)
+ : d_called_(d_called), closure_(closure) {}
~BImpl() override {}
private:
void GetC(InterfaceRequest<C> c) override {
- new CImpl(d_called_, std::move(c), closure_);
+ MakeStrongBinding(base::MakeUnique<CImpl>(d_called_, closure_),
+ std::move(c));
}
bool* d_called_;
- StrongBinding<B> binding_;
base::Closure closure_;
};
@@ -672,7 +658,8 @@ class AImpl : public A {
private:
void GetB(InterfaceRequest<B> b) override {
- new BImpl(&d_called_, std::move(b), closure_);
+ MakeStrongBinding(base::MakeUnique<BImpl>(&d_called_, closure_),
+ std::move(b));
}
bool d_called_;
@@ -683,15 +670,15 @@ class AImpl : public A {
TEST_F(InterfacePtrTest, Scoping) {
APtr a;
base::RunLoop run_loop;
- AImpl a_impl(GetProxy(&a), run_loop.QuitClosure());
+ AImpl a_impl(MakeRequest(&a), run_loop.QuitClosure());
EXPECT_FALSE(a_impl.d_called());
{
BPtr b;
- a->GetB(GetProxy(&b));
+ a->GetB(MakeRequest(&b));
CPtr c;
- b->GetC(GetProxy(&c));
+ b->GetC(MakeRequest(&c));
c->D();
}
@@ -718,11 +705,11 @@ class PingTestImpl : public sample::PingTest {
// Tests that FuseProxy does what it's supposed to do.
TEST_F(InterfacePtrTest, Fusion) {
sample::PingTestPtr proxy;
- PingTestImpl impl(GetProxy(&proxy));
+ PingTestImpl impl(MakeRequest(&proxy));
// Create another PingTest pipe.
sample::PingTestPtr ptr;
- sample::PingTestRequest request = GetProxy(&ptr);
+ sample::PingTestRequest request(&ptr);
// Fuse the new pipe to the one hanging off |impl|.
EXPECT_TRUE(FuseInterface(std::move(request), proxy.PassInterface()));
@@ -735,6 +722,216 @@ TEST_F(InterfacePtrTest, Fusion) {
EXPECT_TRUE(called);
}
+void Fail() {
+ FAIL() << "Unexpected connection error";
+}
+
+TEST_F(InterfacePtrTest, FlushForTesting) {
+ math::CalculatorPtr calc;
+ MathCalculatorImpl calc_impl(MakeRequest(&calc));
+ calc.set_connection_error_handler(base::Bind(&Fail));
+
+ MathCalculatorUI calculator_ui(std::move(calc));
+
+ calculator_ui.Add(2.0, base::Bind(&base::DoNothing));
+ calculator_ui.GetInterfacePtr().FlushForTesting();
+ EXPECT_EQ(2.0, calculator_ui.GetOutput());
+
+ calculator_ui.Multiply(5.0, base::Bind(&base::DoNothing));
+ calculator_ui.GetInterfacePtr().FlushForTesting();
+
+ EXPECT_EQ(10.0, calculator_ui.GetOutput());
+}
+
+void SetBool(bool* value) {
+ *value = true;
+}
+
+TEST_F(InterfacePtrTest, FlushForTestingWithClosedPeer) {
+ math::CalculatorPtr calc;
+ MakeRequest(&calc);
+ bool called = false;
+ calc.set_connection_error_handler(base::Bind(&SetBool, &called));
+ calc.FlushForTesting();
+ EXPECT_TRUE(called);
+ calc.FlushForTesting();
+}
+
+TEST_F(InterfacePtrTest, ConnectionErrorWithReason) {
+ math::CalculatorPtr calc;
+ MathCalculatorImpl calc_impl(MakeRequest(&calc));
+
+ base::RunLoop run_loop;
+ calc.set_connection_error_with_reason_handler(base::Bind(
+ [](const base::Closure& quit_closure, uint32_t custom_reason,
+ const std::string& description) {
+ EXPECT_EQ(42u, custom_reason);
+ EXPECT_EQ("hey", description);
+ quit_closure.Run();
+ },
+ run_loop.QuitClosure()));
+
+ calc_impl.binding()->CloseWithReason(42u, "hey");
+
+ run_loop.Run();
+}
+
+TEST_F(InterfacePtrTest, InterfaceRequestResetWithReason) {
+ math::CalculatorPtr calc;
+ auto request = MakeRequest(&calc);
+
+ base::RunLoop run_loop;
+ calc.set_connection_error_with_reason_handler(base::Bind(
+ [](const base::Closure& quit_closure, uint32_t custom_reason,
+ const std::string& description) {
+ EXPECT_EQ(88u, custom_reason);
+ EXPECT_EQ("greetings", description);
+ quit_closure.Run();
+ },
+ run_loop.QuitClosure()));
+
+ request.ResetWithReason(88u, "greetings");
+
+ run_loop.Run();
+}
+
+TEST_F(InterfacePtrTest, CallbackIsPassedInterfacePtr) {
+ sample::PingTestPtr ptr;
+ sample::PingTestRequest request(&ptr);
+
+ base::RunLoop run_loop;
+
+ // Make a call with the proxy's lifetime bound to the response callback.
+ sample::PingTest* raw_proxy = ptr.get();
+ ptr.set_connection_error_handler(run_loop.QuitClosure());
+ raw_proxy->Ping(
+ base::Bind([](sample::PingTestPtr ptr) {}, base::Passed(&ptr)));
+
+ // Trigger an error on |ptr|. This will ultimately lead to the proxy's
+ // response callbacks being destroyed, which will in turn lead to the proxy
+ // being destroyed. This should not crash.
+ request.PassMessagePipe();
+ run_loop.Run();
+}
+
+TEST_F(InterfacePtrTest, ConnectionErrorHandlerOwnsInterfacePtr) {
+ sample::PingTestPtr* ptr = new sample::PingTestPtr;
+ sample::PingTestRequest request(ptr);
+
+ base::RunLoop run_loop;
+
+ // Make a call with |ptr|'s lifetime bound to the connection error handler
+ // callback.
+ ptr->set_connection_error_handler(base::Bind(
+ [](const base::Closure& quit, sample::PingTestPtr* ptr) {
+ ptr->reset();
+ quit.Run();
+ },
+ run_loop.QuitClosure(), base::Owned(ptr)));
+
+ // Trigger an error on |ptr|. In the error handler |ptr| is reset. This
+ // shouldn't immediately destroy the callback (and |ptr| that it owns), before
+ // the callback is completed.
+ request.PassMessagePipe();
+ run_loop.Run();
+}
+
+TEST_F(InterfacePtrTest, ThreadSafeInterfacePointer) {
+ math::CalculatorPtr ptr;
+ MathCalculatorImpl calc_impl(MakeRequest(&ptr));
+ scoped_refptr<math::ThreadSafeCalculatorPtr> thread_safe_ptr =
+ math::ThreadSafeCalculatorPtr::Create(std::move(ptr));
+
+ base::RunLoop run_loop;
+
+ // Create and start the thread from where we'll call the interface pointer.
+ base::Thread other_thread("service test thread");
+ other_thread.Start();
+
+ auto run_method = base::Bind(
+ [](const scoped_refptr<base::TaskRunner>& main_task_runner,
+ const base::Closure& quit_closure,
+ const scoped_refptr<math::ThreadSafeCalculatorPtr>& thread_safe_ptr) {
+ auto calc_callback = base::Bind(
+ [](const scoped_refptr<base::TaskRunner>& main_task_runner,
+ const base::Closure& quit_closure,
+ base::PlatformThreadId thread_id,
+ double result) {
+ EXPECT_EQ(123, result);
+ // Validate the callback is invoked on the calling thread.
+ EXPECT_EQ(thread_id, base::PlatformThread::CurrentId());
+ // Notify the run_loop to quit.
+ main_task_runner->PostTask(FROM_HERE, quit_closure);
+ });
+ (*thread_safe_ptr)->Add(
+ 123, base::Bind(calc_callback, main_task_runner, quit_closure,
+ base::PlatformThread::CurrentId()));
+ },
+ base::SequencedTaskRunnerHandle::Get(), run_loop.QuitClosure(),
+ thread_safe_ptr);
+ other_thread.message_loop()->task_runner()->PostTask(FROM_HERE, run_method);
+
+ // Block until the method callback is called on the background thread.
+ run_loop.Run();
+}
+
+TEST_F(InterfacePtrTest, ThreadSafeInterfacePointerWithTaskRunner) {
+ // Create and start the thread from where we'll bind the interface pointer.
+ base::Thread other_thread("service test thread");
+ other_thread.Start();
+ const scoped_refptr<base::SingleThreadTaskRunner>& other_thread_task_runner =
+ other_thread.message_loop()->task_runner();
+
+ math::CalculatorPtr ptr;
+ math::CalculatorRequest request(&ptr);
+
+ // Create a ThreadSafeInterfacePtr that we'll bind from a different thread.
+ scoped_refptr<math::ThreadSafeCalculatorPtr> thread_safe_ptr =
+ math::ThreadSafeCalculatorPtr::Create(ptr.PassInterface(),
+ other_thread_task_runner);
+ ASSERT_TRUE(thread_safe_ptr);
+
+ MathCalculatorImpl* math_calc_impl = nullptr;
+ {
+ base::RunLoop run_loop;
+ auto run_method = base::Bind(
+ [](const scoped_refptr<base::TaskRunner>& main_task_runner,
+ const base::Closure& quit_closure,
+ const scoped_refptr<math::ThreadSafeCalculatorPtr>& thread_safe_ptr,
+ math::CalculatorRequest request,
+ MathCalculatorImpl** math_calc_impl) {
+ math::CalculatorPtr ptr;
+ // In real life, the implementation would have a legitimate owner.
+ *math_calc_impl = new MathCalculatorImpl(std::move(request));
+ main_task_runner->PostTask(FROM_HERE, quit_closure);
+ },
+ base::SequencedTaskRunnerHandle::Get(), run_loop.QuitClosure(),
+ thread_safe_ptr, base::Passed(&request), &math_calc_impl);
+ other_thread.message_loop()->task_runner()->PostTask(FROM_HERE, run_method);
+ run_loop.Run();
+ }
+
+ {
+ // The interface ptr is bound, we can call methods on it.
+ auto calc_callback =
+ base::Bind([](const base::Closure& quit_closure, double result) {
+ EXPECT_EQ(123, result);
+ quit_closure.Run();
+ });
+ base::RunLoop run_loop;
+ (*thread_safe_ptr)
+ ->Add(123, base::Bind(calc_callback, run_loop.QuitClosure()));
+ // Block until the method callback is called.
+ run_loop.Run();
+ }
+
+ other_thread_task_runner->DeleteSoon(FROM_HERE, math_calc_impl);
+
+ // Reset the pointer now so the InterfacePtr associated resources can be
+ // deleted before the background thread's message loop is invalidated.
+ thread_safe_ptr = nullptr;
+}
+
} // namespace
} // namespace test
} // namespace mojo