1 /*
2 Copyright (c) DataStax, Inc.
3
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
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
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.
15 */
16
17 #include <gtest/gtest.h>
18
19 #include "atomic.hpp"
20 #include "event_loop.hpp"
21 #include "test_utils.hpp"
22
23 using namespace datastax::internal;
24 using namespace datastax::internal::core;
25
26 class EventLoopUnitTest : public testing::Test {
27 public:
28 class MarkTaskCompleted : public Task {
29 public:
MarkTaskCompleted(EventLoopUnitTest * event_loop_unit_test)30 MarkTaskCompleted(EventLoopUnitTest* event_loop_unit_test)
31 : event_loop_unit_test_(event_loop_unit_test) {}
run(EventLoop * event_loop)32 virtual void run(EventLoop* event_loop) { event_loop_unit_test_->mark_task_completed(); }
33
34 private:
35 EventLoopUnitTest* event_loop_unit_test_;
36 };
37
38 class MarkIsRunningOn : public Task {
39 public:
MarkIsRunningOn(EventLoopUnitTest * event_loop_unit_test,EventLoop * event_loop)40 MarkIsRunningOn(EventLoopUnitTest* event_loop_unit_test, EventLoop* event_loop)
41 : event_loop_unit_test_(event_loop_unit_test)
42 , event_loop_(event_loop) {}
run(EventLoop * event_loop)43 virtual void run(EventLoop* event_loop) {
44 event_loop_unit_test_->set_is_running_on(event_loop_->is_running_on());
45 }
46
47 private:
48 EventLoopUnitTest* event_loop_unit_test_;
49 EventLoop* event_loop_;
50 };
51
52 class StartIoTime : public Task {
53 public:
run(EventLoop * event_loop)54 virtual void run(EventLoop* event_loop) { event_loop->maybe_start_io_time(); }
55 };
56
57 class SetIoTimeElapsed : public Task {
58 public:
SetIoTimeElapsed(EventLoopUnitTest * event_loop_unit_test)59 SetIoTimeElapsed(EventLoopUnitTest* event_loop_unit_test)
60 : event_loop_unit_test_(event_loop_unit_test) {}
run(EventLoop * event_loop)61 virtual void run(EventLoop* event_loop) {
62 event_loop_unit_test_->set_io_time_elapsed(event_loop->io_time_elapsed());
63 }
64
65 private:
66 EventLoopUnitTest* event_loop_unit_test_;
67 };
68
69 public:
EventLoopUnitTest()70 EventLoopUnitTest()
71 : is_task_completed_(false)
72 , is_running_on_(false)
73 , io_time_elapsed_(0) {}
74
is_task_completed()75 bool is_task_completed() { return is_task_completed_; }
is_running_on()76 bool is_running_on() { return is_running_on_; }
io_time_elapsed()77 uint64_t io_time_elapsed() { return io_time_elapsed_; }
78
79 protected:
mark_task_completed()80 void mark_task_completed() { is_task_completed_ = true; }
set_is_running_on(bool is_running_on)81 void set_is_running_on(bool is_running_on) { is_running_on_ = is_running_on; }
set_io_time_elapsed(uint64_t io_time_elapsed)82 void set_io_time_elapsed(uint64_t io_time_elapsed) { io_time_elapsed_ = io_time_elapsed; }
83
84 private:
85 bool is_task_completed_;
86 bool is_running_on_;
87 uint64_t io_time_elapsed_;
88 };
89
90 class TestEventLoop : public EventLoop {
91 public:
TestEventLoop()92 TestEventLoop()
93 : is_on_run_completed_(false)
94 , is_after_run_completed_(false) {}
95
is_on_run_completed()96 bool is_on_run_completed() { return is_on_run_completed_.load(); }
is_after_run_completed()97 bool is_after_run_completed() { return is_after_run_completed_; }
98
99 protected:
on_run()100 void on_run() { is_on_run_completed_.store(true); }
on_after_run()101 void on_after_run() { is_after_run_completed_ = true; }
102
103 private:
104 Atomic<bool> is_on_run_completed_;
105 bool is_after_run_completed_;
106 };
107
TEST_F(EventLoopUnitTest,ExecuteTask)108 TEST_F(EventLoopUnitTest, ExecuteTask) {
109 EventLoop event_loop;
110 ASSERT_EQ(0, event_loop.init("EventLoopUnitTest::ExecuteTask"));
111 ASSERT_STREQ("EventLoopUnitTest::ExecuteTask", event_loop.name().c_str());
112 ASSERT_EQ(0, event_loop.run());
113
114 ASSERT_FALSE(is_task_completed());
115 event_loop.add(new MarkTaskCompleted(this));
116
117 event_loop.close_handles();
118 event_loop.join();
119 ASSERT_TRUE(is_task_completed());
120 }
121
TEST_F(EventLoopUnitTest,ThreadRunningOn)122 TEST_F(EventLoopUnitTest, ThreadRunningOn) {
123 EventLoop event_loop;
124 ASSERT_EQ(0, event_loop.init("EventLoopUnitTest::ThreadRunningOn"));
125 ASSERT_STREQ("EventLoopUnitTest::ThreadRunningOn", event_loop.name().c_str());
126 ASSERT_EQ(0, event_loop.run());
127
128 ASSERT_FALSE(is_running_on());
129 event_loop.add(new MarkIsRunningOn(this, &event_loop));
130
131 event_loop.close_handles();
132 event_loop.join();
133 ASSERT_TRUE(is_running_on());
134 }
135
TEST_F(EventLoopUnitTest,ThreadNotRunningOn)136 TEST_F(EventLoopUnitTest, ThreadNotRunningOn) {
137 EventLoop event_loop;
138 ASSERT_EQ(0, event_loop.init("EventLoopUnitTest::ThreadNotRunningOn (EventLoop 1)"));
139 ASSERT_STREQ("EventLoopUnitTest::ThreadNotRunningOn (EventLoop 1)", event_loop.name().c_str());
140 ASSERT_EQ(0, event_loop.run());
141
142 ASSERT_FALSE(is_running_on());
143
144 EventLoop event_loop_2;
145 ASSERT_EQ(0, event_loop_2.init("EventLoopUnitTest::ThreadNotRunningOn (EventLoop 2)"));
146 ASSERT_STREQ("EventLoopUnitTest::ThreadNotRunningOn (EventLoop 2)", event_loop_2.name().c_str());
147 ASSERT_EQ(0, event_loop_2.run());
148 event_loop_2.add(new MarkIsRunningOn(this, &event_loop));
149 event_loop_2.close_handles();
150 event_loop_2.join();
151
152 event_loop.close_handles();
153 event_loop.join();
154 ASSERT_FALSE(is_running_on());
155 }
156
TEST_F(EventLoopUnitTest,BeforeAndAfterRun)157 TEST_F(EventLoopUnitTest, BeforeAndAfterRun) {
158 TestEventLoop event_loop;
159
160 ASSERT_FALSE(event_loop.is_on_run_completed());
161 ASSERT_FALSE(event_loop.is_after_run_completed());
162 ASSERT_EQ(0, event_loop.init("EventLoopUnitTest::BeforeAndAfterRun"));
163 ASSERT_STREQ("EventLoopUnitTest::BeforeAndAfterRun", event_loop.name().c_str());
164 ASSERT_EQ(0, event_loop.run());
165 while (!event_loop.is_on_run_completed())
166 test::Utils::msleep(1); // Poll to wait for thread to be started
167 ASSERT_TRUE(event_loop.is_on_run_completed());
168 ASSERT_FALSE(event_loop.is_after_run_completed());
169
170 event_loop.close_handles();
171 event_loop.join();
172 ASSERT_TRUE(event_loop.is_on_run_completed());
173 ASSERT_TRUE(event_loop.is_after_run_completed());
174 }
175
TEST_F(EventLoopUnitTest,IoTimeElapsed)176 TEST_F(EventLoopUnitTest, IoTimeElapsed) {
177 // TODO:
178
179 /*
180 * io_time_elapsed() measures the time between the start of I/O processing
181 * (which is started via maybe_start_io_time()) and the end of I/O
182 * processing which is handled by a uv_check_t. A potential way to verify it
183 * would involve putting sleep inside of an I/O callback (or another
184 * uv_check_t as long as the call ordering is correct) then checking
185 * io_time_elapsed() using a uv_prepare_t on the same uv_run() iteration.
186 */
187 }
188