• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "perfetto/ext/ipc/deferred.h"
18 
19 #include "perfetto/base/logging.h"
20 #include "test/gtest_and_gmock.h"
21 
22 #include "src/ipc/test/deferred_unittest_messages.gen.h"
23 
24 namespace perfetto {
25 namespace ipc {
26 namespace {
27 
28 using ::perfetto::ipc::gen::TestMessage;
29 
30 #if PERFETTO_DCHECK_IS_ON()
31 #define EXPECT_DCHECK(x) EXPECT_DEATH_IF_SUPPORTED((x), ".*")
32 #else
33 #define EXPECT_DCHECK(x) x
34 #endif
35 
TEST(DeferredTest,BindAndResolve)36 TEST(DeferredTest, BindAndResolve) {
37   Deferred<TestMessage> deferred;
38   std::shared_ptr<int> num_callbacks(new int{0});
39   deferred.Bind([num_callbacks](AsyncResult<TestMessage> msg) {
40     ASSERT_TRUE(msg.success());
41     ASSERT_TRUE(msg);
42     ASSERT_EQ(42, msg->num());
43     ASSERT_EQ(13, msg.fd());
44     ASSERT_EQ("foo", msg->str());
45     (*num_callbacks)++;
46   });
47 
48   AsyncResult<TestMessage> res = AsyncResult<TestMessage>::Create();
49   res->set_num(42);
50   res.set_fd(13);
51   (*res).set_str("foo");
52   deferred.Resolve(std::move(res));
53 
54   // A second call to Resolve() or Reject() shouldn't have any effect beause we
55   // didn't set has_more.
56   EXPECT_DCHECK(deferred.Resolve(std::move(res)));
57   EXPECT_DCHECK(deferred.Reject());
58 
59   ASSERT_EQ(1, *num_callbacks);
60 }
61 
62 // In case of a Reject() a callback with a nullptr should be received.
TEST(DeferredTest,BindAndFail)63 TEST(DeferredTest, BindAndFail) {
64   Deferred<TestMessage> deferred;
65   std::shared_ptr<int> num_callbacks(new int{0});
66   deferred.Bind([num_callbacks](AsyncResult<TestMessage> msg) {
67     ASSERT_EQ(-1, msg.fd());
68     ASSERT_FALSE(msg.success());
69     ASSERT_FALSE(msg);
70     ASSERT_EQ(nullptr, msg.operator->());
71     (*num_callbacks)++;
72   });
73 
74   AsyncResult<TestMessage> res = AsyncResult<TestMessage>::Create();
75   res.set_fd(42);
76   deferred.Reject();
77   EXPECT_DCHECK(deferred.Resolve(std::move(res)));
78   EXPECT_DCHECK(deferred.Reject());
79   ASSERT_EQ(1, *num_callbacks);
80 }
81 
82 // Test the RAII behavior.
TEST(DeferredTest,AutoRejectIfOutOfScope)83 TEST(DeferredTest, AutoRejectIfOutOfScope) {
84   std::shared_ptr<int> num_callbacks(new int{0});
85   {
86     Deferred<TestMessage> deferred;
87     deferred.Bind([num_callbacks](AsyncResult<TestMessage> msg) {
88       ASSERT_FALSE(msg.success());
89       (*num_callbacks)++;
90     });
91   }
92   ASSERT_EQ(1, *num_callbacks);
93 }
94 
95 // Binds two callbacks one after the other and tests that the bind state of the
96 // first callback is released.
TEST(DeferredTest,BindTwiceDoesNotHoldBindState)97 TEST(DeferredTest, BindTwiceDoesNotHoldBindState) {
98   // Use shared_ptr's use_count() to infer the bind state of the callback.
99   std::shared_ptr<int> num_callbacks(new int{0});
100   Deferred<TestMessage> deferred;
101   deferred.Bind(
102       [num_callbacks](AsyncResult<TestMessage>) { (*num_callbacks)++; });
103 
104   // At this point both the shared_ptr above and the callback in |deferred| are
105   // refcounting the bind state.
106   ASSERT_GE(num_callbacks.use_count(), 2);
107 
108   // Re-binding the callback should release the bind state, without invoking the
109   // old callback.
110   deferred.Bind([](AsyncResult<TestMessage>) {});
111   ASSERT_EQ(1, num_callbacks.use_count());
112   ASSERT_EQ(0, *num_callbacks);
113 
114   // Test that the new callback is invoked when re-bindings.
115   deferred.Bind([num_callbacks](AsyncResult<TestMessage> msg) {
116     ASSERT_TRUE(msg.success());
117     ASSERT_EQ(4242, msg->num());
118     (*num_callbacks)++;
119   });
120   AsyncResult<TestMessage> res = AsyncResult<TestMessage>::Create();
121   res->set_num(4242);
122   deferred.Resolve(std::move(res));
123   ASSERT_EQ(1, *num_callbacks);
124   ASSERT_EQ(1, num_callbacks.use_count());
125 }
126 
TEST(DeferredTest,MoveOperators)127 TEST(DeferredTest, MoveOperators) {
128   Deferred<TestMessage> deferred;
129   std::shared_ptr<int> num_callbacks(new int{0});
130   std::function<void(AsyncResult<TestMessage>)> callback =
131       [num_callbacks](AsyncResult<TestMessage> msg) {
132         ASSERT_TRUE(msg.success());
133         ASSERT_GE(msg->num(), 42);
134         ASSERT_LE(msg->num(), 43);
135         ASSERT_EQ(msg->num() * 10, msg.fd());
136         ASSERT_EQ(std::to_string(msg->num()), msg->str());
137         (*num_callbacks)++;
138       };
139   deferred.Bind(callback);
140 
141   // Do a bit of std::move() dance with both the Deferred and the AsyncResult.
142   AsyncResult<TestMessage> res = AsyncResult<TestMessage>::Create();
143   res.set_fd(420);
144   res->set_num(42);
145   AsyncResult<TestMessage> res_moved(std::move(res));
146   res = std::move(res_moved);
147   res->set_str("42");
148   res_moved = std::move(res);
149 
150   Deferred<TestMessage> deferred_moved(std::move(deferred));
151   deferred = std::move(deferred_moved);
152   deferred_moved = std::move(deferred);
153 
154   EXPECT_DCHECK(deferred.Reject());  // |deferred| has been cleared.
155   ASSERT_EQ(0, *num_callbacks);
156 
157   deferred_moved.Resolve(std::move(res_moved));  // This, instead, should fire.
158   ASSERT_EQ(1, *num_callbacks);
159 
160   // |deferred| and |res| have lost their state but should remain reusable.
161   deferred.Bind(callback);
162   res = AsyncResult<TestMessage>::Create();
163   res.set_fd(430);
164   res->set_num(43);
165   res->set_str("43");
166   deferred.Resolve(std::move(res));
167   ASSERT_EQ(2, *num_callbacks);
168 
169   // Finally re-bind |deferred|, move it to a new scoped Deferred and verify
170   // that the moved-into object still auto-nacks the callback.
171   deferred.Bind([num_callbacks](AsyncResult<TestMessage> msg) {
172     ASSERT_FALSE(msg.success());
173     (*num_callbacks)++;
174   });
175   { Deferred<TestMessage> scoped_deferred(std::move(deferred)); }
176   ASSERT_EQ(3, *num_callbacks);
177   callback = nullptr;
178   ASSERT_EQ(1, num_callbacks.use_count());
179 }
180 
181 // Covers the case of a streaming reply, where the deferred keeps being resolved
182 // until has_more == true.
TEST(DeferredTest,StreamingReply)183 TEST(DeferredTest, StreamingReply) {
184   Deferred<TestMessage> deferred;
185   std::shared_ptr<int> num_callbacks(new int{0});
186   std::function<void(AsyncResult<TestMessage>)> callback =
187       [num_callbacks](AsyncResult<TestMessage> msg) {
188         ASSERT_TRUE(msg.success());
189         ASSERT_EQ(*num_callbacks == 0 ? 13 : -1, msg.fd());
190         ASSERT_EQ(*num_callbacks, msg->num());
191         ASSERT_EQ(std::to_string(*num_callbacks), msg->str());
192         ASSERT_EQ(msg->num() < 3, msg.has_more());
193         (*num_callbacks)++;
194       };
195   deferred.Bind(callback);
196 
197   for (int i = 0; i < 3; i++) {
198     AsyncResult<TestMessage> res = AsyncResult<TestMessage>::Create();
199     res.set_fd(i == 0 ? 13 : -1);
200     res->set_num(i);
201     res->set_str(std::to_string(i));
202     res.set_has_more(true);
203     AsyncResult<TestMessage> res_moved(std::move(res));
204     deferred.Resolve(std::move(res_moved));
205   }
206 
207   Deferred<TestMessage> deferred_moved(std::move(deferred));
208   AsyncResult<TestMessage> res = AsyncResult<TestMessage>::Create();
209   res->set_num(3);
210   res->set_str(std::to_string(3));
211   res.set_has_more(false);
212   deferred_moved.Resolve(std::move(res));
213   ASSERT_EQ(4, *num_callbacks);
214 
215   EXPECT_DCHECK(deferred_moved.Reject());
216   ASSERT_EQ(4, *num_callbacks);
217   callback = nullptr;
218   ASSERT_EQ(1, num_callbacks.use_count());
219 }
220 
221 // Similar to the above, but checks that destroying a Deferred without having
222 // resolved with has_more == true automatically rejects once out of scope.
TEST(DeferredTest,StreamingReplyIsRejectedOutOfScope)223 TEST(DeferredTest, StreamingReplyIsRejectedOutOfScope) {
224   std::shared_ptr<int> num_callbacks(new int{0});
225 
226   {
227     Deferred<TestMessage> deferred;
228     deferred.Bind([num_callbacks](AsyncResult<TestMessage> msg) {
229       ASSERT_EQ((*num_callbacks) < 3, msg.success());
230       ASSERT_EQ(msg.success(), msg.has_more());
231       (*num_callbacks)++;
232     });
233 
234     for (int i = 0; i < 3; i++) {
235       AsyncResult<TestMessage> res = AsyncResult<TestMessage>::Create();
236       res.set_has_more(true);
237       deferred.Resolve(std::move(res));
238     }
239 
240     // |deferred_moved| going out of scope should cause a Reject().
241     { Deferred<TestMessage> deferred_moved = std::move(deferred); }
242     ASSERT_EQ(4, *num_callbacks);
243   }
244 
245   // |deferred| going out of scope should do noting, it has been std::move()'d.
246   ASSERT_EQ(4, *num_callbacks);
247   ASSERT_EQ(1, num_callbacks.use_count());
248 }
249 
250 // Tests that a Deferred<Specialized> still behaves sanely after it has been
251 // moved into a DeferredBase.
TEST(DeferredTest,MoveAsBase)252 TEST(DeferredTest, MoveAsBase) {
253   Deferred<TestMessage> deferred;
254   std::shared_ptr<int> num_callbacks(new int{0});
255   deferred.Bind([num_callbacks](AsyncResult<TestMessage> msg) {
256     ASSERT_TRUE(msg.success());
257     ASSERT_EQ(13, msg.fd());
258     ASSERT_EQ(42, msg->num());
259     ASSERT_EQ("foo", msg->str());
260     (*num_callbacks)++;
261   });
262 
263   DeferredBase deferred_base(std::move(deferred));
264   ASSERT_FALSE(deferred.IsBound());
265   ASSERT_TRUE(deferred_base.IsBound());
266 
267   std::unique_ptr<TestMessage> msg(new TestMessage());
268   msg->set_num(42);
269   msg->set_str("foo");
270 
271   AsyncResult<ProtoMessage> async_result_base(std::move(msg));
272   async_result_base.set_fd(13);
273   deferred_base.Resolve(std::move(async_result_base));
274 
275   EXPECT_DCHECK(deferred_base.Resolve(std::move(async_result_base)));
276   EXPECT_DCHECK(deferred_base.Reject());
277 
278   ASSERT_EQ(1, *num_callbacks);
279 }
280 
281 }  // namespace
282 }  // namespace ipc
283 }  // namespace perfetto
284