Skip to content

Commit 3de80e6

Browse files
committed
cc core: add thorough tests for Async* functions
commit_hash:46d768f0c68eb8322dcd323d14debd4b8b1bdd9a
1 parent 893c9aa commit 3de80e6

5 files changed

Lines changed: 293 additions & 0 deletions

File tree

core/include/userver/engine/task/current_task.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ class ThreadControl;
1616

1717
namespace engine {
1818

19+
class Deadline;
20+
1921
/// @brief Namespace with functions to work with current task from within it
2022
namespace current_task {
2123

@@ -45,6 +47,10 @@ void* GetRawCurrentTaskContext() noexcept;
4547
// For internal use only.
4648
bool IsCritical();
4749

50+
// Note: an actually useful deadline should be acquired from server::request::GetTaskInheritedDeadline.
51+
// For internal use only.
52+
Deadline GetDeadline() noexcept;
53+
4854
} // namespace impl
4955

5056
} // namespace current_task

core/src/engine/task/async_test.cpp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
#include <userver/utest/utest.hpp>
22

33
#include <atomic>
4+
#include <concepts>
45

56
#include <userver/engine/async.hpp>
67
#include <userver/engine/sleep.hpp>
78
#include <userver/engine/task/cancel.hpp>
9+
#include <userver/engine/task/current_task.hpp>
10+
#include <userver/engine/task/inherited_variable.hpp>
11+
#include <userver/engine/task/task_with_result.hpp>
12+
#include <userver/tracing/span.hpp>
813
#include <userver/utils/lazy_prvalue.hpp>
914

1015
#include <compiler/relax_cpu.hpp>
1116
#include <engine/task/task_context.hpp>
17+
#include <engine/tests/task_processor_utils.hpp>
1218

1319
USERVER_NAMESPACE_BEGIN
1420

@@ -328,4 +334,78 @@ UTEST_MT(Async, CancelNotifyRace, 4) {
328334
}
329335
}
330336

337+
namespace {
338+
339+
engine::TaskInheritedVariable<int> kInheritedVariable;
340+
341+
} // namespace
342+
343+
UTEST(Async, AsyncNoSpanCapturesExpectedContext) {
344+
kInheritedVariable.Set(42);
345+
346+
auto task = engine::AsyncNoSpan([inherited = kInheritedVariable.Get()] {
347+
EXPECT_FALSE(tracing::Span::CurrentSpanUnchecked());
348+
EXPECT_EQ(inherited, 42);
349+
EXPECT_FALSE(engine::current_task::impl::IsCritical());
350+
EXPECT_EQ(engine::current_task::impl::GetDeadline(), engine::Deadline{});
351+
return true;
352+
});
353+
static_assert(std::same_as<decltype(task), engine::TaskWithResult<bool>>);
354+
355+
EXPECT_TRUE(task.Get());
356+
}
357+
358+
TEST(Async, AsyncNoSpanWithTaskProcessorCapturesExpectedContext) {
359+
engine::tests::TwoStandaloneTaskProcessors tp;
360+
tp.RunBlocking([&] {
361+
kInheritedVariable.Set(42);
362+
363+
auto task = engine::AsyncNoSpan(tp.GetSecondary(), [&, inherited = kInheritedVariable.Get()] {
364+
EXPECT_FALSE(tracing::Span::CurrentSpanUnchecked());
365+
EXPECT_EQ(inherited, 42);
366+
EXPECT_FALSE(engine::current_task::impl::IsCritical());
367+
EXPECT_EQ(engine::current_task::impl::GetDeadline(), engine::Deadline{});
368+
EXPECT_EQ(&engine::current_task::GetTaskProcessor(), &tp.GetSecondary());
369+
return true;
370+
});
371+
static_assert(std::same_as<decltype(task), engine::TaskWithResult<bool>>);
372+
373+
EXPECT_TRUE(task.Get());
374+
});
375+
}
376+
377+
UTEST(Async, CriticalAsyncNoSpanCapturesExpectedContext) {
378+
kInheritedVariable.Set(42);
379+
380+
auto task = engine::CriticalAsyncNoSpan([inherited = kInheritedVariable.Get()] {
381+
EXPECT_FALSE(tracing::Span::CurrentSpanUnchecked());
382+
EXPECT_EQ(inherited, 42);
383+
EXPECT_TRUE(engine::current_task::impl::IsCritical());
384+
EXPECT_EQ(engine::current_task::impl::GetDeadline(), engine::Deadline{});
385+
return true;
386+
});
387+
static_assert(std::same_as<decltype(task), engine::TaskWithResult<bool>>);
388+
389+
EXPECT_TRUE(task.Get());
390+
}
391+
392+
TEST(Async, CriticalAsyncNoSpanWithTaskProcessorCapturesExpectedContext) {
393+
engine::tests::TwoStandaloneTaskProcessors tp;
394+
tp.RunBlocking([&] {
395+
kInheritedVariable.Set(42);
396+
397+
auto task = engine::CriticalAsyncNoSpan(tp.GetSecondary(), [&, inherited = kInheritedVariable.Get()] {
398+
EXPECT_FALSE(tracing::Span::CurrentSpanUnchecked());
399+
EXPECT_EQ(inherited, 42);
400+
EXPECT_TRUE(engine::current_task::impl::IsCritical());
401+
EXPECT_EQ(engine::current_task::impl::GetDeadline(), engine::Deadline{});
402+
EXPECT_EQ(&engine::current_task::GetTaskProcessor(), &tp.GetSecondary());
403+
return true;
404+
});
405+
static_assert(std::same_as<decltype(task), engine::TaskWithResult<bool>>);
406+
407+
EXPECT_TRUE(task.Get());
408+
});
409+
}
410+
331411
USERVER_NAMESPACE_END

