diff --git a/repertory/repertory_test/src/ring_buffer_open_file_test.cpp b/repertory/repertory_test/src/ring_buffer_open_file_test.cpp index 132234d..cc952c3 100644 --- a/repertory/repertory_test/src/ring_buffer_open_file_test.cpp +++ b/repertory/repertory_test/src/ring_buffer_open_file_test.cpp @@ -734,4 +734,72 @@ TEST_F(ring_buffer_open_file_test, EXPECT_FALSE(file.get_read_state(13U)); } } + +TEST_F(ring_buffer_open_file_test, + prefetches_forward_without_additional_reads) { + constexpr std::size_t ring_size{8U}; + + filesystem_item fsi; + fsi.directory = false; + fsi.api_path = "/test.txt"; + fsi.size = test_chunk_size * 32U; + fsi.source_path = + test::generate_test_file_name("ring_buffer_open_file"); + + std::mutex download_mtx; + std::condition_variable download_notify; + boost::dynamic_bitset<> requested_chunks(ring_size); + + EXPECT_CALL(provider, is_read_only()).WillRepeatedly(Return(false)); + + EXPECT_CALL(provider, read_file_bytes) + .WillRepeatedly( + [&](std::string_view /* api_path */, std::size_t size, + std::uint64_t offset, data_buffer &data, + stop_type & /* stop_requested */) -> api_error { + data.assign(size, 0x5AU); + + const auto chunk = + static_cast(offset / test_chunk_size); + + EXPECT_LT(chunk, ring_size); + EXPECT_EQ(offset % test_chunk_size, 0U); + EXPECT_EQ(size, test_chunk_size); + + { + std::lock_guard download_lock(download_mtx); + if (chunk < ring_size) { + requested_chunks.set(chunk); + } + } + + download_notify.notify_all(); + return api_error::success; + }); + + ring_buffer_open_file file(ring_buffer_dir, test_chunk_size, 30U, + fsi, provider, ring_size); + + data_buffer data; + ASSERT_EQ(api_error::success, + file.read(test_chunk_size, 0U, data)); + ASSERT_EQ(data, data_buffer(test_chunk_size, 0x5AU)); + + // Issue no further reads: chunks 1–7 must be prefetched. + std::unique_lock download_lock(download_mtx); + const auto prefetched = + download_notify.wait_for( + download_lock, std::chrono::seconds{5}, + [&]() -> bool { return requested_chunks.all(); }); + + const auto observed_chunks = requested_chunks; + download_lock.unlock(); + + // Join the workers before their captured state is destroyed. + file.close(); + + EXPECT_TRUE(prefetched) + << "Forward prefetch did not request the entire window. " + << "Requested chunks (7..0): " << observed_chunks; + } } // namespace repertory