direct_io_ut.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. #include <library/cpp/testing/unittest/registar.h>
  2. #include <util/generic/yexception.h>
  3. #include <util/system/fs.h>
  4. #include <util/system/tempfile.h>
  5. #include <util/random/random.h>
  6. #include "direct_io.h"
  7. static const char* FileName_("./test.file");
  8. Y_UNIT_TEST_SUITE(TDirectIoTestSuite) {
  9. Y_UNIT_TEST(TestDirectFile) {
  10. TDirectIOBufferedFile file(FileName_, RdWr | Direct | Seq | CreateAlways, 1 << 15);
  11. TVector<ui64> data((1 << 15) + 1);
  12. TVector<ui64> readResult(data.size());
  13. for (auto& i : data) {
  14. i = RandomNumber<ui64>();
  15. }
  16. for (size_t writePos = 0; writePos < data.size();) {
  17. size_t writeCount = Min<size_t>(1 + RandomNumber<size_t>(1 << 10), data.ysize() - writePos);
  18. file.Write(&data[writePos], sizeof(ui64) * writeCount);
  19. writePos += writeCount;
  20. size_t readPos = RandomNumber(writePos);
  21. size_t readCount = RandomNumber(writePos - readPos);
  22. UNIT_ASSERT_VALUES_EQUAL(
  23. file.Pread(&readResult[0], readCount * sizeof(ui64), readPos * sizeof(ui64)),
  24. readCount * sizeof(ui64));
  25. for (size_t i = 0; i < readCount; ++i) {
  26. UNIT_ASSERT_VALUES_EQUAL(readResult[i], data[i + readPos]);
  27. }
  28. }
  29. file.Finish();
  30. TDirectIOBufferedFile fileNew(FileName_, RdOnly | Direct | Seq | OpenAlways, 1 << 15);
  31. for (int i = 0; i < 1000; ++i) {
  32. size_t readPos = RandomNumber(data.size());
  33. size_t readCount = RandomNumber(data.size() - readPos);
  34. UNIT_ASSERT_VALUES_EQUAL(
  35. fileNew.Pread(&readResult[0], readCount * sizeof(ui64), readPos * sizeof(ui64)),
  36. readCount * sizeof(ui64));
  37. for (size_t j = 0; j < readCount; ++j) {
  38. UNIT_ASSERT_VALUES_EQUAL(readResult[j], data[j + readPos]);
  39. }
  40. }
  41. size_t readCount = data.size();
  42. UNIT_ASSERT_VALUES_EQUAL(
  43. fileNew.Pread(&readResult[0], readCount * sizeof(ui64), 0),
  44. readCount * sizeof(ui64));
  45. for (size_t i = 0; i < readCount; ++i) {
  46. UNIT_ASSERT_VALUES_EQUAL(readResult[i], data[i]);
  47. }
  48. NFs::Remove(FileName_);
  49. }
  50. void TestHugeFile(size_t size) {
  51. TTempFile tmpFile("test.file");
  52. {
  53. TDirectIOBufferedFile directIOFile(tmpFile.Name(), WrOnly | CreateAlways | Direct);
  54. TVector<ui8> data(size, 'x');
  55. directIOFile.Write(&data[0], data.size());
  56. }
  57. {
  58. TDirectIOBufferedFile directIOFile(tmpFile.Name(), RdOnly | Direct);
  59. TVector<ui8> data(size + 1, 'y');
  60. const size_t readResult = directIOFile.Read(&data[0], data.size());
  61. UNIT_ASSERT_VALUES_EQUAL(readResult, size);
  62. UNIT_ASSERT_VALUES_EQUAL(data[0], 'x');
  63. UNIT_ASSERT_VALUES_EQUAL(data[size / 2], 'x');
  64. UNIT_ASSERT_VALUES_EQUAL(data[size - 1], 'x');
  65. UNIT_ASSERT_VALUES_EQUAL(data[size], 'y');
  66. }
  67. }
  68. Y_UNIT_TEST(TestHugeFile1) {
  69. if constexpr (sizeof(size_t) > 4) {
  70. TestHugeFile(5 * 1024 * 1024 * 1024ULL);
  71. }
  72. }
  73. Y_UNIT_TEST(TestHugeFile2) {
  74. if constexpr (sizeof(size_t) > 4) {
  75. TestHugeFile(5 * 1024 * 1024 * 1024ULL + 1111);
  76. }
  77. }
  78. } // Y_UNIT_TEST_SUITE(TDirectIoTestSuite)
  79. Y_UNIT_TEST_SUITE(TDirectIoErrorHandling) {
  80. Y_UNIT_TEST(Constructor) {
  81. // A non-existent file should not be opened for reading
  82. UNIT_ASSERT_EXCEPTION(TDirectIOBufferedFile(FileName_, RdOnly, 1 << 15), TFileError);
  83. }
  84. Y_UNIT_TEST(WritingReadOnlyFileBufferFlushed) {
  85. // Note the absence of Direct
  86. TDirectIOBufferedFile file(FileName_, RdOnly | OpenAlways, 1);
  87. TString buffer = "Hello";
  88. UNIT_ASSERT_EXCEPTION(file.Write(buffer.data(), buffer.size()), TFileError);
  89. NFs::Remove(FileName_);
  90. }
  91. Y_UNIT_TEST(WritingReadOnlyFileAllInBuffer) {
  92. TDirectIOBufferedFile file(FileName_, RdOnly | Direct | Seq | OpenAlways, 1 << 15);
  93. TString buffer = "Hello";
  94. // Doesn't throw because of buffering.
  95. file.Write(buffer.data(), buffer.size());
  96. UNIT_ASSERT_EXCEPTION(file.Finish(), TFileError);
  97. NFs::Remove(FileName_);
  98. }
  99. } // Y_UNIT_TEST_SUITE(TDirectIoErrorHandling)