Skip to content
This repository was archived by the owner on Apr 3, 2025. It is now read-only.

Commit ec6dc3d

Browse files
author
Luc Sinet
committed
develop #comment Unit tests for scheduling periodic tasks.
- Use one future in the test fixtures to synchronize the managers/schedulers.
1 parent c7f1257 commit ec6dc3d

3 files changed

Lines changed: 77 additions & 30 deletions

File tree

test/ManagerTest.hh

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,17 @@ class ManagerTest : public Test {
2626
};
2727

2828
void setup(size_t poolWorkersCount, size_t managerWorkersCount) {
29-
for (size_t i = 0; i < poolWorkersCount; ++i) {
30-
_locks.emplace_back();
31-
}
32-
std::vector<std::shared_future<void>> futures(_locks.size());
33-
34-
for (size_t i = 0; i < _locks.size(); ++i) {
35-
futures[i] = _locks[i].get_future();
29+
if (!_lock.first) {
30+
_lock.first = std::make_unique<std::promise<void>>();
31+
_lock.second = _lock.first->get_future();
3632
}
3733

3834
_threadpool = std::make_shared<Detail::Threadpool>(poolWorkersCount);
3935
_manager = std::make_shared<Manager>(_threadpool, managerWorkersCount);
4036

41-
for (size_t i = 0; i < futures.size(); ++i) {
42-
auto task = [future = std::move(futures[i])] {
43-
EXPECT_EQ(std::future_status::ready, future.wait_for(std::chrono::milliseconds(Async::kTestTimeout)));
37+
for (size_t i = 0; i < managerWorkersCount; ++i) {
38+
auto task = [this] {
39+
EXPECT_EQ(std::future_status::ready, _lock.second.wait_for(std::chrono::milliseconds(Async::kTestTimeout)));
4440
};
4541
_manager->launch(std::move(task));
4642
}
@@ -52,8 +48,8 @@ class ManagerTest : public Test {
5248
}
5349
}
5450
void runTasks() {
55-
for (auto& lock : _locks) {
56-
lock.set_value();
51+
if (_lock.first) {
52+
_lock.first->set_value();
5753
}
5854
for (auto& future : _futures) {
5955
EXPECT_EQ(std::future_status::ready, future.wait_for(std::chrono::milliseconds(Async::kTestTimeout)));
@@ -64,7 +60,7 @@ class ManagerTest : public Test {
6460
protected:
6561
std::shared_ptr<Detail::Threadpool> _threadpool;
6662
std::shared_ptr<Manager> _manager;
67-
std::vector<std::promise<void>> _locks;
63+
std::pair<std::unique_ptr<std::promise<void>>, std::shared_future<void>> _lock;
6864
std::vector<std::shared_future<void>> _futures;
6965
};
7066

test/SchedulerTest.cpp

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,56 @@ TEST_F(SchedulerTest, scheduleNested) {
110110
this->runTasks();
111111
}
112112

113+
TEST_F(SchedulerTest, schedulePeriodic) {
114+
auto threadpool = std::make_shared<Detail::Threadpool>(2);
115+
auto scheduler = std::make_shared<Scheduler>(threadpool, 1);
116+
std::promise<void> p;
117+
auto f = p.get_future();
118+
size_t i = 0;
119+
120+
scheduler->scheduleEvery("0", std::chrono::milliseconds(0), [&i, &p] {
121+
++i;
122+
if (i == 5) {
123+
p.set_value();
124+
}
125+
});
126+
127+
EXPECT_EQ(std::future_status::ready, f.wait_for(std::chrono::milliseconds(Async::kTestTimeout)));
128+
EXPECT_EQ(std::future_status::ready, scheduler->stop().wait_for(std::chrono::milliseconds(Async::kTestTimeout)));
129+
}
130+
131+
TEST_F(SchedulerTest, multiplePeriodicTasksOneWorker) {
132+
_threadpool = std::make_shared<Detail::Threadpool>(2);
133+
auto scheduler = this->setupScheduler(1);
134+
std::promise<void> p;
135+
auto f = p.get_future();
136+
std::string strA = "HloWrd";
137+
std::string strB = "el ol!";
138+
std::string expected = "Hello World!";
139+
std::string final;
140+
size_t i = 0;
141+
142+
scheduler->scheduleEvery("A", std::chrono::milliseconds(0), [&] { //
143+
if (i < strA.size()) {
144+
final.push_back(strA[i]);
145+
}
146+
});
147+
scheduler->scheduleEvery("B", std::chrono::milliseconds(0), [&] { //
148+
if (i < strB.size()) {
149+
final.push_back(strB[i++]);
150+
if (i == strB.size()) {
151+
p.set_value();
152+
}
153+
}
154+
});
155+
// Unblock the scheduler.
156+
this->runTasks();
157+
EXPECT_EQ(std::future_status::ready, f.wait_for(std::chrono::milliseconds(Async::kTestTimeout)));
158+
159+
EXPECT_EQ(expected, final);
160+
EXPECT_EQ(std::future_status::ready, scheduler->stop().wait_for(std::chrono::milliseconds(Async::kTestTimeout)));
161+
}
162+
113163
TEST_F(SchedulerTest, erase) {
114164
size_t n = 0;
115165

@@ -156,7 +206,7 @@ TEST_F(SchedulerTest, scheduleOnStopped) {
156206
auto threadpool = std::make_shared<Detail::Threadpool>(2);
157207
auto scheduler = std::make_shared<Scheduler>(threadpool, 1);
158208

159-
scheduler->stop().get();
209+
EXPECT_EQ(std::future_status::ready, scheduler->stop().wait_for(std::chrono::milliseconds(Async::kTestTimeout)));
160210
auto future = scheduler->scheduleIn("0", std::chrono::milliseconds(0), [] {});
161211

162212
EXPECT_FALSE(scheduler->isScheduled("0"));

test/SchedulerTest.hh

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,24 +27,25 @@ class SchedulerTest : public Test {
2727
};
2828

2929
void setup(size_t poolWorkersCount, size_t schedulerWorkersCount) {
30-
for (size_t i = 0; i < poolWorkersCount; ++i) {
31-
_locks.emplace_back();
32-
}
33-
std::vector<std::shared_future<void>> futures(_locks.size());
30+
_threadpool = std::make_shared<Detail::Threadpool>(poolWorkersCount);
31+
_scheduler = this->setupScheduler(schedulerWorkersCount);
32+
}
3433

35-
for (size_t i = 0; i < _locks.size(); ++i) {
36-
futures[i] = _locks[i].get_future();
34+
std::shared_ptr<Scheduler> setupScheduler(size_t schedulerWorkersCount) {
35+
if (!_lock.first) {
36+
_lock.first = std::make_unique<std::promise<void>>();
37+
_lock.second = _lock.first->get_future();
3738
}
3839

39-
_threadpool = std::make_shared<Detail::Threadpool>(poolWorkersCount);
40-
_scheduler = std::make_shared<Scheduler>(_threadpool, schedulerWorkersCount);
41-
42-
for (size_t i = 0; i < futures.size(); ++i) {
43-
auto task = [future = std::move(futures[i])] {
44-
EXPECT_EQ(std::future_status::ready, future.wait_for(std::chrono::milliseconds(Async::kTestTimeout)));
40+
auto scheduler = std::make_shared<Scheduler>(_threadpool, schedulerWorkersCount);
41+
for (size_t i = 0; i < schedulerWorkersCount; ++i) {
42+
auto task = [this] {
43+
EXPECT_EQ(std::future_status::ready, _lock.second.wait_for(std::chrono::milliseconds(Async::kTestTimeout)));
4544
};
46-
_scheduler->scheduleIn("setup_" + std::to_string(i), -std::chrono::hours(1), std::move(task));
45+
scheduler->scheduleIn("setup_" + std::to_string(i), -std::chrono::hours(1), std::move(task));
4746
}
47+
48+
return scheduler;
4849
}
4950

5051
void addTasks(std::vector<std::pair<std::function<void()>, std::chrono::microseconds>>&& functors) {
@@ -54,8 +55,8 @@ class SchedulerTest : public Test {
5455
}
5556
}
5657
void runTasks() {
57-
for (auto& lock : _locks) {
58-
lock.set_value();
58+
if (_lock.first) {
59+
_lock.first->set_value();
5960
}
6061
for (auto& future : _futures) {
6162
EXPECT_EQ(std::future_status::ready, future.wait_for(std::chrono::milliseconds(Async::kTestTimeout)));
@@ -66,7 +67,7 @@ class SchedulerTest : public Test {
6667
protected:
6768
std::shared_ptr<Detail::Threadpool> _threadpool;
6869
std::shared_ptr<Scheduler> _scheduler;
69-
std::vector<std::promise<void>> _locks;
70+
std::pair<std::unique_ptr<std::promise<void>>, std::shared_future<void>> _lock;
7071
std::vector<std::shared_future<void>> _futures;
7172
};
7273

0 commit comments

Comments
 (0)