blob: 053a09b7bedb4db8bdeaff39725bac15ad166a5b [file] [log] [blame]
Brian Silverman441591b2020-01-31 17:44:32 -08001#include "aos/events/epoll.h"
2
3#include <fcntl.h>
4#include <unistd.h>
5
Brian Silverman441591b2020-01-31 17:44:32 -08006#include "glog/logging.h"
Austin Schuhf74daa62021-07-21 15:29:17 -07007#include "gtest/gtest.h"
Brian Silverman441591b2020-01-31 17:44:32 -08008
9namespace aos {
10namespace internal {
11namespace testing {
12
13// A simple wrapper around both ends of a pipe along with some helpers to easily
14// read/write data through it.
15class Pipe {
16 public:
17 Pipe() { PCHECK(pipe2(fds_, O_NONBLOCK) == 0); }
18 ~Pipe() {
James Kuszmaul4eb27f02021-04-25 14:08:10 -070019 if (fds_[0] >= 0) {
20 PCHECK(close(fds_[0]) == 0);
21 }
22 if (fds_[1] >= 0) {
23 PCHECK(close(fds_[1]) == 0);
24 }
Brian Silverman441591b2020-01-31 17:44:32 -080025 }
26
27 int read_fd() { return fds_[0]; }
28 int write_fd() { return fds_[1]; }
James Kuszmaul4eb27f02021-04-25 14:08:10 -070029 void close_read_fd() {
30 PCHECK(close(fds_[0]) == 0);
31 fds_[0] = -1;
32 }
Brian Silverman441591b2020-01-31 17:44:32 -080033
34 void Write(const std::string &data) {
35 CHECK_EQ(write(write_fd(), data.data(), data.size()),
36 static_cast<ssize_t>(data.size()));
37 }
38
39 std::string Read(size_t size) {
40 std::string result;
41 result.resize(size);
42 CHECK_EQ(read(read_fd(), result.data(), size), static_cast<ssize_t>(size));
43 return result;
44 }
45
46 private:
47 int fds_[2];
48};
49
50class EPollTest : public ::testing::Test {
Austin Schuhf74daa62021-07-21 15:29:17 -070051 public:
52 void RunFor(std::chrono::nanoseconds duration) {
53 TimerFd timerfd;
54 bool did_quit = false;
55 epoll_.OnReadable(timerfd.fd(), [this, &timerfd, &did_quit]() {
56 CHECK(!did_quit);
57 epoll_.Quit();
58 did_quit = true;
59 timerfd.Read();
60 });
61 timerfd.SetTime(monotonic_clock::now() + duration,
62 monotonic_clock::duration::zero());
63 epoll_.Run();
64 CHECK(did_quit);
65 epoll_.DeleteFd(timerfd.fd());
66 }
Brian Silverman441591b2020-01-31 17:44:32 -080067
68 // Tests should avoid relying on ordering for events closer in time than this,
69 // or waiting for longer than this to ensure events happen in order.
70 static constexpr std::chrono::nanoseconds tick_duration() {
71 return std::chrono::milliseconds(50);
72 }
73
Austin Schuhf74daa62021-07-21 15:29:17 -070074 EPoll epoll_;
Brian Silverman441591b2020-01-31 17:44:32 -080075};
76
77// Test that the basics of OnReadable work.
78TEST_F(EPollTest, BasicReadable) {
79 Pipe pipe;
80 bool got_data = false;
81 epoll_.OnReadable(pipe.read_fd(), [&]() {
82 ASSERT_FALSE(got_data);
83 ASSERT_EQ("some", pipe.Read(4));
84 got_data = true;
85 });
86 RunFor(tick_duration());
87 EXPECT_FALSE(got_data);
88
89 pipe.Write("some");
90 RunFor(tick_duration());
91 EXPECT_TRUE(got_data);
92
93 epoll_.DeleteFd(pipe.read_fd());
94}
95
96// Test that the basics of OnWriteable work.
97TEST_F(EPollTest, BasicWriteable) {
98 Pipe pipe;
99 int number_writes = 0;
100 epoll_.OnWriteable(pipe.write_fd(), [&]() {
101 pipe.Write(" ");
102 ++number_writes;
103 });
104
105 // First, fill up the pipe's write buffer.
106 RunFor(tick_duration());
107 EXPECT_GT(number_writes, 0);
108
109 // Now, if we try again, we shouldn't do anything.
110 const int bytes_in_pipe = number_writes;
111 number_writes = 0;
112 RunFor(tick_duration());
113 EXPECT_EQ(number_writes, 0);
114
115 // Empty the pipe, then fill it up again.
116 for (int i = 0; i < bytes_in_pipe; ++i) {
117 ASSERT_EQ(" ", pipe.Read(1));
118 }
119 number_writes = 0;
120 RunFor(tick_duration());
121 EXPECT_EQ(number_writes, bytes_in_pipe);
122
123 epoll_.DeleteFd(pipe.write_fd());
124}
125
James Kuszmaul4eb27f02021-04-25 14:08:10 -0700126// Test that the basics of OnError work.
127TEST_F(EPollTest, BasicError) {
128 // In order to trigger an error, close the read file descriptor (per the
129 // epoll_ctl manpage, this should trigger an error).
130 Pipe pipe;
131 int number_errors = 0;
132 epoll_.OnError(pipe.write_fd(), [&]() {
133 ++number_errors;
134 });
135
136 // Sanity check that we *don't* get any errors before anything interesting has
137 // happened.
138 RunFor(tick_duration());
139 EXPECT_EQ(number_errors, 0);
140
141 pipe.close_read_fd();
142
143 // For some reason, OnError doesn't seem to play nice with the timer setup we
144 // have in this test, so just poll for a single event.
145 epoll_.Poll(false);
146
147 EXPECT_EQ(number_errors, 1);
148
149 epoll_.DeleteFd(pipe.write_fd());
150}
151
Brian Silverman441591b2020-01-31 17:44:32 -0800152TEST(EPollDeathTest, InvalidFd) {
153 EPoll epoll;
154 Pipe pipe;
155 epoll.OnReadable(pipe.read_fd(), []() {});
156 EXPECT_DEATH(epoll.OnReadable(pipe.read_fd(), []() {}),
157 "Duplicate in functions");
158 epoll.OnWriteable(pipe.read_fd(), []() {});
159 EXPECT_DEATH(epoll.OnWriteable(pipe.read_fd(), []() {}),
160 "Duplicate out functions");
161
162 epoll.DeleteFd(pipe.read_fd());
163 EXPECT_DEATH(epoll.DeleteFd(pipe.read_fd()), "fd [0-9]+ not found");
164 EXPECT_DEATH(epoll.DeleteFd(pipe.write_fd()), "fd [0-9]+ not found");
165}
166
167// Tests that enabling/disabling a writeable FD works.
168TEST_F(EPollTest, WriteableEnableDisable) {
169 Pipe pipe;
170 int number_writes = 0;
171 epoll_.OnWriteable(pipe.write_fd(), [&]() {
172 pipe.Write(" ");
173 ++number_writes;
174 });
175
176 // First, fill up the pipe's write buffer.
177 RunFor(tick_duration());
178 EXPECT_GT(number_writes, 0);
179
180 // Empty the pipe.
181 const int bytes_in_pipe = number_writes;
182 for (int i = 0; i < bytes_in_pipe; ++i) {
183 ASSERT_EQ(" ", pipe.Read(1));
184 }
185
186 // If we disable writeable checking, then nothing should happen.
187 epoll_.DisableWriteable(pipe.write_fd());
188 number_writes = 0;
189 RunFor(tick_duration());
190 EXPECT_EQ(number_writes, 0);
191
192 // Disabling it again should be a NOP.
193 epoll_.DisableWriteable(pipe.write_fd());
194
195 // And then when we re-enable, it should fill the pipe up again.
196 epoll_.EnableWriteable(pipe.write_fd());
197 number_writes = 0;
198 RunFor(tick_duration());
199 EXPECT_EQ(number_writes, bytes_in_pipe);
200
201 epoll_.DeleteFd(pipe.write_fd());
202}
203
Austin Schuhf74daa62021-07-21 15:29:17 -0700204TEST_F(EPollTest, QuitInBeforeWait) {
205 epoll_.BeforeWait([this]() { epoll_.Quit(); });
206 epoll_.Run();
207}
208
Brian Silverman441591b2020-01-31 17:44:32 -0800209} // namespace testing
210} // namespace internal
211} // namespace aos