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