1/*
2 * Copyright (C) 2017 The Android Open foo 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
24namespace perfetto {
25namespace ipc {
26namespace {
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
34TEST(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.
61TEST(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.
81TEST(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.
95TEST(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
125TEST(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.
181TEST(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.
221TEST(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.
250TEST(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