aboutsummaryrefslogtreecommitdiffstats
path: root/vespalib/src/tests/coro/waiting_for/waiting_for_test.cpp
blob: a30b0dbc87e99fb1c74ac3d39a35dae498079a34 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/vespalib/coro/lazy.h>
#include <vespa/vespalib/coro/completion.h>
#include <vespa/vespalib/coro/waiting_for.h>
#include <vespa/vespalib/util/time.h>
#include <vespa/vespalib/gtest/gtest.h>

using namespace vespalib::coro;

struct AsyncService {
    std::vector<WaitingFor<int>> pending;
    auto get_value() {
        return wait_for<int>([&](WaitingFor<int> handle)
                             {
                                 pending.push_back(std::move(handle));
                             });
    }
};

struct AsyncVoidService {
    std::vector<void*> pending;
    auto get_value() {
        return wait_for<int>([&](WaitingFor<int> handle)
                             {
                                 pending.push_back(handle.release());
                             });
    }
};

struct SyncService {
    auto get_value() {
        return wait_for<int>([](WaitingFor<int> handle)
                                {
                                    handle.set_value(42);
                                    return handle.mu(); // symmetric transfer
                                });
    }
};

template<typename Service>
Lazy<int> wait_for_value(Service &service) {
    int value = co_await service.get_value();
    co_return value;
}

template <typename T>
Lazy<T> wait_for_fun(auto &&fun) {
    T result = co_await wait_for<T>(fun);
    co_return result;
}

TEST(WaitingForTest, wait_for_external_async_int) {
    AsyncService service;
    auto res = make_future(wait_for_value(service));
    EXPECT_TRUE(res.wait_for(0ms) == std::future_status::timeout);
    ASSERT_EQ(service.pending.size(), 1);
    service.pending[0].set_value(42);
    EXPECT_TRUE(res.wait_for(0ms) == std::future_status::timeout);
    service.pending.clear();
    EXPECT_TRUE(res.wait_for(0ms) == std::future_status::ready);
    EXPECT_EQ(res.get(), 42);
}

TEST(WaitingForTest, wait_for_external_async_int_calculated_by_coroutine) {
    AsyncService service1;
    AsyncService service2;
    auto res = make_future(wait_for_value(service1));
    ASSERT_EQ(service1.pending.size(), 1);
    {
        async_wait(wait_for_value(service2), std::move(service1.pending[0]));
        service1.pending.clear();
    }
    EXPECT_TRUE(res.wait_for(0ms) == std::future_status::timeout);
    ASSERT_EQ(service2.pending.size(), 1);
    service2.pending[0].set_value(42);
    service2.pending.clear();
    EXPECT_TRUE(res.wait_for(0ms) == std::future_status::ready);
    EXPECT_EQ(res.get(), 42);
}

TEST(WaitingForTest, wait_for_external_async_int_via_void_ptr) {
    AsyncVoidService service;
    auto res = make_future(wait_for_value(service));
    EXPECT_TRUE(res.wait_for(0ms) == std::future_status::timeout);
    ASSERT_EQ(service.pending.size(), 1);
    {
        auto handle = WaitingFor<int>::from_pointer(service.pending[0]);
        handle.set_value(42);
        EXPECT_TRUE(res.wait_for(0ms) == std::future_status::timeout);
    }
    EXPECT_TRUE(res.wait_for(0ms) == std::future_status::ready);
    EXPECT_EQ(res.get(), 42);
}

TEST(WaitingForTest, wait_for_external_sync_int) {
    SyncService service;
    auto res = make_future(wait_for_value(service));
    EXPECT_TRUE(res.wait_for(0ms) == std::future_status::ready);
    EXPECT_EQ(res.get(), 42);
}

TEST(WaitingForTest, wait_for_move_only_value) {
    auto val = std::make_unique<int>(42);
    auto fun = [&val](auto handle){ handle.set_value(std::move(val)); }; // asymmetric transfer
    auto res = make_future(wait_for_fun<decltype(val)>(fun));
    EXPECT_TRUE(res.wait_for(0ms) == std::future_status::ready);
    EXPECT_EQ(*res.get(), 42);
}

TEST(WaitingForTest, set_error) {
    PromiseState<int> state;
    WaitingFor<int> pending = WaitingFor<int>::from_state(state);
    pending.set_error(std::make_exception_ptr(13));
    EXPECT_TRUE(state.result.has_error());
}

TEST(WaitingForTest, set_done) {
    PromiseState<int> state;
    WaitingFor<int> pending = WaitingFor<int>::from_state(state);
    pending.set_value(5);
    EXPECT_TRUE(state.result.has_value());
    pending.set_done();
    EXPECT_TRUE(state.result.was_canceled());
}

GTEST_MAIN_RUN_ALL_TESTS()