core/src/engine/task/task_base.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ void* GetRawCurrentTaskContext() noexcept { return current_task::GetCurrentTaskC
165165

166166
bool IsCritical() { return GetCurrentTaskContext().WasStartedAsCritical(); }
167167

168+
Deadline GetDeadline() noexcept { return GetCurrentTaskContext().GetCancelDeadline(); }
169+
168170
} // namespace impl
169171

170172
} // namespace current_task

core/src/engine/task/task_context.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ class TaskContext final : public ContextAccessor, public Awaiter, public deadloc
169169
void SetQueueWaitTimepoint(std::chrono::steady_clock::time_point tp) { task_queue_wait_timepoint_ = tp; }
170170

171171
void SetCancelDeadline(Deadline deadline);
172+
Deadline GetCancelDeadline() const noexcept { return cancel_deadline_; }
172173

173174
bool HasLocalStorage() const noexcept;
174175
task_local::Storage& GetLocalStorage() noexcept;

core/src/utils/async_test.cpp

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,22 @@
11
#include <userver/utils/async.hpp>
22

3+
#include <concepts>
34
#include <vector>
45

56
#include <boost/range/adaptor/transformed.hpp>
67
#include <boost/range/numeric.hpp>
78

89
#include <userver/concurrent/variable.hpp>
10+
#include <userver/engine/sleep.hpp>
11+
#include <userver/engine/task/current_task.hpp>
12+
#include <userver/engine/task/inherited_variable.hpp>
913
#include <userver/engine/task/task_with_result.hpp>
14+
#include <userver/tracing/span.hpp>
1015
#include <userver/utest/utest.hpp>
1116

1217
#include <engine/ev/thread_control.hpp>
18+
#include <engine/task/task_context.hpp>
19+
#include <engine/tests/task_processor_utils.hpp>
1320

1421
USERVER_NAMESPACE_BEGIN
1522

@@ -122,4 +129,201 @@ Response AsyncRequestProcessor::Foo(Request&& request) { return request * 2; }
122129

123130
} // namespace
124131

