activity_test.cc
Go to the documentation of this file.
1 // Copyright 2021 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
16 
17 #include <stdlib.h>
18 
19 #include <functional>
20 #include <tuple>
21 
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24 
30 
31 using testing::_;
32 using testing::Mock;
34 using testing::SaveArg;
36 
37 namespace grpc_core {
38 
39 // A simple Barrier type: stalls progress until it is 'cleared'.
40 class Barrier {
41  public:
42  struct Result {};
43 
45  return [this]() -> Poll<Result> {
46  MutexLock lock(&mu_);
47  if (cleared_) {
48  return Result{};
49  } else {
50  return wait_set_.AddPending(Activity::current()->MakeOwningWaker());
51  }
52  };
53  }
54 
55  void Clear() {
56  mu_.Lock();
57  cleared_ = true;
58  auto wakeup = wait_set_.TakeWakeupSet();
59  mu_.Unlock();
60  wakeup.Wakeup();
61  }
62 
63  private:
65  WaitSet wait_set_ ABSL_GUARDED_BY(mu_);
66  bool cleared_ ABSL_GUARDED_BY(mu_) = false;
67 };
68 
69 // A simple Barrier type: stalls progress until it is 'cleared'.
70 // This variant supports only a single waiter.
72  public:
73  struct Result {};
74 
76  return [this]() -> Poll<Result> {
77  MutexLock lock(&mu_);
78  if (cleared_) {
79  return Result{};
80  } else {
81  waker_ = Activity::current()->MakeOwningWaker();
82  return Pending();
83  }
84  };
85  }
86 
87  void Clear() {
88  mu_.Lock();
89  cleared_ = true;
90  auto waker = std::move(waker_);
91  mu_.Unlock();
92  waker.Wakeup();
93  }
94 
95  private:
97  Waker waker_ ABSL_GUARDED_BY(mu_);
98  bool cleared_ ABSL_GUARDED_BY(mu_) = false;
99 };
100 
101 TEST(ActivityTest, ImmediatelyCompleteWithSuccess) {
102  StrictMock<MockFunction<void(absl::Status)>> on_done;
103  EXPECT_CALL(on_done, Call(absl::OkStatus()));
104  MakeActivity(
105  [] { return [] { return absl::OkStatus(); }; }, NoWakeupScheduler(),
106  [&on_done](absl::Status status) { on_done.Call(std::move(status)); });
107 }
108 
109 TEST(ActivityTest, ImmediatelyCompleteWithFailure) {
110  StrictMock<MockFunction<void(absl::Status)>> on_done;
112  MakeActivity(
113  [] { return [] { return absl::CancelledError(); }; }, NoWakeupScheduler(),
114  [&on_done](absl::Status status) { on_done.Call(std::move(status)); });
115 }
116 
117 TEST(ActivityTest, DropImmediately) {
118  StrictMock<MockFunction<void(absl::Status)>> on_done;
120  MakeActivity(
121  [] { return []() -> Poll<absl::Status> { return Pending(); }; },
123  [&on_done](absl::Status status) { on_done.Call(std::move(status)); });
124 }
125 
126 template <typename B>
127 class BarrierTest : public testing::Test {
128  public:
129  using Type = B;
130 };
131 
134 
136  typename TestFixture::Type b;
137  StrictMock<MockFunction<void(absl::Status)>> on_done;
138  auto activity = MakeActivity(
139  [&b] {
140  return Seq(b.Wait(), [](typename TestFixture::Type::Result) {
141  return absl::OkStatus();
142  });
143  },
145  [&on_done](absl::Status status) { on_done.Call(std::move(status)); });
146  // Clearing the barrier should let the activity proceed to return a result.
147  EXPECT_CALL(on_done, Call(absl::OkStatus()));
148  b.Clear();
149 }
150 
151 TYPED_TEST(BarrierTest, BarrierPing) {
152  typename TestFixture::Type b1;
153  typename TestFixture::Type b2;
154  StrictMock<MockFunction<void(absl::Status)>> on_done1;
155  StrictMock<MockFunction<void(absl::Status)>> on_done2;
156  MockCallbackScheduler scheduler1;
157  MockCallbackScheduler scheduler2;
158  auto activity1 = MakeActivity(
159  [&b1, &b2] {
160  return Seq(b1.Wait(), [&b2](typename TestFixture::Type::Result) {
161  // Clear the barrier whilst executing an activity
162  b2.Clear();
163  return absl::OkStatus();
164  });
165  },
166  UseMockCallbackScheduler{&scheduler1},
167  [&on_done1](absl::Status status) { on_done1.Call(std::move(status)); });
168  auto activity2 = MakeActivity(
169  [&b2] {
170  return Seq(b2.Wait(), [](typename TestFixture::Type::Result) {
171  return absl::OkStatus();
172  });
173  },
174  UseMockCallbackScheduler{&scheduler2},
175  [&on_done2](absl::Status status) { on_done2.Call(std::move(status)); });
176  // Since barrier triggers inside activity1 promise, activity2 wakeup will be
177  // scheduled from a callback.
178  std::function<void()> cb1;
179  std::function<void()> cb2;
180  EXPECT_CALL(scheduler1, Schedule(_)).WillOnce(SaveArg<0>(&cb1));
181  b1.Clear();
182  Mock::VerifyAndClearExpectations(&scheduler1);
183  EXPECT_CALL(on_done1, Call(absl::OkStatus()));
184  EXPECT_CALL(scheduler2, Schedule(_)).WillOnce(SaveArg<0>(&cb2));
185  cb1();
186  Mock::VerifyAndClearExpectations(&on_done1);
187  EXPECT_CALL(on_done2, Call(absl::OkStatus()));
188  cb2();
189 }
190 
192  typename TestFixture::Type b;
193  StrictMock<MockFunction<void(absl::Status)>> on_done;
194  EXPECT_CALL(on_done, Call(absl::OkStatus()));
195  MakeActivity(
196  [&b] {
197  return Seq(Join(b.Wait(),
198  [&b] {
199  b.Clear();
200  return 1;
201  }),
202  [](std::tuple<typename TestFixture::Type::Result, int>) {
203  return absl::OkStatus();
204  });
205  },
207  [&on_done](absl::Status status) { on_done.Call(std::move(status)); });
208 }
209 
210 TYPED_TEST(BarrierTest, WakeAfterDestruction) {
211  typename TestFixture::Type b;
212  {
213  StrictMock<MockFunction<void(absl::Status)>> on_done;
215  MakeActivity(
216  [&b] {
217  return Seq(b.Wait(), [](typename TestFixture::Type::Result) {
218  return absl::OkStatus();
219  });
220  },
222  [&on_done](absl::Status status) { on_done.Call(std::move(status)); });
223  }
224  b.Clear();
225 }
226 
227 TEST(ActivityTest, ForceWakeup) {
228  StrictMock<MockFunction<void(absl::Status)>> on_done;
229  int run_count = 0;
230  auto activity = MakeActivity(
231  [&run_count]() -> Poll<absl::Status> {
232  ++run_count;
233  switch (run_count) {
234  case 1:
235  return Pending{};
236  case 2:
237  return absl::OkStatus();
238  default:
239  abort();
240  }
241  },
243  [&on_done](absl::Status status) { on_done.Call(std::move(status)); });
244  EXPECT_CALL(on_done, Call(absl::OkStatus()));
245  activity->ForceWakeup();
246 }
247 
248 struct TestContext {
249  bool* done;
250 };
251 template <>
253 
254 TEST(ActivityTest, WithContext) {
255  bool done = false;
256  StrictMock<MockFunction<void(absl::Status)>> on_done;
257  EXPECT_CALL(on_done, Call(absl::OkStatus()));
258  MakeActivity(
259  [] {
260  *GetContext<TestContext>()->done = true;
261  return Immediate(absl::OkStatus());
262  },
264  [&on_done](absl::Status status) { on_done.Call(std::move(status)); },
265  TestContext{&done});
266  EXPECT_TRUE(done);
267 }
268 
269 TEST(ActivityTest, CanCancelDuringExecution) {
270  ActivityPtr activity;
271  StrictMock<MockFunction<void(absl::Status)>> on_done;
272  int run_count = 0;
273 
274  activity = MakeActivity(
275  [&activity, &run_count]() -> Poll<absl::Status> {
276  ++run_count;
277  switch (run_count) {
278  case 1:
279  return Pending{};
280  case 2:
281  activity.reset();
282  return Pending{};
283  default:
284  abort();
285  }
286  },
288  [&on_done](absl::Status status) { on_done.Call(std::move(status)); });
289 
291  activity->ForceWakeup();
292 }
293 
294 TEST(ActivityTest, CanCancelDuringSuccessfulExecution) {
295  ActivityPtr activity;
296  StrictMock<MockFunction<void(absl::Status)>> on_done;
297  int run_count = 0;
298 
299  activity = MakeActivity(
300  [&activity, &run_count]() -> Poll<absl::Status> {
301  ++run_count;
302  switch (run_count) {
303  case 1:
304  return Pending{};
305  case 2:
306  activity.reset();
307  return absl::OkStatus();
308  default:
309  abort();
310  }
311  },
313  [&on_done](absl::Status status) { on_done.Call(std::move(status)); });
314 
315  EXPECT_CALL(on_done, Call(absl::OkStatus()));
316  activity->ForceWakeup();
317 }
318 
319 TEST(WakerTest, CanWakeupEmptyWaker) {
320  // Empty wakers should not do anything upon wakeup.
321  Waker().Wakeup();
322 }
323 
324 } // namespace grpc_core
325 
326 int main(int argc, char** argv) {
327  ::testing::InitGoogleTest(&argc, argv);
328  return RUN_ALL_TESTS();
329 }
testing::StrictMock
Definition: bloaty/third_party/googletest/googlemock/include/gmock/gmock-nice-strict.h:148
Type
struct Type Type
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/protobuf.h:673
grpc_core::SingleBarrier
Definition: activity_test.cc:71
grpc_core
Definition: call_metric_recorder.h:31
grpc_core::Activity::current
static Activity * current()
Definition: activity.h:124
grpc_core::MutexLock
Definition: src/core/lib/gprpp/sync.h:88
absl::CancelledError
Status CancelledError(absl::string_view message)
Definition: third_party/abseil-cpp/absl/status/status.cc:331
grpc_core::Barrier
Definition: activity_test.cc:40
absl::OkStatus
Status OkStatus()
Definition: third_party/abseil-cpp/absl/status/status.h:882
grpc_core::TEST
TEST(AvlTest, NoOp)
Definition: avl_test.cc:21
status
absl::Status status
Definition: rls.cc:251
grpc_core::Barrier::Clear
void Clear()
Definition: activity_test.cc:55
seq.h
testing::Test
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:402
grpc_core::MakeActivity
ActivityPtr MakeActivity(Factory promise_factory, WakeupScheduler wakeup_scheduler, OnDone on_done, Contexts &&... contexts)
Definition: activity.h:522
testing::internal::ProxyTypeList
Definition: googletest/googletest/include/gtest/internal/gtest-type-util.h:155
grpc_core::ContextType
Definition: core/lib/promise/context.h:32
grpc_core::Pending
Definition: poll.h:29
wait_set.h
grpc_core::SingleBarrier::ABSL_GUARDED_BY
Waker waker_ ABSL_GUARDED_BY(mu_)
grpc_core::SingleBarrier::Clear
void Clear()
Definition: activity_test.cc:87
absl::move
constexpr absl::remove_reference_t< T > && move(T &&t) noexcept
Definition: abseil-cpp/absl/utility/utility.h:221
grpc_core::Mutex::Lock
void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION()
Definition: src/core/lib/gprpp/sync.h:69
re2::Result
TestInstance::Result Result
Definition: bloaty/third_party/re2/re2/testing/tester.cc:96
b2
T::second_type b2
Definition: abseil-cpp/absl/container/internal/hash_function_defaults_test.cc:308
Type
Definition: bloaty/third_party/protobuf/src/google/protobuf/type.pb.h:182
grpc_core::TestContext
Definition: activity_test.cc:248
grpc_core::WaitSet
Definition: wait_set.h:40
grpc_core::InlineWakeupScheduler
Definition: test_wakeup_schedulers.h:38
testing::SaveArg
internal::SaveArgAction< k, Ptr > SaveArg(Ptr pointer)
Definition: googletest/googlemock/include/gmock/gmock-actions.h:1413
gmock_output_test._
_
Definition: bloaty/third_party/googletest/googlemock/test/gmock_output_test.py:175
grpc_core::Barrier::Wait
Promise< Result > Wait()
Definition: activity_test.cc:44
done
struct tab * done
Definition: bloaty/third_party/zlib/examples/enough.c:176
grpc_core::TYPED_TEST
TYPED_TEST(BarrierTest, Barrier)
Definition: activity_test.cc:135
grpc_core::Barrier::Result
Definition: activity_test.cc:42
grpc_core::ActivityPtr
OrphanablePtr< Activity > ActivityPtr
Definition: activity.h:163
RUN_ALL_TESTS
int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2471
b
uint64_t b
Definition: abseil-cpp/absl/container/internal/layout_test.cc:53
grpc_core::MockCallbackScheduler
Definition: test_wakeup_schedulers.h:46
promise.h
EXPECT_CALL
#define EXPECT_CALL(obj, call)
test_wakeup_schedulers.h
grpc_core::WithContext
promise_detail::WithContext< T, F > WithContext(F f, T *context)
Definition: core/lib/promise/context.h:80
grpc_core::Activity::MakeOwningWaker
virtual Waker MakeOwningWaker()=0
b1
T::second_type b1
Definition: abseil-cpp/absl/container/internal/hash_function_defaults_test.cc:306
testing::Mock
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:9549
grpc_core::Barrier::ABSL_GUARDED_BY
WaitSet wait_set_ ABSL_GUARDED_BY(mu_)
grpc_core::Mutex
Definition: src/core/lib/gprpp/sync.h:61
grpc_core::Mutex::Unlock
void Unlock() ABSL_UNLOCK_FUNCTION()
Definition: src/core/lib/gprpp/sync.h:70
join.h
testing::_
const internal::AnythingMatcher _
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:8548
testing::InitGoogleTest
GTEST_API_ void InitGoogleTest(int *argc, char **argv)
Definition: bloaty/third_party/googletest/googletest/src/gtest.cc:6106
main
int main(int argc, char **argv)
Definition: activity_test.cc:326
grpc_core::Waker
Definition: activity.h:61
tests.unit._server_ssl_cert_config_test.Call
Call
Definition: _server_ssl_cert_config_test.py:70
grpc_core::Promise
std::function< Poll< T >()> Promise
Definition: promise/promise.h:37
absl::Status
Definition: third_party/abseil-cpp/absl/status/status.h:424
grpc_core::TestContext::done
bool * done
Definition: activity_test.cc:249
testing::MockFunction
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:11854
grpc_core::SingleBarrier::Wait
Promise< Result > Wait()
Definition: activity_test.cc:75
grpc_core::TYPED_TEST_SUITE
TYPED_TEST_SUITE(BarrierTest, BarrierTestTypes)
EXPECT_TRUE
#define EXPECT_TRUE(condition)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1967
grpc_core::UseMockCallbackScheduler
Definition: test_wakeup_schedulers.h:58
grpc_core::NoWakeupScheduler
Definition: test_wakeup_schedulers.h:28
grpc_core::Immediate
promise_detail::Immediate< T > Immediate(T value)
Definition: promise/promise.h:73
grpc_core::Waker::Wakeup
void Wakeup()
Definition: activity.h:77
grpc_core::Seq
promise_detail::Seq< Functors... > Seq(Functors... functors)
Definition: seq.h:62
grpc_core::SingleBarrier::Result
Definition: activity_test.cc:73
function
std::function< bool(GrpcTool *, int, const char **, const CliCredentials &, GrpcToolOutputCallback)> function
Definition: grpc_tool.cc:250
activity.h
absl::variant
Definition: abseil-cpp/absl/types/internal/variant.h:46
grpc_core::BarrierTest
Definition: activity_test.cc:127
grpc_core::Barrier::mu_
Mutex mu_
Definition: activity_test.cc:64
grpc_core::SingleBarrier::mu_
Mutex mu_
Definition: activity_test.cc:96
grpc_core::Join
promise_detail::Join< Promise... > Join(Promise... promises)
Definition: join.h:49


grpc
Author(s):
autogenerated on Thu Mar 13 2025 02:58:29