blob: 4e6bbbcfeb926371dcd63996e8e03ddeff99c52c [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
6#include "gtest/gtest.h"
7#include "glog/logging.h"
8
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() {
19 PCHECK(close(fds_[0]) == 0);
20 PCHECK(close(fds_[1]) == 0);
21 }
22
23 int read_fd() { return fds_[0]; }
24 int write_fd() { return fds_[1]; }
25
26 void Write(const std::string &data) {
27 CHECK_EQ(write(write_fd(), data.data(), data.size()),
28 static_cast<ssize_t>(data.size()));
29 }
30
31 std::string Read(size_t size) {
32 std::string result;
33 result.resize(size);
34 CHECK_EQ(read(read_fd(), result.data(), size), static_cast<ssize_t>(size));
35 return result;
36 }
37
38 private:
39 int fds_[2];
40};
41
42class EPollTest : public ::testing::Test {
43 public:
44 void RunFor(std::chrono::nanoseconds duration) {
45 TimerFd timerfd;
46 bool did_quit = false;
47 epoll_.OnReadable(timerfd.fd(), [this, &timerfd, &did_quit]() {
48 CHECK(!did_quit);
49 epoll_.Quit();
50 did_quit = true;
51 timerfd.Read();
52 });
53 timerfd.SetTime(monotonic_clock::now() + duration,
54 monotonic_clock::duration::zero());
55 epoll_.Run();
56 CHECK(did_quit);
57 epoll_.DeleteFd(timerfd.fd());
58 }
59
60 // Tests should avoid relying on ordering for events closer in time than this,
61 // or waiting for longer than this to ensure events happen in order.
62 static constexpr std::chrono::nanoseconds tick_duration() {
63 return std::chrono::milliseconds(50);
64 }
65
66 EPoll epoll_;
67};
68
69// Test that the basics of OnReadable work.
70TEST_F(EPollTest, BasicReadable) {
71 Pipe pipe;
72 bool got_data = false;
73 epoll_.OnReadable(pipe.read_fd(), [&]() {
74 ASSERT_FALSE(got_data);
75 ASSERT_EQ("some", pipe.Read(4));
76 got_data = true;
77 });
78 RunFor(tick_duration());
79 EXPECT_FALSE(got_data);
80
81 pipe.Write("some");
82 RunFor(tick_duration());
83 EXPECT_TRUE(got_data);
84
85 epoll_.DeleteFd(pipe.read_fd());
86}
87
88// Test that the basics of OnWriteable work.
89TEST_F(EPollTest, BasicWriteable) {
90 Pipe pipe;
91 int number_writes = 0;
92 epoll_.OnWriteable(pipe.write_fd(), [&]() {
93 pipe.Write(" ");
94 ++number_writes;
95 });
96
97 // First, fill up the pipe's write buffer.
98 RunFor(tick_duration());
99 EXPECT_GT(number_writes, 0);
100
101 // Now, if we try again, we shouldn't do anything.
102 const int bytes_in_pipe = number_writes;
103 number_writes = 0;
104 RunFor(tick_duration());
105 EXPECT_EQ(number_writes, 0);
106
107 // Empty the pipe, then fill it up again.
108 for (int i = 0; i < bytes_in_pipe; ++i) {
109 ASSERT_EQ(" ", pipe.Read(1));
110 }
111 number_writes = 0;
112 RunFor(tick_duration());
113 EXPECT_EQ(number_writes, bytes_in_pipe);
114
115 epoll_.DeleteFd(pipe.write_fd());
116}
117
118TEST(EPollDeathTest, InvalidFd) {
119 EPoll epoll;
120 Pipe pipe;
121 epoll.OnReadable(pipe.read_fd(), []() {});
122 EXPECT_DEATH(epoll.OnReadable(pipe.read_fd(), []() {}),
123 "Duplicate in functions");
124 epoll.OnWriteable(pipe.read_fd(), []() {});
125 EXPECT_DEATH(epoll.OnWriteable(pipe.read_fd(), []() {}),
126 "Duplicate out functions");
127
128 epoll.DeleteFd(pipe.read_fd());
129 EXPECT_DEATH(epoll.DeleteFd(pipe.read_fd()), "fd [0-9]+ not found");
130 EXPECT_DEATH(epoll.DeleteFd(pipe.write_fd()), "fd [0-9]+ not found");
131}
132
133// Tests that enabling/disabling a writeable FD works.
134TEST_F(EPollTest, WriteableEnableDisable) {
135 Pipe pipe;
136 int number_writes = 0;
137 epoll_.OnWriteable(pipe.write_fd(), [&]() {
138 pipe.Write(" ");
139 ++number_writes;
140 });
141
142 // First, fill up the pipe's write buffer.
143 RunFor(tick_duration());
144 EXPECT_GT(number_writes, 0);
145
146 // Empty the pipe.
147 const int bytes_in_pipe = number_writes;
148 for (int i = 0; i < bytes_in_pipe; ++i) {
149 ASSERT_EQ(" ", pipe.Read(1));
150 }
151
152 // If we disable writeable checking, then nothing should happen.
153 epoll_.DisableWriteable(pipe.write_fd());
154 number_writes = 0;
155 RunFor(tick_duration());
156 EXPECT_EQ(number_writes, 0);
157
158 // Disabling it again should be a NOP.
159 epoll_.DisableWriteable(pipe.write_fd());
160
161 // And then when we re-enable, it should fill the pipe up again.
162 epoll_.EnableWriteable(pipe.write_fd());
163 number_writes = 0;
164 RunFor(tick_duration());
165 EXPECT_EQ(number_writes, bytes_in_pipe);
166
167 epoll_.DeleteFd(pipe.write_fd());
168}
169
170} // namespace testing
171} // namespace internal
172} // namespace aos