blob: b725747ff47e6f7707a5e53fe0cf5691080ad072 [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;
Austin Schuh60e77942022-05-16 17:48:24 -0700132 epoll_.OnError(pipe.write_fd(), [&]() { ++number_errors; });
James Kuszmaul4eb27f02021-04-25 14:08:10 -0700133
134 // Sanity check that we *don't* get any errors before anything interesting has
135 // happened.
136 RunFor(tick_duration());
137 EXPECT_EQ(number_errors, 0);
138
139 pipe.close_read_fd();
140
141 // For some reason, OnError doesn't seem to play nice with the timer setup we
142 // have in this test, so just poll for a single event.
143 epoll_.Poll(false);
144
145 EXPECT_EQ(number_errors, 1);
146
147 epoll_.DeleteFd(pipe.write_fd());
148}
149
Brian Silverman441591b2020-01-31 17:44:32 -0800150TEST(EPollDeathTest, InvalidFd) {
151 EPoll epoll;
152 Pipe pipe;
153 epoll.OnReadable(pipe.read_fd(), []() {});
154 EXPECT_DEATH(epoll.OnReadable(pipe.read_fd(), []() {}),
155 "Duplicate in functions");
156 epoll.OnWriteable(pipe.read_fd(), []() {});
157 EXPECT_DEATH(epoll.OnWriteable(pipe.read_fd(), []() {}),
158 "Duplicate out functions");
159
160 epoll.DeleteFd(pipe.read_fd());
161 EXPECT_DEATH(epoll.DeleteFd(pipe.read_fd()), "fd [0-9]+ not found");
162 EXPECT_DEATH(epoll.DeleteFd(pipe.write_fd()), "fd [0-9]+ not found");
163}
164
165// Tests that enabling/disabling a writeable FD works.
166TEST_F(EPollTest, WriteableEnableDisable) {
167 Pipe pipe;
168 int number_writes = 0;
169 epoll_.OnWriteable(pipe.write_fd(), [&]() {
170 pipe.Write(" ");
171 ++number_writes;
172 });
173
174 // First, fill up the pipe's write buffer.
175 RunFor(tick_duration());
176 EXPECT_GT(number_writes, 0);
177
178 // Empty the pipe.
179 const int bytes_in_pipe = number_writes;
180 for (int i = 0; i < bytes_in_pipe; ++i) {
181 ASSERT_EQ(" ", pipe.Read(1));
182 }
183
184 // If we disable writeable checking, then nothing should happen.
185 epoll_.DisableWriteable(pipe.write_fd());
186 number_writes = 0;
187 RunFor(tick_duration());
188 EXPECT_EQ(number_writes, 0);
189
190 // Disabling it again should be a NOP.
191 epoll_.DisableWriteable(pipe.write_fd());
192
193 // And then when we re-enable, it should fill the pipe up again.
194 epoll_.EnableWriteable(pipe.write_fd());
195 number_writes = 0;
196 RunFor(tick_duration());
197 EXPECT_EQ(number_writes, bytes_in_pipe);
198
199 epoll_.DeleteFd(pipe.write_fd());
200}
201
Austin Schuhf74daa62021-07-21 15:29:17 -0700202TEST_F(EPollTest, QuitInBeforeWait) {
203 epoll_.BeforeWait([this]() { epoll_.Quit(); });
204 epoll_.Run();
205}
206
Brian Silverman441591b2020-01-31 17:44:32 -0800207} // namespace testing
208} // namespace internal
209} // namespace aos