diff options
Diffstat (limited to 'mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc')
-rw-r--r-- | mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc | 309 |
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 |