132+
namespace {
133+
134+
engine::TaskInheritedVariable<int> kInheritedVariable;
135+
136+
} // namespace
137+
138+
UTEST(UtilsAsync, AsyncCapturesExpectedContext) {
139+
kInheritedVariable.Set(42);
140+
const auto parent_trace_id = tracing::Span::CurrentSpan().GetTraceId();
141+
142+
auto task = utils::Async("async", [&, inherited = kInheritedVariable.Get()] {
143+
EXPECT_TRUE(tracing::Span::CurrentSpanUnchecked());
144+
EXPECT_EQ(tracing::Span::CurrentSpan().GetTraceId(), parent_trace_id);
145+
EXPECT_EQ(inherited, 42);
146+
EXPECT_FALSE(engine::current_task::impl::IsCritical());
147+
EXPECT_FALSE(engine::current_task::IsCancelRequested());
148+
return true;
149+
});
150+
static_assert(std::same_as<decltype(task), engine::TaskWithResult<bool>>);
151+
152+
EXPECT_TRUE(task.Get());
153+
}
154+
155+
TEST(UtilsAsync, AsyncWithTaskProcessorCapturesExpectedContext) {
156+
engine::tests::TwoStandaloneTaskProcessors tp;
157+
tp.RunBlocking([&] {
158+
kInheritedVariable.Set(42);
159+
const auto parent_trace_id = tracing::Span::CurrentSpan().GetTraceId();
160+
161+
auto task = utils::Async(tp.GetSecondary(), "async", [&, inherited = kInheritedVariable.Get()] {
162+
EXPECT_TRUE(tracing::Span::CurrentSpanUnchecked());
163+
EXPECT_EQ(tracing::Span::CurrentSpan().GetTraceId(), parent_trace_id);
164+
EXPECT_EQ(inherited, 42);
165+
EXPECT_FALSE(engine::current_task::impl::IsCritical());
166+
EXPECT_FALSE(engine::current_task::IsCancelRequested());
167+
EXPECT_EQ(&engine::current_task::GetTaskProcessor(), &tp.GetSecondary());
168+
return true;
169+
});
170+
static_assert(std::same_as<decltype(task), engine::TaskWithResult<bool>>);
171+
172+
EXPECT_TRUE(task.Get());
173+
});
174+
}
175+
176+
TEST(UtilsAsync, CriticalAsyncWithTaskProcessorCapturesExpectedContext) {
177+
engine::tests::TwoStandaloneTaskProcessors tp;
178+
tp.RunBlocking([&] {
179+
kInheritedVariable.Set(42);
180+
const auto parent_trace_id = tracing::Span::CurrentSpan().GetTraceId();
181+
182+
auto task = utils::CriticalAsync(tp.GetSecondary(), "async", [&, inherited = kInheritedVariable.Get()] {
183+
EXPECT_TRUE(tracing::Span::CurrentSpanUnchecked());
184+
EXPECT_EQ(tracing::Span::CurrentSpan().GetTraceId(), parent_trace_id);
185+
EXPECT_EQ(inherited, 42);
186+
EXPECT_TRUE(engine::current_task::impl::IsCritical());
187+
EXPECT_FALSE(engine::current_task::IsCancelRequested());
188+
EXPECT_EQ(&engine::current_task::GetTaskProcessor(), &tp.GetSecondary());
189+
return true;
190+
});
191+
static_assert(std::same_as<decltype(task), engine::TaskWithResult<bool>>);
192+
193+
EXPECT_TRUE(task.Get());
194+
});
195+
}
196+
197+
TEST(UtilsAsync, SharedAsyncWithTaskProcessorCapturesExpectedContext) {
198+
engine::tests::TwoStandaloneTaskProcessors tp;
199+
tp.RunBlocking([&] {
200+
kInheritedVariable.Set(42);
201+
const auto parent_trace_id = tracing::Span::CurrentSpan().GetTraceId();
202+
203+
auto task = utils::SharedAsync(tp.GetSecondary(), "async", [&, inherited = kInheritedVariable.Get()] {
204+
EXPECT_TRUE(tracing::Span::CurrentSpanUnchecked());
205+
EXPECT_EQ(tracing::Span::CurrentSpan().GetTraceId(), parent_trace_id);
206+
EXPECT_EQ(inherited, 42);
207+
EXPECT_FALSE(engine::current_task::impl::IsCritical());
208+
EXPECT_FALSE(engine::current_task::IsCancelRequested());
209+
EXPECT_EQ(&engine::current_task::GetTaskProcessor(), &tp.GetSecondary());
210+
return true;
211+
});
212+
static_assert(std::same_as<decltype(task), engine::SharedTaskWithResult<bool>>);
213+
214+
EXPECT_TRUE(task.Get());
215+
});
216+
}
217+
218+
UTEST(UtilsAsync, CriticalAsyncCapturesExpectedContext) {
219+
kInheritedVariable.Set(42);
220+
const auto parent_trace_id = tracing::Span::CurrentSpan().GetTraceId();
221+
222+
auto task = utils::CriticalAsync("async", [&, inherited = kInheritedVariable.Get()] {
223+
EXPECT_TRUE(tracing::Span::CurrentSpanUnchecked());
224+
EXPECT_EQ(tracing::Span::CurrentSpan().GetTraceId(), parent_trace_id);
225+
EXPECT_EQ(inherited, 42);
226+
EXPECT_TRUE(engine::current_task::impl::IsCritical());
227+
EXPECT_FALSE(engine::current_task::IsCancelRequested());
228+
return true;
229+
});
230+
static_assert(std::same_as<decltype(task), engine::TaskWithResult<bool>>);
231+
232+
EXPECT_TRUE(task.Get());
233+
}
234+
235+
UTEST(UtilsAsync, SharedCriticalAsyncCapturesExpectedContext) {
236+
kInheritedVariable.Set(42);
237+
const auto parent_trace_id = tracing::Span::CurrentSpan().GetTraceId();
238+
239+
auto task = utils::SharedCriticalAsync("async", [&, inherited = kInheritedVariable.Get()] {
240+
EXPECT_TRUE(tracing::Span::CurrentSpanUnchecked());
241+
EXPECT_EQ(tracing::Span::CurrentSpan().GetTraceId(), parent_trace_id);
242+
EXPECT_EQ(inherited, 42);
243+
EXPECT_TRUE(engine::current_task::impl::IsCritical());
244+
EXPECT_FALSE(engine::current_task::IsCancelRequested());
245+
return true;
246+
});
247+
static_assert(std::same_as<decltype(task), engine::SharedTaskWithResult<bool>>);
248+
249+
EXPECT_TRUE(task.Get());
250+
}
251+
252+
UTEST(UtilsAsync, SharedAsyncCapturesExpectedContext) {
253+
kInheritedVariable.Set(42);
254+
const auto parent_trace_id = tracing::Span::CurrentSpan().GetTraceId();
255+
256+
auto task = utils::SharedAsync("async", [&, inherited = kInheritedVariable.Get()] {
257+
EXPECT_TRUE(tracing::Span::CurrentSpanUnchecked());
258+
EXPECT_EQ(tracing::Span::CurrentSpan().GetTraceId(), parent_trace_id);
259+
EXPECT_EQ(inherited, 42);
260+
EXPECT_FALSE(engine::current_task::impl::IsCritical());
261+
EXPECT_FALSE(engine::current_task::IsCancelRequested());
262+
return true;
263+
});
264+
static_assert(std::same_as<decltype(task), engine::SharedTaskWithResult<bool>>);
265+
266+
EXPECT_TRUE(task.Get());
267+
}
268+
269+
UTEST(UtilsAsync, AsyncWithDeadlineCapturesExpectedContext) {
270+
kInheritedVariable.Set(42);
271+
const auto parent_trace_id = tracing::Span::CurrentSpan().GetTraceId();
272+
273+
const auto deadline = engine::Deadline::FromDuration(utest::kMaxTestWaitTime);
274+
auto task = utils::Async("async", deadline, [&, inherited = kInheritedVariable.Get()] {
275+
EXPECT_TRUE(tracing::Span::CurrentSpanUnchecked());
276+
EXPECT_EQ(tracing::Span::CurrentSpan().GetTraceId(), parent_trace_id);
277+
EXPECT_EQ(inherited, 42);
278+
EXPECT_FALSE(engine::current_task::impl::IsCritical());
279+
EXPECT_EQ(engine::current_task::impl::GetDeadline(), deadline);
280+
return true;
281+
});
282+
static_assert(std::same_as<decltype(task), engine::TaskWithResult<bool>>);
283+
284+
EXPECT_TRUE(task.Get());
285+
}
286+
287+
TEST(UtilsAsync, AsyncBackgroundCapturesExpectedContext) {
288+
engine::tests::TwoStandaloneTaskProcessors tp;
289+
tp.RunBlocking([&] {
290+
kInheritedVariable.Set(42);
291+
const auto parent_trace_id = tracing::Span::CurrentSpan().GetTraceId();
292+
293+
auto task = utils::AsyncBackground("async", tp.GetSecondary(), [&, parent_trace_id] {
294+
EXPECT_TRUE(tracing::Span::CurrentSpanUnchecked());
295+
EXPECT_EQ(tracing::Span::CurrentSpan().GetTraceId(), parent_trace_id);
296+
EXPECT_FALSE(kInheritedVariable.GetOptional());
297+
EXPECT_FALSE(engine::current_task::impl::IsCritical());
298+
EXPECT_FALSE(engine::current_task::IsCancelRequested());
299+
EXPECT_EQ(&engine::current_task::GetTaskProcessor(), &tp.GetSecondary());
300+
return true;
301+
});
302+
static_assert(std::same_as<decltype(task), engine::TaskWithResult<bool>>);
303+
304+
EXPECT_TRUE(task.Get());
305+
});
306+
}
307+
308+
TEST(UtilsAsync, CriticalAsyncBackgroundCapturesExpectedContext) {
309+
engine::tests::TwoStandaloneTaskProcessors tp;
310+
tp.RunBlocking([&] {
311+
kInheritedVariable.Set(42);
312+
const auto parent_trace_id = tracing::Span::CurrentSpan().GetTraceId();
313+
314+
auto task = utils::CriticalAsyncBackground("async", tp.GetSecondary(), [&, parent_trace_id] {
315+
EXPECT_TRUE(tracing::Span::CurrentSpanUnchecked());
316+
EXPECT_EQ(tracing::Span::CurrentSpan().GetTraceId(), parent_trace_id);
317+
EXPECT_FALSE(kInheritedVariable.GetOptional());
318+
EXPECT_TRUE(engine::current_task::impl::IsCritical());
319+
EXPECT_FALSE(engine::current_task::IsCancelRequested());
320+
EXPECT_EQ(&engine::current_task::GetTaskProcessor(), &tp.GetSecondary());
321+
return true;
322+
});
323+
static_assert(std::same_as<decltype(task), engine::TaskWithResult<bool>>);
324+
325+
EXPECT_TRUE(task.Get());
326+
});
327+
}
328+
125329
USERVER_NAMESPACE_END

0 commit comments

Comments
 (0)