1 // 2 // Copyright (C) 2017 The Android Open Source Project 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 #include "update_engine/payload_consumer/cached_file_descriptor.h" 18 19 #include <fcntl.h> 20 21 #include <algorithm> 22 #include <string> 23 #include <vector> 24 25 #include <gtest/gtest.h> 26 27 #include "update_engine/common/test_utils.h" 28 #include "update_engine/common/utils.h" 29 30 using chromeos_update_engine::test_utils::ExpectVectorsEq; 31 using std::min; 32 using std::string; 33 using std::vector; 34 35 namespace chromeos_update_engine { 36 37 namespace { 38 const size_t kCacheSize = 100; 39 const size_t kFileSize = 1024; 40 const size_t kRandomIterations = 1000; 41 } // namespace 42 43 class CachedFileDescriptorTest : public ::testing::Test { 44 public: 45 void Open() { 46 cfd_.reset(new CachedFileDescriptor(fd_, kCacheSize)); 47 EXPECT_TRUE(cfd_->Open(temp_file_.path().c_str(), O_RDWR, 0600)); 48 } 49 50 void Write(uint8_t* buffer, size_t count) { 51 size_t total_bytes_wrote = 0; 52 while (total_bytes_wrote < count) { 53 auto bytes_wrote = 54 cfd_->Write(buffer + total_bytes_wrote, count - total_bytes_wrote); 55 ASSERT_NE(bytes_wrote, -1); 56 total_bytes_wrote += bytes_wrote; 57 } 58 } 59 60 void Close() { EXPECT_TRUE(cfd_->Close()); } 61 62 void SetUp() override { 63 brillo::Blob zero_blob(kFileSize, 0); 64 EXPECT_TRUE(utils::WriteFile( 65 temp_file_.path().c_str(), zero_blob.data(), zero_blob.size())); 66 Open(); 67 } 68 69 void TearDown() override { 70 Close(); 71 EXPECT_FALSE(cfd_->IsOpen()); 72 } 73 74 protected: 75 FileDescriptorPtr fd_{new EintrSafeFileDescriptor}; 76 test_utils::ScopedTempFile temp_file_{"CachedFileDescriptor-file.XXXXXX"}; 77 int value_{1}; 78 FileDescriptorPtr cfd_; 79 }; 80 81 TEST_F(CachedFileDescriptorTest, IsOpenTest) { 82 EXPECT_TRUE(cfd_->IsOpen()); 83 } 84 85 TEST_F(CachedFileDescriptorTest, SimpleWriteTest) { 86 EXPECT_EQ(cfd_->Seek(0, SEEK_SET), 0); 87 brillo::Blob blob_in(kFileSize, value_); 88 Write(blob_in.data(), blob_in.size()); 89 EXPECT_TRUE(cfd_->Flush()); 90 91 brillo::Blob blob_out; 92 EXPECT_TRUE(utils::ReadFile(temp_file_.path(), &blob_out)); 93 EXPECT_EQ(blob_in, blob_out); 94 } 95 96 TEST_F(CachedFileDescriptorTest, OneBytePerWriteTest) { 97 EXPECT_EQ(cfd_->Seek(0, SEEK_SET), 0); 98 brillo::Blob blob_in(kFileSize, value_); 99 for (size_t idx = 0; idx < blob_in.size(); idx++) { 100 Write(&blob_in[idx], 1); 101 } 102 EXPECT_TRUE(cfd_->Flush()); 103 104 brillo::Blob blob_out; 105 EXPECT_TRUE(utils::ReadFile(temp_file_.path(), &blob_out)); 106 EXPECT_EQ(blob_in, blob_out); 107 } 108 109 TEST_F(CachedFileDescriptorTest, RandomWriteTest) { 110 EXPECT_EQ(cfd_->Seek(0, SEEK_SET), 0); 111 112 brillo::Blob blob_in(kFileSize, 0); 113 srand(time(nullptr)); 114 uint32_t rand_seed; 115 for (size_t idx = 0; idx < kRandomIterations; idx++) { 116 // zero to full size available. 117 size_t start = rand_r(&rand_seed) % blob_in.size(); 118 size_t size = rand_r(&rand_seed) % (blob_in.size() - start); 119 std::fill_n(&blob_in[start], size, idx % 256); 120 EXPECT_EQ(cfd_->Seek(start, SEEK_SET), static_cast<off64_t>(start)); 121 Write(&blob_in[start], size); 122 } 123 EXPECT_TRUE(cfd_->Flush()); 124 125 brillo::Blob blob_out; 126 EXPECT_TRUE(utils::ReadFile(temp_file_.path(), &blob_out)); 127 EXPECT_EQ(blob_in, blob_out); 128 } 129 130 TEST_F(CachedFileDescriptorTest, SeekTest) { 131 EXPECT_EQ(cfd_->Seek(0, SEEK_SET), 0); 132 EXPECT_EQ(cfd_->Seek(1, SEEK_SET), 1); 133 EXPECT_EQ(cfd_->Seek(kFileSize - 1, SEEK_SET), 134 static_cast<off64_t>(kFileSize - 1)); 135 EXPECT_EQ(cfd_->Seek(kFileSize, SEEK_SET), static_cast<off64_t>(kFileSize)); 136 EXPECT_EQ(cfd_->Seek(kFileSize + 1, SEEK_SET), 137 static_cast<off64_t>(kFileSize + 1)); 138 139 EXPECT_EQ(cfd_->Seek(0, SEEK_SET), 0); 140 EXPECT_EQ(cfd_->Seek(1, SEEK_CUR), 1); 141 EXPECT_EQ(cfd_->Seek(1, SEEK_CUR), 2); 142 EXPECT_EQ(cfd_->Seek(kFileSize - 1, SEEK_SET), 143 static_cast<off64_t>(kFileSize - 1)); 144 EXPECT_EQ(cfd_->Seek(1, SEEK_CUR), static_cast<off64_t>(kFileSize)); 145 EXPECT_EQ(cfd_->Seek(1, SEEK_CUR), static_cast<off64_t>(kFileSize + 1)); 146 } 147 148 TEST_F(CachedFileDescriptorTest, NoFlushTest) { 149 EXPECT_EQ(cfd_->Seek(0, SEEK_SET), 0); 150 brillo::Blob blob_in(kFileSize, value_); 151 Write(blob_in.data(), blob_in.size()); 152 153 brillo::Blob blob_out; 154 EXPECT_TRUE(utils::ReadFile(temp_file_.path(), &blob_out)); 155 EXPECT_NE(blob_in, blob_out); 156 } 157 158 TEST_F(CachedFileDescriptorTest, CacheSizeWriteTest) { 159 off64_t seek = 10; 160 brillo::Blob blob_in(kFileSize, 0); 161 std::fill_n(&blob_in[seek], kCacheSize, value_); 162 // We are writing exactly one cache size; Then it should be committed. 163 EXPECT_EQ(cfd_->Seek(seek, SEEK_SET), seek); 164 Write(&blob_in[seek], kCacheSize); 165 166 brillo::Blob blob_out; 167 EXPECT_TRUE(utils::ReadFile(temp_file_.path(), &blob_out)); 168 EXPECT_EQ(blob_in, blob_out); 169 } 170 171 TEST_F(CachedFileDescriptorTest, UnderCacheSizeWriteTest) { 172 off64_t seek = 100; 173 size_t less_than_cache_size = kCacheSize - 1; 174 EXPECT_EQ(cfd_->Seek(seek, SEEK_SET), seek); 175 brillo::Blob blob_in(kFileSize, 0); 176 std::fill_n(&blob_in[seek], less_than_cache_size, value_); 177 // We are writing less than one cache size; then it should not be committed. 178 Write(&blob_in[seek], less_than_cache_size); 179 180 // Revert the changes in |blob_in|. 181 std::fill_n(&blob_in[seek], less_than_cache_size, 0); 182 brillo::Blob blob_out; 183 EXPECT_TRUE(utils::ReadFile(temp_file_.path(), &blob_out)); 184 EXPECT_EQ(blob_in, blob_out); 185 } 186 187 TEST_F(CachedFileDescriptorTest, SeekAfterWriteTest) { 188 off64_t seek = 100; 189 size_t less_than_cache_size = kCacheSize - 3; 190 EXPECT_EQ(cfd_->Seek(seek, SEEK_SET), seek); 191 brillo::Blob blob_in(kFileSize, 0); 192 std::fill_n(&blob_in[seek], less_than_cache_size, value_); 193 // We are writing less than one cache size; then it should not be committed. 194 Write(&blob_in[seek], less_than_cache_size); 195 196 // Then we seek, it should've written the cache after seek. 197 EXPECT_EQ(cfd_->Seek(200, SEEK_SET), 200); 198 199 brillo::Blob blob_out; 200 EXPECT_TRUE(utils::ReadFile(temp_file_.path(), &blob_out)); 201 EXPECT_EQ(blob_in, blob_out); 202 } 203 204 } // namespace chromeos_update_engine 205