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 MutexTest : public ::testing::Test 13 { 14 protected: 15 constexpr static std::string testMutex = "TestMutex"; 16 const fs::path path = "/tmp"; 17 18 MutexTest() : mutex(testMutex) 19 { 20 auto fd = inotify_init1(IN_NONBLOCK); 21 EXPECT_NE(fd, -1) << "Error occurred during the inotify_init1, error: " 22 << errno; 23 24 auto wd = inotify_add_watch(fd, path.c_str(), IN_CLOSE_WRITE); 25 EXPECT_NE(wd, -1) 26 << "Error occurred during the inotify_add_watch, error: " << errno; 27 fdioInstance = std::make_unique<sdbusplus::async::fdio>(*ctx, fd); 28 } 29 30 std::optional<sdbusplus::async::context> ctx{std::in_place}; 31 32 auto testAsyncAddition(int val = 1) -> sdbusplus::async::task<> 33 { 34 sdbusplus::async::lock_guard lg{mutex}; 35 co_await lg.lock(); 36 37 sharedVar += val; 38 } 39 40 auto testAsyncSubtraction(int val = 1) -> sdbusplus::async::task<> 41 { 42 sdbusplus::async::lock_guard lg{mutex}; 43 co_await lg.lock(); 44 45 sharedVar -= val; 46 } 47 48 auto writeToFile() -> sdbusplus::async::task<> 49 { 50 std::ofstream outfile((path / testMutex).native()); 51 EXPECT_TRUE(outfile.is_open()) 52 << "Error occurred during file open, error: " << errno; 53 54 outfile << testMutex << std::endl; 55 outfile.close(); 56 57 co_return; 58 } 59 60 auto readFromFile() -> sdbusplus::async::task<> 61 { 62 std::ifstream infile((path / testMutex).native()); 63 EXPECT_TRUE(infile.is_open()) 64 << "Error occurred during file open, error: " << errno; 65 66 std::string line; 67 std::getline(infile, line); 68 EXPECT_EQ(line, testMutex); 69 infile.close(); 70 71 co_return; 72 } 73 74 auto testFdEvents() -> sdbusplus::async::task<> 75 { 76 sdbusplus::async::lock_guard lg{mutex}; 77 co_await lg.lock(); 78 79 ctx->spawn(writeToFile()); 80 co_await fdioInstance->next(); 81 co_await readFromFile(); 82 ran++; 83 84 co_return; 85 } 86 87 int sharedVar = 0; 88 int ran = 0; 89 sdbusplus::async::mutex mutex; 90 91 private: 92 std::unique_ptr<sdbusplus::async::fdio> fdioInstance; 93 int fd = -1; 94 int wd = -1; 95 }; 96 97 TEST_F(MutexTest, TestAsyncAddition) 98 { 99 constexpr auto testIterations = 10; 100 for (auto i = 0; i < testIterations; i++) 101 { 102 ctx->spawn(testAsyncAddition()); 103 } 104 105 ctx->spawn( 106 sdbusplus::async::sleep_for(*ctx, 1s) | 107 sdbusplus::async::execution::then([&]() { ctx->request_stop(); })); 108 109 ctx->run(); 110 111 EXPECT_EQ(sharedVar, testIterations); 112 } 113 114 TEST_F(MutexTest, TestAsyncMixed) 115 { 116 constexpr auto testIterations = 10; 117 for (auto i = 0; i < testIterations; i++) 118 { 119 ctx->spawn(testAsyncAddition()); 120 ctx->spawn(testAsyncSubtraction(2)); 121 } 122 123 ctx->spawn( 124 sdbusplus::async::sleep_for(*ctx, 1s) | 125 sdbusplus::async::execution::then([&]() { ctx->request_stop(); })); 126 127 ctx->run(); 128 129 EXPECT_EQ(sharedVar, -testIterations); 130 } 131 132 TEST_F(MutexTest, TestFdEvents) 133 { 134 constexpr static auto testIterations = 5; 135 136 for (auto i = 0; i < testIterations; i++) 137 { 138 ctx->spawn(testFdEvents()); 139 } 140 ctx->spawn( 141 sdbusplus::async::sleep_for(*ctx, 3s) | 142 sdbusplus::async::execution::then([&]() { ctx->request_stop(); })); 143 ctx->run(); 144 EXPECT_EQ(ran, testIterations); 145 } 146 147 TEST_F(MutexTest, TestLockGuardNoLock) 148 { 149 sdbusplus::async::lock_guard lg{mutex}; 150 } 151