| #include "NVMeCache.hpp" |
| |
| #include <boost/asio.hpp> |
| #include <boost/asio/spawn.hpp> |
| |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| class TestNVMeNestedRefresh : public testing::Test |
| { |
| public: |
| boost::asio::io_context io; |
| std::shared_ptr<Scheduler<std::chrono::steady_clock>> scheduler; |
| |
| TestNVMeNestedRefresh() |
| { |
| scheduler = std::make_shared<Scheduler<std::chrono::steady_clock>>(io); |
| } |
| }; |
| |
| class MetricMock : public MetricBase<std::chrono::steady_clock> |
| { |
| public: |
| explicit MetricMock( |
| std::shared_ptr<Scheduler<std::chrono::steady_clock>> scheduler) : |
| MetricBase<std::chrono::steady_clock>( |
| std::move(scheduler), std::chrono::steady_clock::duration::max()) |
| {} |
| |
| MOCK_METHOD( |
| void, readDevice, |
| (std::function<void(std::error_code ec, size_t size, bool complete)> && |
| cb), |
| (noexcept, override)); |
| |
| MOCK_METHOD((std::string_view), getIdentifier, (), |
| (const, noexcept, override)); |
| MOCK_METHOD(bool, isCacheValid, (), (const, noexcept, override)); |
| MOCK_METHOD((std::tuple<std::chrono::time_point<ClockType>, |
| std::chrono::time_point<ClockType>, |
| std::span<const uint8_t>>), |
| getCache, (), (const, noexcept, override)); |
| }; |
| |
| TEST_F(TestNVMeNestedRefresh, NestedRefresh) |
| { |
| auto mtx = std::make_shared<MetricMock>(scheduler); |
| |
| EXPECT_CALL(*mtx, readDevice) |
| .WillRepeatedly( |
| [](std::function<void(std::error_code ec, size_t size, |
| bool complete)>&& cb) { cb({}, 0, true); }); |
| |
| scheduler->start(); |
| scheduler->dequeue(); |
| |
| bool cb1Called = false; |
| bool cb2Called = false; |
| |
| mtx->refresh([&](std::error_code ec) { |
| EXPECT_FALSE(ec); |
| cb1Called = true; |
| |
| // Issue 1: isRefreshing() should be false when the callback is |
| // triggered for completion In the bugged version, it is still true. |
| EXPECT_FALSE(mtx->isRefreshing()); |
| |
| // Issue 2: Nested refresh |
| mtx->refresh([&](std::error_code ec) { |
| EXPECT_FALSE(ec); |
| cb2Called = true; |
| }); |
| }); |
| |
| io.run_one(); // Run the first refresh |
| io.poll(); // Run any remaining handlers |
| |
| EXPECT_TRUE(cb1Called); |
| |
| // In the bugged version, cb2 will NEVER be called because it was cleared |
| // and task->refreshing was reset to false by the first refresh completion |
| // logic. |
| EXPECT_TRUE(cb2Called); |
| } |
| |
| int main(int argc, char** argv) |
| { |
| ::testing::InitGoogleTest(&argc, argv); |
| return RUN_ALL_TESTS(); |
| } |