Home | History | Annotate | Download | only in ipc
      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 
     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 
     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.
     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.
     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.
     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 
    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.
    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.
    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.
    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