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