BlockCacheTests.cpp 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AzCore/Casting/numeric_cast.h>
  9. #include <AzCore/UnitTest/TestTypes.h>
  10. #include <AzTest/AzTest.h>
  11. #include <AzCore/IO/Streamer/BlockCache.h>
  12. #include <AzCore/IO/Streamer/FileRequest.h>
  13. #include <AzCore/IO/Streamer/StreamerContext.h>
  14. #include <AzCore/Memory/Memory.h>
  15. #include <AzCore/Memory/PoolAllocator.h>
  16. #include <AzCore/std/smart_ptr/make_shared.h>
  17. #include <AzCore/std/smart_ptr/unique_ptr.h>
  18. #include <Tests/FileIOBaseTestTypes.h>
  19. #include <Tests/Streamer/StreamStackEntryConformityTests.h>
  20. #include <Tests/Streamer/StreamStackEntryMock.h>
  21. namespace AZ::IO
  22. {
  23. class BlockCacheTestDescription :
  24. public StreamStackEntryConformityTestsDescriptor<BlockCache>
  25. {
  26. public:
  27. BlockCache CreateInstance() override
  28. {
  29. return BlockCache(5 * 1024 * 1024, 64 * 1024, AZCORE_GLOBAL_NEW_ALIGNMENT, false);
  30. }
  31. };
  32. INSTANTIATE_TYPED_TEST_SUITE_P(Streamer_BlockCacheConformityTests, StreamStackEntryConformityTests, BlockCacheTestDescription);
  33. class BlockCacheTest
  34. : public UnitTest::LeakDetectionFixture
  35. {
  36. public:
  37. void SetUp() override
  38. {
  39. m_prevFileIO = AZ::IO::FileIOBase::GetInstance();
  40. AZ::IO::FileIOBase::SetInstance(&m_fileIO);
  41. m_path = "Test";
  42. m_context = new StreamerContext();
  43. }
  44. void TearDown() override
  45. {
  46. delete[] m_buffer;
  47. m_buffer = nullptr;
  48. m_cache = nullptr;
  49. m_mock = nullptr;
  50. delete m_context;
  51. m_context = nullptr;
  52. AZ::IO::FileIOBase::SetInstance(m_prevFileIO);
  53. }
  54. void CreateTestEnvironmentImplementation(bool onlyEpilogWrites)
  55. {
  56. using ::testing::_;
  57. m_cache = AZStd::make_shared<BlockCache>(m_cacheSize, m_blockSize, AZCORE_GLOBAL_NEW_ALIGNMENT, onlyEpilogWrites);
  58. m_mock = AZStd::make_shared<StreamStackEntryMock>();
  59. m_cache->SetNext(m_mock);
  60. EXPECT_CALL(*m_mock, SetContext(_)).Times(1);
  61. m_cache->SetContext(*m_context);
  62. m_bufferSize = m_readBufferLength >> 2;
  63. m_buffer = new u32[m_bufferSize];
  64. }
  65. void RedirectReadCalls()
  66. {
  67. using ::testing::_;
  68. using ::testing::AnyNumber;
  69. using ::testing::Return;
  70. EXPECT_CALL(*m_mock, ExecuteRequests())
  71. .WillOnce(Return(true))
  72. .WillRepeatedly(Return(false));
  73. EXPECT_CALL(*m_mock, QueueRequest(_))
  74. .WillRepeatedly(Invoke(this, &BlockCacheTest::QueueReadRequest));
  75. }
  76. void QueueReadRequest(FileRequest* request)
  77. {
  78. auto data = AZStd::get_if<Requests::ReadData>(&request->GetCommand());
  79. if (data)
  80. {
  81. if (m_fakeFileFound)
  82. {
  83. u64 size = data->m_size >> 2;
  84. u32* buffer = reinterpret_cast<u32*>(data->m_output);
  85. for (u64 i = 0; i < size; ++i)
  86. {
  87. buffer[i] = aznumeric_caster(data->m_offset + (i << 2));
  88. }
  89. ReadFile(data->m_output, data->m_path, data->m_offset, data->m_size);
  90. request->SetStatus(IStreamerTypes::RequestStatus::Completed);
  91. }
  92. else
  93. {
  94. request->SetStatus(IStreamerTypes::RequestStatus::Failed);
  95. }
  96. m_context->MarkRequestAsCompleted(request);
  97. }
  98. else if (
  99. AZStd::holds_alternative<Requests::FlushData>(request->GetCommand()) ||
  100. AZStd::holds_alternative<Requests::FlushAllData>(request->GetCommand()))
  101. {
  102. request->SetStatus(IStreamerTypes::RequestStatus::Completed);
  103. m_context->MarkRequestAsCompleted(request);
  104. }
  105. else if (AZStd::holds_alternative<Requests::FileMetaDataRetrievalData>(request->GetCommand()))
  106. {
  107. auto& data2 = AZStd::get<Requests::FileMetaDataRetrievalData>(request->GetCommand());
  108. data2.m_found = m_fakeFileFound;
  109. data2.m_fileSize = m_fakeFileLength;
  110. request->SetStatus(m_fakeFileFound ? IStreamerTypes::RequestStatus::Completed : IStreamerTypes::RequestStatus::Failed);
  111. m_context->MarkRequestAsCompleted(request);
  112. }
  113. else
  114. {
  115. // While there are more commands that possible, only the above ones are supported in these tests. Add additional
  116. // commands as needed.
  117. FAIL();
  118. }
  119. }
  120. void RedirectCanceledReadCalls()
  121. {
  122. using ::testing::_;
  123. using ::testing::Return;
  124. EXPECT_CALL(*m_mock, ExecuteRequests())
  125. .WillOnce(Return(true))
  126. .WillRepeatedly(Return(false));
  127. EXPECT_CALL(*m_mock, QueueRequest(_))
  128. .WillRepeatedly(Invoke(this, &BlockCacheTest::QueueCanceledReadRequest));
  129. }
  130. void QueueCanceledReadRequest(FileRequest* request)
  131. {
  132. auto data = AZStd::get_if<Requests::ReadData>(&request->GetCommand());
  133. if (data)
  134. {
  135. ReadFile(data->m_output, data->m_path, data->m_offset, data->m_size);
  136. request->SetStatus(IStreamerTypes::RequestStatus::Canceled);
  137. m_context->MarkRequestAsCompleted(request);
  138. }
  139. else if (AZStd::holds_alternative<Requests::FileMetaDataRetrievalData>(request->GetCommand()))
  140. {
  141. auto& data2 = AZStd::get<Requests::FileMetaDataRetrievalData>(request->GetCommand());
  142. data2.m_found = true;
  143. data2.m_fileSize = m_fakeFileLength;
  144. request->SetStatus(IStreamerTypes::RequestStatus::Completed);
  145. m_context->MarkRequestAsCompleted(request);
  146. }
  147. else
  148. {
  149. FAIL();
  150. }
  151. }
  152. void VerifyReadBuffer(u32* buffer, u64 offset, u64 size)
  153. {
  154. size = size >> 2;
  155. for (u64 i = 0; i < size; ++i)
  156. {
  157. // Using assert here because in case of a problem EXPECT would
  158. // cause a large amount of log noise.
  159. ASSERT_EQ(buffer[i], offset + (i << 2));
  160. }
  161. }
  162. void VerifyReadBuffer(u64 offset, u64 size)
  163. {
  164. VerifyReadBuffer(m_buffer, offset, size);
  165. }
  166. protected:
  167. // To make testing easier, this utility mock unpacks the read requests.
  168. MOCK_METHOD4(ReadFile, bool(void*, const RequestPath&, u64, u64));
  169. void RunProcessLoop()
  170. {
  171. do
  172. {
  173. while (m_context->FinalizeCompletedRequests())
  174. {
  175. }
  176. } while (m_cache->ExecuteRequests());
  177. }
  178. void RunAndCompleteRequest(FileRequest* request, IStreamerTypes::RequestStatus expectedResult)
  179. {
  180. IStreamerTypes::RequestStatus result = IStreamerTypes::RequestStatus::Pending;
  181. request->SetCompletionCallback([&result](const FileRequest& request)
  182. {
  183. // Capture result before internal request is recycled.
  184. result = request.GetStatus();
  185. });
  186. m_cache->QueueRequest(request);
  187. RunProcessLoop();
  188. EXPECT_EQ(expectedResult, result);
  189. }
  190. void ProcessRead(void* output, const RequestPath& path, u64 offset, u64 size, IStreamerTypes::RequestStatus expectedResult)
  191. {
  192. FileRequest* request = m_context->GetNewInternalRequest();
  193. request->CreateRead(nullptr, output, size, path, offset, size);
  194. RunAndCompleteRequest(request, expectedResult);
  195. }
  196. UnitTest::TestFileIOBase m_fileIO;
  197. FileIOBase* m_prevFileIO{};
  198. StreamerContext* m_context;
  199. AZStd::shared_ptr<BlockCache> m_cache;
  200. AZStd::shared_ptr<StreamStackEntryMock> m_mock;
  201. RequestPath m_path;
  202. u32* m_buffer{ nullptr };
  203. size_t m_bufferSize{ 0 };
  204. u64 m_cacheSize{ 5 * 1024 * 1024 };
  205. u32 m_blockSize{ 64 * 1024 };
  206. u64 m_fakeFileLength{ 5 * m_blockSize };
  207. u64 m_readBufferLength{ 10 * 1024 * 1024 };
  208. bool m_fakeFileFound{ true };
  209. };
  210. /////////////////////////////////////////////////////////////
  211. // Prolog and epilog enabled
  212. /////////////////////////////////////////////////////////////
  213. class Streamer_BlockCacheWithPrologAndEpilogTest
  214. : public BlockCacheTest
  215. {
  216. public:
  217. void CreateTestEnvironment()
  218. {
  219. CreateTestEnvironmentImplementation(false);
  220. }
  221. };
  222. // File |------------------------------------------------|
  223. // Request |------------------------------------------------|
  224. // Cache [ x ][ x ][ x ][ x ][ x ]
  225. TEST_F(Streamer_BlockCacheWithPrologAndEpilogTest, ReadFile_EntireFileRead_FileReadInASingleRead)
  226. {
  227. using ::testing::_;
  228. CreateTestEnvironment();
  229. RedirectReadCalls();
  230. EXPECT_CALL(*this, ReadFile(_, _, 0, m_fakeFileLength));
  231. ProcessRead(m_buffer, m_path, 0, m_fakeFileLength, IStreamerTypes::RequestStatus::Completed);
  232. VerifyReadBuffer(0, m_fakeFileLength);
  233. }
  234. // File |----------------------------------------------|
  235. // Request |----------------------------------------------|
  236. // Cache [ x ][ x ][ x ][ x ][ x ]
  237. TEST_F(Streamer_BlockCacheWithPrologAndEpilogTest, ReadFile_EntireUnalignedFileRead_FileReadInASingleRead)
  238. {
  239. using ::testing::_;
  240. m_fakeFileLength -= 512;
  241. CreateTestEnvironment();
  242. RedirectReadCalls();
  243. EXPECT_CALL(*this, ReadFile(_, _, 0, m_fakeFileLength));
  244. ProcessRead(m_buffer, m_path, 0, m_fakeFileLength, IStreamerTypes::RequestStatus::Completed);
  245. VerifyReadBuffer(0, m_fakeFileLength);
  246. }
  247. // File |------------------------------------------------|
  248. // Request |-------------------------------------------|
  249. // Cache [ v ][ x ][ x ][ x ][ x ]
  250. TEST_F(Streamer_BlockCacheWithPrologAndEpilogTest, ReadFile_PrologCacheLargeRequest_FileReadInTwoReads)
  251. {
  252. using ::testing::_;
  253. CreateTestEnvironment();
  254. RedirectReadCalls();
  255. EXPECT_CALL(*this, ReadFile(_, _, 0, m_blockSize));
  256. EXPECT_CALL(*this, ReadFile(_, _, m_blockSize, m_fakeFileLength - m_blockSize));
  257. ProcessRead(m_buffer, m_path, 256, m_fakeFileLength - 256, IStreamerTypes::RequestStatus::Completed);
  258. VerifyReadBuffer(256, m_fakeFileLength - 256);
  259. }
  260. // File |------------------------------------------------|
  261. // Request |-------------------------------------------|
  262. // Cache [ x ][ x ][ x ][ x ][ v ]
  263. TEST_F(Streamer_BlockCacheWithPrologAndEpilogTest, ReadFile_EpilogCacheLargeRequest_FileReadInTwoReads)
  264. {
  265. using ::testing::_;
  266. CreateTestEnvironment();
  267. RedirectReadCalls();
  268. EXPECT_CALL(*this, ReadFile(_, _, 0, m_fakeFileLength - m_blockSize));
  269. EXPECT_CALL(*this, ReadFile(_, _, m_fakeFileLength - m_blockSize, m_blockSize));
  270. ProcessRead(m_buffer, m_path, 0, m_fakeFileLength - 256, IStreamerTypes::RequestStatus::Completed);
  271. VerifyReadBuffer(0, m_fakeFileLength - 256);
  272. }
  273. // File |----------------------------------------------|
  274. // Request |-------------------------------------------|
  275. // Cache [ x ][ x ][ x ][ x ][ v ]
  276. TEST_F(Streamer_BlockCacheWithPrologAndEpilogTest, ReadFile_UnalignedEpilogCacheLargeRequest_FileReadInTwoReads)
  277. {
  278. using ::testing::_;
  279. m_fakeFileLength -= 512;
  280. CreateTestEnvironment();
  281. RedirectReadCalls();
  282. EXPECT_CALL(*this, ReadFile(_, _, 0, 4 * m_blockSize));
  283. EXPECT_CALL(*this, ReadFile(_, _, 4 * m_blockSize, m_fakeFileLength - 4 * m_blockSize));
  284. ProcessRead(m_buffer, m_path, 0, m_fakeFileLength - 256, IStreamerTypes::RequestStatus::Completed);
  285. VerifyReadBuffer(0, m_fakeFileLength - 256);
  286. }
  287. // File |------------------------------------------------|
  288. // Request |---------------------------------------|
  289. // Cache [ v ][ x ][ x ][ x ][ v ]
  290. TEST_F(Streamer_BlockCacheWithPrologAndEpilogTest, ReadFile_PrologAndEpilogCacheLargeRequest_FileReadInThreeReads)
  291. {
  292. using ::testing::_;
  293. CreateTestEnvironment();
  294. RedirectReadCalls();
  295. EXPECT_CALL(*this, ReadFile(_, _, 0, m_blockSize));
  296. EXPECT_CALL(*this, ReadFile(_, _, m_blockSize, m_fakeFileLength - 2 * m_blockSize));
  297. EXPECT_CALL(*this, ReadFile(_, _, m_fakeFileLength - m_blockSize, m_blockSize));
  298. ProcessRead(m_buffer, m_path, 256, m_fakeFileLength - 512, IStreamerTypes::RequestStatus::Completed);
  299. VerifyReadBuffer(256, m_fakeFileLength - 512);
  300. }
  301. // File |------------------------------------------------|
  302. // Request |---------|
  303. // Cache [ v ][ v ][ x ][ x ][ x ]
  304. TEST_F(Streamer_BlockCacheWithPrologAndEpilogTest, ReadFile_PrologAndEpilogInTwoBlocks_FileReadInTwoReads)
  305. {
  306. using ::testing::_;
  307. CreateTestEnvironment();
  308. RedirectReadCalls();
  309. EXPECT_CALL(*this, ReadFile(_, _, 0, m_blockSize));
  310. EXPECT_CALL(*this, ReadFile(_, _, m_blockSize, m_blockSize));
  311. ProcessRead(m_buffer, m_path, 256, m_blockSize, IStreamerTypes::RequestStatus::Completed);
  312. VerifyReadBuffer(256, m_blockSize);
  313. }
  314. // File |------------------------------------------------|
  315. // Request |--------|
  316. // Cache [ x ][ x ][ x ][ x ][ x ]
  317. TEST_F(Streamer_BlockCacheWithPrologAndEpilogTest, ReadFile_ExactBlockRead_FileReadInASingleRead)
  318. {
  319. using ::testing::_;
  320. CreateTestEnvironment();
  321. RedirectReadCalls();
  322. EXPECT_CALL(*this, ReadFile(_, _, 0, m_blockSize));
  323. ProcessRead(m_buffer, m_path, 0, m_blockSize, IStreamerTypes::RequestStatus::Completed);
  324. VerifyReadBuffer(0, m_blockSize);
  325. }
  326. // File |------------------------------------------------|
  327. // Request |------|
  328. // Cache [ v ][ x ][ x ][ x ][ x ]
  329. TEST_F(Streamer_BlockCacheWithPrologAndEpilogTest, ReadFile_SmallRead_FileReadInASingleRead)
  330. {
  331. using ::testing::_;
  332. CreateTestEnvironment();
  333. RedirectReadCalls();
  334. EXPECT_CALL(*this, ReadFile(_, _, 0, m_blockSize));
  335. ProcessRead(m_buffer, m_path, 0, m_blockSize - 256, IStreamerTypes::RequestStatus::Completed);
  336. VerifyReadBuffer(0, m_blockSize - 256);
  337. }
  338. // File |-----|
  339. // Request |---|
  340. // Cache [ v ][ x ][ x ][ x ][ x ]
  341. TEST_F(Streamer_BlockCacheWithPrologAndEpilogTest, ReadFile_SmallReadUnalignedFile_FileReadInASingleRead)
  342. {
  343. using ::testing::_;
  344. m_fakeFileLength = m_blockSize - 128;
  345. CreateTestEnvironment();
  346. RedirectReadCalls();
  347. EXPECT_CALL(*this, ReadFile(_, _, 0, m_fakeFileLength));
  348. ProcessRead(m_buffer, m_path, 0, m_fakeFileLength - 256, IStreamerTypes::RequestStatus::Completed);
  349. VerifyReadBuffer(0, m_fakeFileLength - 256);
  350. }
  351. // File |------------------------------------------------|
  352. // Request |---|
  353. // Cache [ v ][ x ][ x ][ x ][ x ]
  354. TEST_F(Streamer_BlockCacheWithPrologAndEpilogTest, ReadFile_SmallReadWithOffset_FileReadInASingleRead)
  355. {
  356. using ::testing::_;
  357. CreateTestEnvironment();
  358. RedirectReadCalls();
  359. EXPECT_CALL(*this, ReadFile(_, _, 0, m_blockSize));
  360. ProcessRead(m_buffer, m_path, 256, m_blockSize - 512, IStreamerTypes::RequestStatus::Completed);
  361. VerifyReadBuffer(256, m_blockSize - 512);
  362. }
  363. // File |-----|
  364. // Request |---|
  365. // Cache [ v ][ x ][ x ][ x ][ x ]
  366. TEST_F(Streamer_BlockCacheWithPrologAndEpilogTest, ReadFile_SmallReadWithOffsetInUnaligedFile_FileReadInASingleRead)
  367. {
  368. using ::testing::_;
  369. m_fakeFileLength = m_blockSize - 128;
  370. CreateTestEnvironment();
  371. RedirectReadCalls();
  372. EXPECT_CALL(*this, ReadFile(_, _, 0, m_fakeFileLength));
  373. ProcessRead(m_buffer, m_path, 256, m_blockSize - 512, IStreamerTypes::RequestStatus::Completed);
  374. VerifyReadBuffer(256, m_blockSize - 512);
  375. }
  376. // File |-----|
  377. // Request |----|
  378. // Cache [ v ][ x ][ x ][ x ][ x ]
  379. TEST_F(Streamer_BlockCacheWithPrologAndEpilogTest, ReadFile_SmallReadTillEndWithOffsetInUnaligedFile_FileReadInASingleRead)
  380. {
  381. using ::testing::_;
  382. m_fakeFileLength = m_blockSize - 128;
  383. CreateTestEnvironment();
  384. RedirectReadCalls();
  385. EXPECT_CALL(*this, ReadFile(_, _, 0, m_fakeFileLength));
  386. ProcessRead(m_buffer, m_path, 256, m_fakeFileLength - 256, IStreamerTypes::RequestStatus::Completed);
  387. VerifyReadBuffer(256, m_fakeFileLength - 256);
  388. }
  389. // File |------------------------------------------------|
  390. // Request |---|
  391. // Cache [ x ][ v ][ x ][ x ][ x ]
  392. TEST_F(Streamer_BlockCacheWithPrologAndEpilogTest, ReadFile_SmallReadWithOffsetIntoNextBlock_FileReadInASingleRead)
  393. {
  394. using ::testing::_;
  395. CreateTestEnvironment();
  396. RedirectReadCalls();
  397. EXPECT_CALL(*this, ReadFile(_, _, m_blockSize, m_blockSize));
  398. ProcessRead(m_buffer, m_path, m_blockSize + 256, m_blockSize - 512, IStreamerTypes::RequestStatus::Completed);
  399. VerifyReadBuffer(m_blockSize + 256, m_blockSize - 512);
  400. }
  401. // File |------------------------------------------------|
  402. // Request |------|
  403. // Cache [ x ][ x ][ x ][ x ][ v ]
  404. TEST_F(Streamer_BlockCacheWithPrologAndEpilogTest, ReadFile_SmallReadWithOffsetIntoLastBlock_FileReadInASingleRead)
  405. {
  406. using ::testing::_;
  407. CreateTestEnvironment();
  408. RedirectReadCalls();
  409. EXPECT_CALL(*this, ReadFile(_, _, 4 * m_blockSize, m_blockSize));
  410. ProcessRead(m_buffer, m_path, 4 * m_blockSize + 256, m_blockSize - 256, IStreamerTypes::RequestStatus::Completed);
  411. VerifyReadBuffer(4 * m_blockSize + 256, m_blockSize - 256);
  412. }
  413. // File |----------------------------------------------|
  414. // Request0 |---------------------------------------|
  415. // Request1 |----|
  416. // Cache [ v ][ x ][ x ][ x ][ v ]
  417. // This test queues up multiple read that overlap so one in-flight cache block is used in two requests.
  418. TEST_F(Streamer_BlockCacheWithPrologAndEpilogTest, ReadFile_MultipleReadsOverlapping_BothFilesAreCorrectlyRead)
  419. {
  420. using ::testing::_;
  421. using ::testing::Return;
  422. CreateTestEnvironment();
  423. EXPECT_CALL(*m_mock, ExecuteRequests())
  424. .WillOnce(Return(true))
  425. .WillRepeatedly(Return(false));
  426. EXPECT_CALL(*m_mock, QueueRequest(_))
  427. .WillRepeatedly(Invoke(this, &BlockCacheTest::QueueReadRequest));
  428. EXPECT_CALL(*this, ReadFile(_, _, 0, m_blockSize));
  429. EXPECT_CALL(*this, ReadFile(_, _, m_blockSize, m_fakeFileLength - 2 * m_blockSize));
  430. EXPECT_CALL(*this, ReadFile(_, _, m_fakeFileLength - m_blockSize, m_blockSize));
  431. constexpr size_t secondReadSize = 512;
  432. constexpr size_t buffer1Size = secondReadSize / sizeof(u32);
  433. u32 buffer1[buffer1Size];
  434. FileRequest* request0 = m_context->GetNewInternalRequest();
  435. FileRequest* request1 = m_context->GetNewInternalRequest();
  436. request0->CreateRead(nullptr, m_buffer, m_bufferSize, m_path, 256, m_fakeFileLength - 512);
  437. request1->CreateRead(nullptr, buffer1, buffer1Size, m_path, m_fakeFileLength-768, secondReadSize);
  438. bool allRequestsCompleted = true;
  439. auto completed = [&allRequestsCompleted](const FileRequest& request)
  440. {
  441. // Capture result before request is recycled.
  442. allRequestsCompleted = allRequestsCompleted && request.GetStatus() == IStreamerTypes::RequestStatus::Completed;
  443. };
  444. request0->SetCompletionCallback(completed);
  445. request1->SetCompletionCallback(completed);
  446. m_cache->QueueRequest(request0);
  447. m_cache->QueueRequest(request1);
  448. RunProcessLoop();
  449. EXPECT_TRUE(allRequestsCompleted);
  450. VerifyReadBuffer(256, m_fakeFileLength - 512);
  451. VerifyReadBuffer(buffer1, m_fakeFileLength - 768, secondReadSize);
  452. }
  453. // File |----------------------------------------------|
  454. // Request0 |---------------------------------------|
  455. // Request1 |----|
  456. // Cache [ v ][ x ][ x ][ x ][ v ]
  457. // This test queues up multiple read that overlap so one in-flight cache block is used in two requests. This
  458. // is the same as the previous version except it finishes the first request so there's no wait-request created.
  459. TEST_F(Streamer_BlockCacheWithPrologAndEpilogTest, ReadFile_MultipleReadsOverlappingAfterComplete_BothFilesAreCorrectlyRead)
  460. {
  461. using ::testing::_;
  462. using ::testing::Return;
  463. CreateTestEnvironment();
  464. EXPECT_CALL(*m_mock, ExecuteRequests())
  465. .WillOnce(Return(true))
  466. .WillOnce(Return(false))
  467. .WillOnce(Return(true))
  468. .WillRepeatedly(Return(false));
  469. EXPECT_CALL(*m_mock, QueueRequest(_))
  470. .WillRepeatedly(Invoke(this, &BlockCacheTest::QueueReadRequest));
  471. EXPECT_CALL(*this, ReadFile(_, _, 0, m_blockSize));
  472. EXPECT_CALL(*this, ReadFile(_, _, m_blockSize, m_fakeFileLength - 2 * m_blockSize));
  473. EXPECT_CALL(*this, ReadFile(_, _, m_fakeFileLength - m_blockSize, m_blockSize));
  474. constexpr size_t secondReadSize = 512;
  475. constexpr size_t buffer1Size = secondReadSize / sizeof(u32);
  476. u32 buffer1[buffer1Size];
  477. FileRequest* request0 = m_context->GetNewInternalRequest();
  478. FileRequest* request1 = m_context->GetNewInternalRequest();
  479. request0->CreateRead(nullptr, m_buffer, m_bufferSize, m_path, 256, m_fakeFileLength - 512);
  480. request1->CreateRead(nullptr, buffer1, buffer1Size, m_path, m_fakeFileLength - 768, secondReadSize);
  481. bool allRequestsCompleted = true;
  482. auto completed = [&allRequestsCompleted](const FileRequest& request)
  483. {
  484. // Capture result before request is recycled.
  485. allRequestsCompleted = allRequestsCompleted && request.GetStatus() == IStreamerTypes::RequestStatus::Completed;
  486. };
  487. request0->SetCompletionCallback(completed);
  488. request1->SetCompletionCallback(completed);
  489. m_cache->QueueRequest(request0);
  490. RunProcessLoop();
  491. m_cache->QueueRequest(request1);
  492. RunProcessLoop();
  493. EXPECT_TRUE(allRequestsCompleted);
  494. VerifyReadBuffer(256, m_fakeFileLength - 512);
  495. VerifyReadBuffer(buffer1, m_fakeFileLength - 768, secondReadSize);
  496. }
  497. TEST_F(Streamer_BlockCacheWithPrologAndEpilogTest, ReadFile_FileLengthNotFound_RequestReturnsFailure)
  498. {
  499. using ::testing::_;
  500. using ::testing::Return;
  501. CreateTestEnvironment();
  502. RedirectReadCalls();
  503. m_fakeFileFound = false;
  504. m_fakeFileLength = 0;
  505. ProcessRead(m_buffer, m_path, 0, m_blockSize, IStreamerTypes::RequestStatus::Failed);
  506. }
  507. TEST_F(Streamer_BlockCacheWithPrologAndEpilogTest, ReadFile_DelayedRequest_DelayedRequestAlsoFinishes)
  508. {
  509. using ::testing::_;
  510. using ::testing::Invoke;
  511. using ::testing::Return;
  512. static const constexpr size_t count = 3;
  513. m_cacheSize = (count - 1) * m_blockSize;
  514. CreateTestEnvironment();
  515. EXPECT_CALL(*m_mock, ExecuteRequests())
  516. .WillOnce(Return(true))
  517. .WillRepeatedly(Return(false));
  518. EXPECT_CALL(*m_mock, QueueRequest(_))
  519. .Times(count * 2) // Once for the file meta file retrieval and a second time for the read.
  520. .WillRepeatedly(Invoke(this, &BlockCacheTest::QueueReadRequest));
  521. EXPECT_CALL(*m_mock, UpdateStatus(_))
  522. .WillRepeatedly(Invoke([](StreamStackEntry::Status& status)
  523. {
  524. status.m_numAvailableSlots = 64;
  525. status.m_isIdle = false;
  526. }));
  527. EXPECT_CALL(*this, ReadFile(_, _, _, _)).Times(count);
  528. constexpr size_t scratchBufferSize = 128_kib;
  529. using ScratchBuffer = char[scratchBufferSize];
  530. ScratchBuffer buffers[count];
  531. bool allRequestsCompleted = true;
  532. auto completed = [&allRequestsCompleted](const FileRequest& request)
  533. {
  534. // Capture result before request is recycled.
  535. allRequestsCompleted = allRequestsCompleted && request.GetStatus() == IStreamerTypes::RequestStatus::Completed;
  536. };
  537. for (size_t i = 0; i < count; ++i)
  538. {
  539. StreamStackEntry::Status status;
  540. m_cache->UpdateStatus(status);
  541. EXPECT_EQ(i == (count - 1) ? 0 : (count - i - 1), status.m_numAvailableSlots);
  542. FileRequest* request = m_context->GetNewInternalRequest();
  543. request->CreateRead(nullptr, buffers[i], scratchBufferSize, m_path, (m_blockSize - 256) * i, m_blockSize - 256);
  544. request->SetCompletionCallback(completed);
  545. m_cache->QueueRequest(request);
  546. }
  547. RunProcessLoop();
  548. EXPECT_TRUE(allRequestsCompleted);
  549. }
  550. /////////////////////////////////////////////////////////////
  551. // Prolog and epilog can read, but only the epilog can write.
  552. /////////////////////////////////////////////////////////////
  553. class Streamer_BlockCacheWithOnlyEpilogTest
  554. : public BlockCacheTest
  555. {
  556. public:
  557. void CreateTestEnvironment()
  558. {
  559. CreateTestEnvironmentImplementation(true);
  560. }
  561. };
  562. // File |------------------------------------------------|
  563. // Request |------------------------------------------------|
  564. // Cache [ x ][ x ][ x ][ x ][ x ]
  565. TEST_F(Streamer_BlockCacheWithOnlyEpilogTest, ReadFile_EntireFileRead_FileReadInASingleRead)
  566. {
  567. using ::testing::_;
  568. CreateTestEnvironment();
  569. RedirectReadCalls();
  570. EXPECT_CALL(*this, ReadFile(_, _, 0, m_fakeFileLength));
  571. ProcessRead(m_buffer, m_path, 0, m_fakeFileLength, IStreamerTypes::RequestStatus::Completed);
  572. VerifyReadBuffer(0, m_fakeFileLength);
  573. }
  574. // File |----------------------------------------------|
  575. // Request |----------------------------------------------|
  576. // Cache [ x ][ x ][ x ][ x ][ x ]
  577. TEST_F(Streamer_BlockCacheWithOnlyEpilogTest, ReadFile_EntireUnalignedFileRead_FileReadInASingleRead)
  578. {
  579. using ::testing::_;
  580. m_fakeFileLength -= 512;
  581. CreateTestEnvironment();
  582. RedirectReadCalls();
  583. EXPECT_CALL(*this, ReadFile(_, _, 0, m_fakeFileLength));
  584. ProcessRead(m_buffer, m_path, 0, m_fakeFileLength, IStreamerTypes::RequestStatus::Completed);
  585. VerifyReadBuffer(0, m_fakeFileLength);
  586. }
  587. // File |------------------------------------------------|
  588. // Request |-------------------------------------------|
  589. // Cache [ v ][ x ][ x ][ x ][ x ]
  590. TEST_F(Streamer_BlockCacheWithOnlyEpilogTest, ReadFile_PrologCacheLargeRequest_FileReadInTwoReads)
  591. {
  592. using ::testing::_;
  593. CreateTestEnvironment();
  594. RedirectReadCalls();
  595. EXPECT_CALL(*this, ReadFile(_, _, 256, m_fakeFileLength - 256));
  596. ProcessRead(m_buffer, m_path, 256, m_fakeFileLength - 256, IStreamerTypes::RequestStatus::Completed);
  597. VerifyReadBuffer(256, m_fakeFileLength - 256);
  598. }
  599. // File |------------------------------------------------|
  600. // Request |-------------------------------------------|
  601. // Cache [ x ][ x ][ x ][ x ][ v ]
  602. TEST_F(Streamer_BlockCacheWithOnlyEpilogTest, ReadFile_EpilogCacheLargeRequest_FileReadInTwoReads)
  603. {
  604. using ::testing::_;
  605. CreateTestEnvironment();
  606. RedirectReadCalls();
  607. EXPECT_CALL(*this, ReadFile(_, _, 0, m_fakeFileLength - m_blockSize));
  608. EXPECT_CALL(*this, ReadFile(_, _, m_fakeFileLength - m_blockSize, m_blockSize));
  609. ProcessRead(m_buffer, m_path, 0, m_fakeFileLength - 256, IStreamerTypes::RequestStatus::Completed);
  610. VerifyReadBuffer(0, m_fakeFileLength - 256);
  611. }
  612. // File |----------------------------------------------|
  613. // Request |-------------------------------------------|
  614. // Cache [ x ][ x ][ x ][ x ][ v ]
  615. TEST_F(Streamer_BlockCacheWithOnlyEpilogTest, ReadFile_UnalignedEpilogCacheLargeRequest_FileReadInTwoReads)
  616. {
  617. using ::testing::_;
  618. m_fakeFileLength -= 512;
  619. CreateTestEnvironment();
  620. RedirectReadCalls();
  621. EXPECT_CALL(*this, ReadFile(_, _, 0, 4 * m_blockSize));
  622. EXPECT_CALL(*this, ReadFile(_, _, 4 * m_blockSize, m_fakeFileLength - 4 * m_blockSize));
  623. ProcessRead(m_buffer, m_path, 0, m_fakeFileLength - 256, IStreamerTypes::RequestStatus::Completed);
  624. VerifyReadBuffer(0, m_fakeFileLength - 256);
  625. }
  626. // File |------------------------------------------------|
  627. // Request |---------------------------------------|
  628. // Cache [ v ][ x ][ x ][ x ][ v ]
  629. TEST_F(Streamer_BlockCacheWithOnlyEpilogTest, ReadFile_PrologAndEpilogCacheLargeRequest_FileReadInThreeReads)
  630. {
  631. using ::testing::_;
  632. CreateTestEnvironment();
  633. RedirectReadCalls();
  634. EXPECT_CALL(*this, ReadFile(_, _, 256, m_fakeFileLength - m_blockSize - 256));
  635. EXPECT_CALL(*this, ReadFile(_, _, m_fakeFileLength - m_blockSize, m_blockSize));
  636. ProcessRead(m_buffer, m_path, 256, m_fakeFileLength - 512, IStreamerTypes::RequestStatus::Completed);
  637. VerifyReadBuffer(256, m_fakeFileLength - 512);
  638. }
  639. // File |------------------------------------------------|
  640. // Request |---------|
  641. // Cache [ v ][ v ][ x ][ x ][ x ]
  642. TEST_F(Streamer_BlockCacheWithOnlyEpilogTest, ReadFile_PrologAndEpilogInTwoBlocks_FileReadInTwoReads)
  643. {
  644. using ::testing::_;
  645. CreateTestEnvironment();
  646. RedirectReadCalls();
  647. EXPECT_CALL(*this, ReadFile(_, _, 256, m_blockSize - 256));
  648. EXPECT_CALL(*this, ReadFile(_, _, m_blockSize, m_blockSize));
  649. ProcessRead(m_buffer, m_path, 256, m_blockSize, IStreamerTypes::RequestStatus::Completed);
  650. VerifyReadBuffer(256, m_blockSize);
  651. }
  652. // File |------------------------------------------------|
  653. // Request |--------|
  654. // Cache [ x ][ x ][ x ][ x ][ x ]
  655. TEST_F(Streamer_BlockCacheWithOnlyEpilogTest, ReadFile_ExactBlockRead_FileReadInASingleRead)
  656. {
  657. using ::testing::_;
  658. CreateTestEnvironment();
  659. RedirectReadCalls();
  660. EXPECT_CALL(*this, ReadFile(_, _, 0, m_blockSize));
  661. ProcessRead(m_buffer, m_path, 0, m_blockSize, IStreamerTypes::RequestStatus::Completed);
  662. VerifyReadBuffer(0, m_blockSize);
  663. }
  664. // File |------------------------------------------------|
  665. // Request |------|
  666. // Cache [ v ][ x ][ x ][ x ][ x ]
  667. TEST_F(Streamer_BlockCacheWithOnlyEpilogTest, ReadFile_SmallRead_FileReadInASingleRead)
  668. {
  669. using ::testing::_;
  670. CreateTestEnvironment();
  671. RedirectReadCalls();
  672. EXPECT_CALL(*this, ReadFile(_, _, 0, m_blockSize));
  673. ProcessRead(m_buffer, m_path, 0, m_blockSize - 256, IStreamerTypes::RequestStatus::Completed);
  674. VerifyReadBuffer(0, m_blockSize - 256);
  675. }
  676. // File |-----|
  677. // Request |---|
  678. // Cache [ v ][ x ][ x ][ x ][ x ]
  679. TEST_F(Streamer_BlockCacheWithOnlyEpilogTest, ReadFile_SmallReadUnalignedFile_FileReadInASingleRead)
  680. {
  681. using ::testing::_;
  682. m_fakeFileLength = m_blockSize - 128;
  683. CreateTestEnvironment();
  684. RedirectReadCalls();
  685. EXPECT_CALL(*this, ReadFile(_, _, 0, m_fakeFileLength));
  686. ProcessRead(m_buffer, m_path, 0, m_fakeFileLength - 256, IStreamerTypes::RequestStatus::Completed);
  687. VerifyReadBuffer(0, m_fakeFileLength - 256);
  688. }
  689. // File |------------------------------------------------|
  690. // Request |---|
  691. // Cache [ v ][ x ][ x ][ x ][ x ]
  692. TEST_F(Streamer_BlockCacheWithOnlyEpilogTest, ReadFile_SmallReadWithOffset_FileReadInASingleRead)
  693. {
  694. using ::testing::_;
  695. CreateTestEnvironment();
  696. RedirectReadCalls();
  697. EXPECT_CALL(*this, ReadFile(_, _, 0, m_blockSize));
  698. ProcessRead(m_buffer, m_path, 256, m_blockSize - 512, IStreamerTypes::RequestStatus::Completed);
  699. VerifyReadBuffer(256, m_blockSize - 512);
  700. }
  701. // File |-----|
  702. // Request |---|
  703. // Cache [ v ][ x ][ x ][ x ][ x ]
  704. TEST_F(Streamer_BlockCacheWithOnlyEpilogTest, ReadFile_SmallReadWithOffsetInUnaligedFile_FileReadInASingleRead)
  705. {
  706. using ::testing::_;
  707. m_fakeFileLength = m_blockSize - 128;
  708. CreateTestEnvironment();
  709. RedirectReadCalls();
  710. EXPECT_CALL(*this, ReadFile(_, _, 0, m_fakeFileLength));
  711. ProcessRead(m_buffer, m_path, 256, m_blockSize - 512, IStreamerTypes::RequestStatus::Completed);
  712. VerifyReadBuffer(256, m_blockSize - 512);
  713. }
  714. // File |-----|
  715. // Request |----|
  716. // Cache [ v ][ x ][ x ][ x ][ x ]
  717. TEST_F(Streamer_BlockCacheWithOnlyEpilogTest, ReadFile_SmallReadTillEndWithOffsetInUnaligedFile_FileReadInASingleRead)
  718. {
  719. using ::testing::_;
  720. m_fakeFileLength = m_blockSize - 128;
  721. CreateTestEnvironment();
  722. RedirectReadCalls();
  723. EXPECT_CALL(*this, ReadFile(_, _, 0, m_fakeFileLength));
  724. ProcessRead(m_buffer, m_path, 256, m_fakeFileLength - 256, IStreamerTypes::RequestStatus::Completed);
  725. VerifyReadBuffer(256, m_fakeFileLength - 256);
  726. }
  727. // File |------------------------------------------------|
  728. // Request |---|
  729. // Cache [ x ][ v ][ x ][ x ][ x ]
  730. TEST_F(Streamer_BlockCacheWithOnlyEpilogTest, ReadFile_SmallReadWithOffsetIntoNextBlock_FileReadInASingleRead)
  731. {
  732. using ::testing::_;
  733. CreateTestEnvironment();
  734. RedirectReadCalls();
  735. EXPECT_CALL(*this, ReadFile(_, _, m_blockSize, m_blockSize));
  736. ProcessRead(m_buffer, m_path, m_blockSize + 256, m_blockSize - 512, IStreamerTypes::RequestStatus::Completed);
  737. VerifyReadBuffer(m_blockSize + 256, m_blockSize - 512);
  738. }
  739. // File |------------------------------------------------|
  740. // Request |------|
  741. // Cache [ x ][ x ][ x ][ x ][ v ]
  742. TEST_F(Streamer_BlockCacheWithOnlyEpilogTest, ReadFile_SmallReadWithOffsetIntoLastBlock_FileReadInASingleRead)
  743. {
  744. using ::testing::_;
  745. CreateTestEnvironment();
  746. RedirectReadCalls();
  747. EXPECT_CALL(*this, ReadFile(_, _, 4 * m_blockSize, m_blockSize));
  748. ProcessRead(m_buffer, m_path, 4 * m_blockSize + 256, m_blockSize - 256, IStreamerTypes::RequestStatus::Completed);
  749. VerifyReadBuffer(4 * m_blockSize + 256, m_blockSize - 256);
  750. }
  751. // File |----------------------------------------------|
  752. // Request0 |---------------------------------------|
  753. // Request1 |----|
  754. // Cache [ v ][ x ][ x ][ x ][ v ]
  755. // This test queues up multiple reads that overlap so one in-flight cache block is used in two requests.
  756. TEST_F(Streamer_BlockCacheWithOnlyEpilogTest, ReadFile_MultipleReadsOverlapping_BothFilesAreCorrectlyRead)
  757. {
  758. using ::testing::_;
  759. using ::testing::Return;
  760. CreateTestEnvironment();
  761. EXPECT_CALL(*m_mock, ExecuteRequests())
  762. .WillOnce(Return(true))
  763. .WillRepeatedly(Return(false));
  764. EXPECT_CALL(*m_mock, QueueRequest(_))
  765. .WillRepeatedly(Invoke(this, &BlockCacheTest::QueueReadRequest));
  766. EXPECT_CALL(*this, ReadFile(_, _, 256, m_fakeFileLength - m_blockSize - 256));
  767. EXPECT_CALL(*this, ReadFile(_, _, m_fakeFileLength - m_blockSize, m_blockSize));
  768. constexpr size_t secondReadSize = 512;
  769. constexpr size_t buffer1Size = secondReadSize / sizeof(u32);
  770. u32 buffer1[buffer1Size];
  771. FileRequest* request0 = m_context->GetNewInternalRequest();
  772. FileRequest* request1 = m_context->GetNewInternalRequest();
  773. request0->CreateRead(nullptr, m_buffer, m_bufferSize, m_path, 256, m_fakeFileLength - 512);
  774. request1->CreateRead(nullptr, buffer1, buffer1Size, m_path, m_fakeFileLength - 768, secondReadSize);
  775. bool allRequestsCompleted = true;
  776. auto completed = [&allRequestsCompleted](const FileRequest& request)
  777. {
  778. // Capture result before request is recycled.
  779. allRequestsCompleted = allRequestsCompleted && request.GetStatus() == IStreamerTypes::RequestStatus::Completed;
  780. };
  781. request0->SetCompletionCallback(completed);
  782. request1->SetCompletionCallback(completed);
  783. m_cache->QueueRequest(request0);
  784. m_cache->QueueRequest(request1);
  785. RunProcessLoop();
  786. EXPECT_TRUE(allRequestsCompleted);
  787. VerifyReadBuffer(256, m_fakeFileLength - 512);
  788. VerifyReadBuffer(buffer1, m_fakeFileLength - 768, secondReadSize);
  789. }
  790. // File |----------------------------------------------|
  791. // Request0 |---------------------------------------|
  792. // Request1 |----|
  793. // Cache [ v ][ x ][ x ][ x ][ v ]
  794. // This test queues up multiple reads that overlap so one in-flight cache block is used in two requests. This
  795. // is the same as the previous version except it finishes the first request so there's no wait-request created.
  796. TEST_F(Streamer_BlockCacheWithOnlyEpilogTest, ReadFile_MultipleReadsOverlappingAfterComplete_BothFilesAreCorrectlyRead)
  797. {
  798. using ::testing::_;
  799. using ::testing::Return;
  800. CreateTestEnvironment();
  801. EXPECT_CALL(*m_mock, ExecuteRequests())
  802. .WillOnce(Return(true))
  803. .WillRepeatedly(Return(false));
  804. EXPECT_CALL(*m_mock, QueueRequest(_))
  805. .WillRepeatedly(Invoke(this, &BlockCacheTest::QueueReadRequest));
  806. EXPECT_CALL(*this, ReadFile(_, _, 256, m_fakeFileLength - m_blockSize - 256));
  807. EXPECT_CALL(*this, ReadFile(_, _, m_fakeFileLength - m_blockSize, m_blockSize));
  808. constexpr size_t secondReadSize = 512;
  809. constexpr size_t buffer1Size = secondReadSize / sizeof(u32);
  810. u32 buffer1[buffer1Size];
  811. FileRequest* request0 = m_context->GetNewInternalRequest();
  812. FileRequest* request1 = m_context->GetNewInternalRequest();
  813. request0->CreateRead(nullptr, m_buffer, m_bufferSize, m_path, 256, m_fakeFileLength - 512);
  814. request1->CreateRead(nullptr, buffer1, buffer1Size, m_path, m_fakeFileLength - 768, secondReadSize);
  815. bool allRequestsCompleted = true;
  816. auto completed = [&allRequestsCompleted](const FileRequest& request)
  817. {
  818. // Capture result before request is recycled.
  819. allRequestsCompleted = allRequestsCompleted && request.GetStatus() == IStreamerTypes::RequestStatus::Completed;
  820. };
  821. request0->SetCompletionCallback(completed);
  822. request1->SetCompletionCallback(completed);
  823. m_cache->QueueRequest(request0);
  824. RunProcessLoop();
  825. m_cache->QueueRequest(request1);
  826. m_context->FinalizeCompletedRequests();
  827. RunProcessLoop();
  828. EXPECT_TRUE(allRequestsCompleted);
  829. VerifyReadBuffer(256, m_fakeFileLength - 512);
  830. VerifyReadBuffer(buffer1, m_fakeFileLength - 768, secondReadSize);
  831. }
  832. // File |----------------------------------------------|
  833. // Request0 |---------------------|
  834. // Request1 |----------------------|
  835. // Cache [ v ][ x ][ x ][ x ][ v ]
  836. // This test queues up multiple reads that overlap so one in-flight cache block is used in two requests with the second
  837. // request using prolog, main and epilog.
  838. TEST_F(Streamer_BlockCacheWithOnlyEpilogTest, ReadFile_FetchPrologFromCache_BothFilesAreCorrectlyRead)
  839. {
  840. using ::testing::_;
  841. using ::testing::Return;
  842. CreateTestEnvironment();
  843. EXPECT_CALL(*m_mock, ExecuteRequests())
  844. .WillOnce(Return(true))
  845. .WillRepeatedly(Return(false));
  846. EXPECT_CALL(*m_mock, QueueRequest(_))
  847. .WillRepeatedly(Invoke(this, &BlockCacheTest::QueueReadRequest));
  848. size_t firstReadSize = m_fakeFileLength - (2 * m_blockSize) - 512;
  849. FileRequest* request0 = m_context->GetNewInternalRequest();
  850. request0->CreateRead(nullptr, m_buffer, m_bufferSize, m_path, 256, firstReadSize);
  851. EXPECT_CALL(*this, ReadFile(_, _, 256, m_fakeFileLength - (3 * m_blockSize) - 256));
  852. EXPECT_CALL(*this, ReadFile(_, _, m_fakeFileLength - (3 * m_blockSize), m_blockSize));
  853. size_t secondReadSize = (m_blockSize - 256) + m_blockSize + (m_blockSize - 256);
  854. size_t secondReadOffset = m_fakeFileLength - secondReadSize - 256;
  855. size_t buffer1Size = secondReadSize / sizeof(u32);
  856. auto buffer1 = AZStd::make_unique<u32[]>(buffer1Size);
  857. FileRequest* request1 = m_context->GetNewInternalRequest();
  858. request1->CreateRead(nullptr, buffer1.get(), buffer1Size, m_path, secondReadOffset, secondReadSize);
  859. EXPECT_CALL(*this, ReadFile(_, _, m_fakeFileLength - 2 * m_blockSize, m_blockSize));
  860. EXPECT_CALL(*this, ReadFile(_, _, m_fakeFileLength - m_blockSize, m_blockSize));
  861. bool allRequestsCompleted = true;
  862. auto completed = [&allRequestsCompleted](const FileRequest& request)
  863. {
  864. // Capture result before request is recycled.
  865. allRequestsCompleted = allRequestsCompleted && request.GetStatus() == IStreamerTypes::RequestStatus::Completed;
  866. };
  867. request0->SetCompletionCallback(completed);
  868. request1->SetCompletionCallback(completed);
  869. m_cache->QueueRequest(request0);
  870. m_cache->QueueRequest(request1);
  871. RunProcessLoop();
  872. EXPECT_TRUE(allRequestsCompleted);
  873. VerifyReadBuffer(256, firstReadSize);
  874. VerifyReadBuffer(buffer1.get(), secondReadOffset, secondReadSize);
  875. }
  876. /////////////////////////////////////////////////////////////
  877. // Generic block cache test.
  878. /////////////////////////////////////////////////////////////
  879. class Streamer_BlockCacheGenericTest
  880. : public BlockCacheTest
  881. {
  882. public:
  883. void CreateTestEnvironment()
  884. {
  885. CreateTestEnvironmentImplementation(false);
  886. }
  887. };
  888. TEST_F(Streamer_BlockCacheGenericTest, Cancel_QueueReadAndCancel_SubRequestPushCanceledThroughCache)
  889. {
  890. using ::testing::_;
  891. CreateTestEnvironment();
  892. RedirectCanceledReadCalls();
  893. EXPECT_CALL(*this, ReadFile(_, _, 0, m_blockSize));
  894. EXPECT_CALL(*this, ReadFile(_, _, m_blockSize, m_fakeFileLength - 2 * m_blockSize));
  895. EXPECT_CALL(*this, ReadFile(_, _, m_fakeFileLength - m_blockSize, m_blockSize));
  896. ProcessRead(m_buffer, m_path, 256, m_fakeFileLength - 512, IStreamerTypes::RequestStatus::Canceled);
  897. }
  898. // File |------------------------------------------------|
  899. // Request |---|
  900. // Cache [ v ][ x ][ x ][ x ][ x ]
  901. TEST_F(Streamer_BlockCacheGenericTest, Flush_FlushPreviouslyReadFile_FileIsReadAgain)
  902. {
  903. using ::testing::_;
  904. CreateTestEnvironment();
  905. RedirectReadCalls();
  906. // Initial read to seed the cache.
  907. EXPECT_CALL(*this, ReadFile(_, _, _, _)).Times(1);
  908. ProcessRead(m_buffer, m_path, 256, m_blockSize - 512, IStreamerTypes::RequestStatus::Completed);
  909. // Flush from the cache to remove the previously cached read.
  910. FileRequest* request = m_context->GetNewInternalRequest();
  911. request->CreateFlush(m_path);
  912. RunAndCompleteRequest(request, IStreamerTypes::RequestStatus::Completed);
  913. // The partial read would normally be serviced from the cache, but now triggers another read.
  914. EXPECT_CALL(*this, ReadFile(_, _, _, _)).Times(1);
  915. ProcessRead(m_buffer, m_path, 512, m_blockSize - 1024, IStreamerTypes::RequestStatus::Completed);
  916. }
  917. // File |------------------------------------------------|
  918. // Request |---|
  919. // Cache [ v ][ x ][ x ][ x ][ x ]
  920. TEST_F(Streamer_BlockCacheGenericTest, FlushAll_FlushAllPreviouslyReadFiles_FileIsReadAgain)
  921. {
  922. using ::testing::_;
  923. CreateTestEnvironment();
  924. RedirectReadCalls();
  925. // Initial read to seed the cache.
  926. EXPECT_CALL(*this, ReadFile(_, _, _, _)).Times(1);
  927. ProcessRead(m_buffer, m_path, 256, m_blockSize - 512, IStreamerTypes::RequestStatus::Completed);
  928. // Flush everything from the cache, including the previously cached read.
  929. FileRequest* request = m_context->GetNewInternalRequest();
  930. request->CreateFlushAll();
  931. RunAndCompleteRequest(request, IStreamerTypes::RequestStatus::Completed);
  932. // The partial read would normally be serviced from the cache, but now triggers another read.
  933. EXPECT_CALL(*this, ReadFile(_, _, _, _)).Times(1);
  934. ProcessRead(m_buffer, m_path, 512, m_blockSize - 1024, IStreamerTypes::RequestStatus::Completed);
  935. }
  936. } // namespace AZ::IO