| OLD | NEW |
| (Empty) |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "mojo/public/cpp/bindings/synchronous_interface_ptr.h" | |
| 6 | |
| 7 #include <thread> | |
| 8 #include <utility> | |
| 9 | |
| 10 #include "gtest/gtest.h" | |
| 11 #include "mojo/public/cpp/bindings/binding.h" | |
| 12 #include "mojo/public/cpp/bindings/interface_request.h" | |
| 13 #include "mojo/public/cpp/bindings/strong_binding.h" | |
| 14 #include "mojo/public/cpp/utility/run_loop.h" | |
| 15 #include "mojo/public/interfaces/bindings/tests/math_calculator.mojom-sync.h" | |
| 16 #include "mojo/public/interfaces/bindings/tests/math_calculator.mojom.h" | |
| 17 #include "mojo/public/interfaces/bindings/tests/scoping.mojom-sync.h" | |
| 18 #include "mojo/public/interfaces/bindings/tests/scoping.mojom.h" | |
| 19 | |
| 20 namespace mojo { | |
| 21 namespace test { | |
| 22 namespace { | |
| 23 | |
| 24 using CalcCallback = mojo::Callback<void(double)>; | |
| 25 | |
| 26 // This runs in a separate thread. | |
| 27 class MathCalculatorImpl : public math::Calculator { | |
| 28 public: | |
| 29 explicit MathCalculatorImpl(InterfaceRequest<math::Calculator> request) | |
| 30 : total_(0.0), binding_(this, request.Pass()) {} | |
| 31 ~MathCalculatorImpl() override {} | |
| 32 | |
| 33 void Clear(const CalcCallback& callback) override { | |
| 34 total_ = 0.0; | |
| 35 callback.Run(total_); | |
| 36 } | |
| 37 | |
| 38 void Add(double value, const CalcCallback& callback) override { | |
| 39 total_ += value; | |
| 40 callback.Run(total_); | |
| 41 } | |
| 42 | |
| 43 void Multiply(double value, const CalcCallback& callback) override { | |
| 44 total_ *= value; | |
| 45 callback.Run(total_); | |
| 46 } | |
| 47 | |
| 48 private: | |
| 49 double total_; | |
| 50 Binding<math::Calculator> binding_; | |
| 51 }; | |
| 52 | |
| 53 class SynchronousInterfacePtrTest : public testing::Test { | |
| 54 public: | |
| 55 ~SynchronousInterfacePtrTest() override { loop_.RunUntilIdle(); } | |
| 56 | |
| 57 void PumpMessages() { loop_.RunUntilIdle(); } | |
| 58 | |
| 59 // This is meant to be passed in to an std::thread -- the thread will have its | |
| 60 // own RunLoop! | |
| 61 static void StartMathCalculator(InterfaceRequest<math::Calculator> server) { | |
| 62 // Runloop is thread-local, and this is what the MathCalculatorImpl will end | |
| 63 // up using. | |
| 64 RunLoop loop; | |
| 65 MathCalculatorImpl calc_impl(std::move(server)); | |
| 66 loop.Run(); | |
| 67 } | |
| 68 | |
| 69 private: | |
| 70 RunLoop loop_; | |
| 71 }; | |
| 72 | |
| 73 TEST_F(SynchronousInterfacePtrTest, IsBound) { | |
| 74 SynchronousInterfacePtr<math::Calculator> calc; | |
| 75 EXPECT_FALSE(calc.is_bound()); | |
| 76 EXPECT_FALSE(calc); | |
| 77 | |
| 78 MathCalculatorImpl calc_impl(GetSynchronousProxy(&calc)); | |
| 79 EXPECT_TRUE(calc.is_bound()); | |
| 80 EXPECT_TRUE(calc); | |
| 81 } | |
| 82 | |
| 83 // Do an end to end | |
| 84 TEST_F(SynchronousInterfacePtrTest, EndToEnd) { | |
| 85 SynchronousInterfacePtr<math::Calculator> calc; | |
| 86 std::thread server(StartMathCalculator, GetSynchronousProxy(&calc)); | |
| 87 | |
| 88 double out; | |
| 89 calc->Add(2.0, &out); | |
| 90 calc->Multiply(5.0, &out); | |
| 91 EXPECT_EQ(10.0, out); | |
| 92 | |
| 93 calc.PassInterfaceHandle(); | |
| 94 server.join(); | |
| 95 } | |
| 96 | |
| 97 // Move them around. | |
| 98 TEST_F(SynchronousInterfacePtrTest, Movable) { | |
| 99 SynchronousInterfacePtr<math::Calculator> a; | |
| 100 SynchronousInterfacePtr<math::Calculator> b; | |
| 101 MathCalculatorImpl calc_impl(GetSynchronousProxy(&b)); | |
| 102 | |
| 103 EXPECT_TRUE(!a); | |
| 104 EXPECT_FALSE(!b); | |
| 105 | |
| 106 a = std::move(b); | |
| 107 | |
| 108 EXPECT_FALSE(!a); | |
| 109 EXPECT_TRUE(!b); | |
| 110 } | |
| 111 | |
| 112 // Test ::reset() and the explicit bool operator. | |
| 113 TEST_F(SynchronousInterfacePtrTest, Resettable) { | |
| 114 MessagePipe pipe; | |
| 115 // Save this so we can test it later. | |
| 116 Handle handle = pipe.handle0.get(); | |
| 117 | |
| 118 SynchronousInterfacePtr<math::Calculator> a; | |
| 119 EXPECT_TRUE(!a); | |
| 120 a = SynchronousInterfacePtr<math::Calculator>::Create( | |
| 121 InterfaceHandle<math::Calculator>(std::move(pipe.handle0), 0u)); | |
| 122 EXPECT_FALSE(!a); | |
| 123 | |
| 124 a.reset(); | |
| 125 EXPECT_TRUE(!a); | |
| 126 | |
| 127 // Test that handle was closed. | |
| 128 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, CloseRaw(handle)); | |
| 129 } | |
| 130 | |
| 131 TEST_F(SynchronousInterfacePtrTest, SetNull) { | |
| 132 MessagePipe pipe; | |
| 133 auto a = SynchronousInterfacePtr<math::Calculator>::Create( | |
| 134 InterfaceHandle<math::Calculator>(std::move(pipe.handle0), 0u)); | |
| 135 | |
| 136 EXPECT_TRUE(a); | |
| 137 a = nullptr; | |
| 138 EXPECT_FALSE(a); | |
| 139 } | |
| 140 | |
| 141 // SynchronousInterfacePtr<> will return false on method invocations if its | |
| 142 // underlying end of the pipe is dead. | |
| 143 TEST_F(SynchronousInterfacePtrTest, EncounteredError) { | |
| 144 SynchronousInterfacePtr<math::Calculator> calc; | |
| 145 { | |
| 146 MathCalculatorImpl calc_impl(GetSynchronousProxy(&calc)); | |
| 147 EXPECT_TRUE(calc.is_bound()); | |
| 148 } | |
| 149 | |
| 150 EXPECT_TRUE(calc.is_bound()); | |
| 151 | |
| 152 double out = 0.0; | |
| 153 EXPECT_FALSE(calc->Add(2.0, &out)); | |
| 154 EXPECT_EQ(0.0, out); | |
| 155 } | |
| 156 | |
| 157 class CImpl : public C { | |
| 158 public: | |
| 159 CImpl(bool* d_called, InterfaceRequest<C> request) | |
| 160 : d_called_(d_called), binding_(this, request.Pass()) {} | |
| 161 ~CImpl() override {} | |
| 162 | |
| 163 private: | |
| 164 void D() override { *d_called_ = true; } | |
| 165 | |
| 166 bool* d_called_; | |
| 167 StrongBinding<C> binding_; | |
| 168 }; | |
| 169 | |
| 170 class BImpl : public B { | |
| 171 public: | |
| 172 BImpl(bool* d_called, InterfaceRequest<B> request) | |
| 173 : d_called_(d_called), binding_(this, request.Pass()) {} | |
| 174 ~BImpl() override {} | |
| 175 | |
| 176 private: | |
| 177 void GetC(InterfaceRequest<C> c) override { new CImpl(d_called_, c.Pass()); } | |
| 178 | |
| 179 bool* d_called_; | |
| 180 StrongBinding<B> binding_; | |
| 181 }; | |
| 182 | |
| 183 class AImpl : public A { | |
| 184 public: | |
| 185 explicit AImpl(InterfaceRequest<A> request) | |
| 186 : d_called_(false), binding_(this, request.Pass()) {} | |
| 187 ~AImpl() override {} | |
| 188 | |
| 189 bool d_called() const { return d_called_; } | |
| 190 | |
| 191 private: | |
| 192 void GetB(InterfaceRequest<B> b) override { new BImpl(&d_called_, b.Pass()); } | |
| 193 | |
| 194 bool d_called_; | |
| 195 Binding<A> binding_; | |
| 196 }; | |
| 197 | |
| 198 // Test that, for synchronous method calls that don't have return args, the | |
| 199 // bindings return right away, leaving the messages in the message pipe while | |
| 200 // closing their end. | |
| 201 TEST_F(SynchronousInterfacePtrTest, Scoping) { | |
| 202 SynchronousInterfacePtr<A> a; | |
| 203 AImpl a_impl(GetSynchronousProxy(&a)); | |
| 204 | |
| 205 EXPECT_FALSE(a_impl.d_called()); | |
| 206 | |
| 207 { | |
| 208 SynchronousInterfacePtr<B> b; | |
| 209 a->GetB(GetSynchronousProxy(&b)); | |
| 210 SynchronousInterfacePtr<C> c; | |
| 211 b->GetC(GetSynchronousProxy(&c)); | |
| 212 c->D(); | |
| 213 } | |
| 214 | |
| 215 // While B & C have fallen out of scope, the service-side endpoints of the | |
| 216 // pipes will remain until they are flushed. | |
| 217 EXPECT_FALSE(a_impl.d_called()); | |
| 218 PumpMessages(); | |
| 219 EXPECT_TRUE(a_impl.d_called()); | |
| 220 } | |
| 221 | |
| 222 } // namespace | |
| 223 } // namespace test | |
| 224 } // namespace mojo | |
| OLD | NEW |