2 * Copyright 2014 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <gtest/gtest.h>
21 #include "folly/wangle/Executor.h"
22 #include "folly/wangle/ManualExecutor.h"
23 #include "folly/wangle/ThreadGate.h"
24 #include "folly/wangle/GenericThreadGate.h"
26 using namespace folly::wangle;
27 using std::make_shared;
28 using std::shared_ptr;
33 explicit ManualWaiter(shared_ptr<ManualExecutor> ex) : ex(ex) {}
40 shared_ptr<ManualExecutor> ex;
43 struct GenericThreadGateFixture : public testing::Test {
44 GenericThreadGateFixture() :
45 westExecutor(new ManualExecutor),
46 eastExecutor(new ManualExecutor),
47 waiter(new ManualWaiter(westExecutor)),
48 tg(westExecutor, eastExecutor, waiter),
52 ManualWaiter eastWaiter(eastExecutor);
54 eastWaiter.makeProgress();
58 ~GenericThreadGateFixture() {
60 tg.gate<void>([] { return makeFuture(); });
64 shared_ptr<ManualExecutor> westExecutor;
65 shared_ptr<ManualExecutor> eastExecutor;
66 shared_ptr<ManualWaiter> waiter;
68 shared_ptr<ManualExecutor>,
69 shared_ptr<ManualExecutor>,
70 shared_ptr<ManualWaiter>> tg;
75 TEST_F(GenericThreadGateFixture, gate_and_wait) {
76 auto f = tg.gate<void>([] { return makeFuture(); });
77 EXPECT_FALSE(f.isReady());
80 EXPECT_TRUE(f.isReady());
83 TEST_F(GenericThreadGateFixture, gate_many) {
84 vector<Future<void>> fs;
87 for (int i = 0; i < n; i++)
88 fs.push_back(tg.gate<void>([&] { return makeFuture(); }));
91 EXPECT_FALSE(f.isReady());
93 auto all = whenAll(fs.begin(), fs.end());
97 TEST_F(GenericThreadGateFixture, gate_alternating) {
98 vector<Promise<void>> ps(10);
99 vector<Future<void>> fs;
104 auto f = tg.gate<void>([=] { return pp->getFuture(); });
106 // abuse the thread gate to do our dirty work in the other thread
107 tg.gate<void>([=] { pp->setValue(); return makeFuture(); });
109 fs.push_back(f.then([&](Try<void>&&) { count++; }));
113 EXPECT_FALSE(f.isReady());
116 auto all = whenAll(fs.begin(), fs.end());
119 EXPECT_EQ(ps.size(), count);
122 TEST(GenericThreadGate, noWaiter) {
123 auto west = make_shared<ManualExecutor>();
124 auto east = make_shared<ManualExecutor>();
126 auto dummyFuture = p.getFuture();
128 GenericThreadGate<ManualExecutor*, ManualExecutor*>
129 tg(west.get(), east.get());
131 EXPECT_THROW(tg.waitFor(dummyFuture), std::logic_error);
134 TEST_F(GenericThreadGateFixture, gate_with_promise) {
137 auto westId = std::this_thread::get_id();
138 bool westThenCalled = false;
139 auto f = p.getFuture().then(
140 [westId, &westThenCalled](Try<int>&& t) {
141 EXPECT_EQ(t.value(), 1);
142 EXPECT_EQ(std::this_thread::get_id(), westId);
143 westThenCalled = true;
147 bool eastPromiseMade = false;
148 auto thread = std::thread([&p, &eastPromiseMade, this]() {
149 EXPECT_NE(t.get_id(), std::this_thread::get_id());
150 // South thread != west thread. p gets set in west thread.
151 tg.gate<int>([&p, &eastPromiseMade, this] {
152 EXPECT_EQ(t.get_id(), std::this_thread::get_id());
153 Promise<int> eastPromise;
154 auto eastFuture = eastPromise.getFuture();
155 eastPromise.setValue(1);
156 eastPromiseMade = true;
163 EXPECT_TRUE(westThenCalled);
164 EXPECT_TRUE(eastPromiseMade);
165 EXPECT_EQ(f.value(), 1);