xref: /openbmc/sdbusplus/test/async/fdio_timed.cpp (revision 5b5432510a197a468dead611f4d76dd58201d44a)
1 #include <sdbusplus/async.hpp>
2 
3 #include <filesystem>
4 #include <fstream>
5 
6 #include <gtest/gtest.h>
7 
8 using namespace std::literals;
9 
10 namespace fs = std::filesystem;
11 
12 class FdioTimedTest : public ::testing::Test
13 {
14   protected:
15     enum class testWriteOperation
16     {
17         writeSync,
18         writeAsync,
19         writeSkip
20     };
21 
22     const fs::path path = "/tmp/test_fdio_timed";
23 
FdioTimedTest()24     FdioTimedTest()
25     {
26         if (!fs::exists(path))
27         {
28             fs::create_directory(path);
29         }
30 
31         fd = inotify_init1(IN_NONBLOCK);
32         EXPECT_NE(fd, -1) << "Error occurred during the inotify_init1, error: "
33                           << errno;
34 
35         wd = inotify_add_watch(fd, path.c_str(), IN_CLOSE_WRITE);
36         EXPECT_NE(wd, -1)
37             << "Error occurred during the inotify_add_watch, error: " << errno;
38         fdioInstance = std::make_unique<sdbusplus::async::fdio>(
39             *ctx, fd, std::chrono::microseconds(1000));
40     }
41 
~FdioTimedTest()42     ~FdioTimedTest() noexcept override
43     {
44         if (fd != -1)
45         {
46             if (wd != -1)
47             {
48                 inotify_rm_watch(fd, wd);
49             }
50             close(fd);
51         }
52         ctx.reset();
53 
54         if (fs::exists(path))
55         {
56             fs::remove_all(path);
57         }
58     }
59 
writeToFile()60     auto writeToFile() -> sdbusplus::async::task<>
61     {
62         std::ofstream outfile((path / "test_fdio.txt").native());
63         EXPECT_TRUE(outfile.is_open())
64             << "Error occurred during file open, error: " << errno;
65         outfile << "Test fdio!" << std::endl;
66         outfile.close();
67         co_return;
68     }
69 
testFdTimedEvents(bool & ran,testWriteOperation writeOperation,int testIterations)70     auto testFdTimedEvents(bool& ran, testWriteOperation writeOperation,
71                            int testIterations) -> sdbusplus::async::task<>
72     {
73         for (int i = 0; i < testIterations; i++)
74         {
75             switch (writeOperation)
76             {
77                 case testWriteOperation::writeSync:
78                     co_await writeToFile();
79                     break;
80                 case testWriteOperation::writeAsync:
81                     ctx->spawn(
82                         sdbusplus::async::sleep_for(*ctx, 1s) |
83                         stdexec::then([&]() { ctx->spawn(writeToFile()); }));
84                     break;
85                 case testWriteOperation::writeSkip:
86                 default:
87                     break;
88             }
89 
90             bool receivedTimeout = false;
91 
92             try
93             {
94                 co_await fdioInstance->next();
95             }
96             catch (const sdbusplus::async::fdio_timeout_exception& e)
97             {
98                 receivedTimeout = true;
99             }
100 
101             switch (writeOperation)
102             {
103                 case testWriteOperation::writeSync:
104                     EXPECT_FALSE(receivedTimeout) << "Expected event";
105                     break;
106                 case testWriteOperation::writeAsync:
107                 case testWriteOperation::writeSkip:
108                 default:
109                     EXPECT_TRUE(receivedTimeout) << "Expected timeout";
110                     break;
111             }
112         }
113         ran = true;
114 
115         co_return;
116     }
117 
118     std::unique_ptr<sdbusplus::async::fdio> fdioInstance;
119     std::optional<sdbusplus::async::context> ctx{std::in_place};
120 
121   private:
122     int fd = -1;
123     int wd = -1;
124 };
125 
TEST_F(FdioTimedTest,TestWriteSkipWithTimeout)126 TEST_F(FdioTimedTest, TestWriteSkipWithTimeout)
127 {
128     bool ran = false;
129     ctx->spawn(testFdTimedEvents(ran, testWriteOperation::writeSkip, 1));
130     ctx->spawn(
131         sdbusplus::async::sleep_for(*ctx, 2s) |
132         sdbusplus::async::execution::then([&]() { ctx->request_stop(); }));
133     ctx->run();
134     EXPECT_TRUE(ran);
135 }
136 
TEST_F(FdioTimedTest,TestWriteAsyncWithTimeout)137 TEST_F(FdioTimedTest, TestWriteAsyncWithTimeout)
138 {
139     bool ran = false;
140     ctx->spawn(testFdTimedEvents(ran, testWriteOperation::writeAsync, 1));
141     ctx->spawn(
142         sdbusplus::async::sleep_for(*ctx, 2s) |
143         sdbusplus::async::execution::then([&]() { ctx->request_stop(); }));
144     ctx->run();
145     EXPECT_TRUE(ran);
146 }
147 
TEST_F(FdioTimedTest,TestWriteAsyncWithTimeoutIterative)148 TEST_F(FdioTimedTest, TestWriteAsyncWithTimeoutIterative)
149 {
150     bool ran = false;
151     ctx->spawn(testFdTimedEvents(ran, testWriteOperation::writeAsync, 100));
152     ctx->spawn(
153         sdbusplus::async::sleep_for(*ctx, 2s) |
154         sdbusplus::async::execution::then([&]() { ctx->request_stop(); }));
155     ctx->run();
156     EXPECT_TRUE(ran);
157 }
158 
TEST_F(FdioTimedTest,TestWriteSync)159 TEST_F(FdioTimedTest, TestWriteSync)
160 {
161     bool ran = false;
162     ctx->spawn(testFdTimedEvents(ran, testWriteOperation::writeSync, 1));
163     ctx->spawn(
164         sdbusplus::async::sleep_for(*ctx, 2s) |
165         sdbusplus::async::execution::then([&]() { ctx->request_stop(); }));
166     ctx->run();
167     EXPECT_TRUE(ran);
168 }
169 
TEST_F(FdioTimedTest,TestWriteSyncIterative)170 TEST_F(FdioTimedTest, TestWriteSyncIterative)
171 {
172     bool ran = false;
173     ctx->spawn(testFdTimedEvents(ran, testWriteOperation::writeSync, 100));
174     ctx->spawn(
175         sdbusplus::async::sleep_for(*ctx, 2s) |
176         sdbusplus::async::execution::then([&]() { ctx->request_stop(); }));
177     ctx->run();
178     EXPECT_TRUE(ran);
179 }
180