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/file_descriptor_utils.h" 18 19 #include <fcntl.h> 20 21 #include <string> 22 #include <utility> 23 #include <vector> 24 25 #include <brillo/data_encoding.h> 26 #include <gtest/gtest.h> 27 28 #include "update_engine/common/hash_calculator.h" 29 #include "update_engine/common/test_utils.h" 30 #include "update_engine/common/utils.h" 31 #include "update_engine/payload_consumer/fake_file_descriptor.h" 32 #include "update_engine/payload_consumer/file_descriptor.h" 33 #include "update_engine/payload_generator/extent_ranges.h" 34 35 using google::protobuf::RepeatedPtrField; 36 37 namespace chromeos_update_engine { 38 39 namespace { 40 41 RepeatedPtrField<Extent> CreateExtentList( 42 const std::vector<std::pair<uint64_t, uint64_t>>& lst) { 43 RepeatedPtrField<Extent> result; 44 for (const auto& item : lst) { 45 *result.Add() = ExtentForRange(item.first, item.second); 46 } 47 return result; 48 } 49 50 } // namespace 51 52 class FileDescriptorUtilsTest : public ::testing::Test { 53 protected: 54 void SetUp() override { 55 EXPECT_TRUE(utils::MakeTempFile("fd_tgt.XXXXXX", &tgt_path_, nullptr)); 56 EXPECT_TRUE(target_->Open(tgt_path_.c_str(), O_RDWR)); 57 } 58 59 // Check that the |target_| file contains |expected_contents|. 60 void ExpectTarget(const std::string& expected_contents) { 61 std::string target_contents; 62 EXPECT_TRUE(utils::ReadFile(tgt_path_, &target_contents)); 63 EXPECT_EQ(expected_contents.size(), target_contents.size()); 64 if (target_contents != expected_contents) { 65 ADD_FAILURE() << "Contents don't match."; 66 LOG(INFO) << "Expected contents:"; 67 utils::HexDumpString(expected_contents); 68 LOG(INFO) << "Actual contents:"; 69 utils::HexDumpString(target_contents); 70 } 71 } 72 73 // Path to the target temporary file. 74 std::string tgt_path_; 75 76 // Source and target file descriptor used for testing the tools. 77 FakeFileDescriptor* fake_source_{new FakeFileDescriptor()}; 78 FileDescriptorPtr source_{fake_source_}; 79 FileDescriptorPtr target_{new EintrSafeFileDescriptor()}; 80 }; 81 82 // Source and target extents should have the same number of blocks. 83 TEST_F(FileDescriptorUtilsTest, CopyAndHashExtentsMismatchBlocksTest) { 84 auto src_extents = CreateExtentList({{1, 4}}); 85 auto tgt_extents = CreateExtentList({{0, 5}}); 86 87 EXPECT_FALSE(fd_utils::CopyAndHashExtents( 88 source_, src_extents, target_, tgt_extents, 4, nullptr)); 89 } 90 91 // Failing to read from the source should fail the copy. 92 TEST_F(FileDescriptorUtilsTest, CopyAndHashExtentsReadFailureTest) { 93 auto extents = CreateExtentList({{0, 5}}); 94 fake_source_->AddFailureRange(10, 5); 95 96 EXPECT_FALSE(fd_utils::CopyAndHashExtents( 97 source_, extents, target_, extents, 4, nullptr)); 98 } 99 100 // Failing to write to the target should fail the copy. 101 TEST_F(FileDescriptorUtilsTest, CopyAndHashExtentsWriteFailureTest) { 102 auto src_extents = CreateExtentList({{0, 2}}); 103 auto tgt_extents = CreateExtentList({{5, 2}}); 104 fake_source_->AddFailureRange(5 * 4, 10); 105 106 // Note that we pass |source_| as the target as well, which should fail to 107 // write. 108 EXPECT_FALSE(fd_utils::CopyAndHashExtents( 109 source_, src_extents, source_, tgt_extents, 4, nullptr)); 110 } 111 112 // Test that we can copy extents without hashing them, allowing a nullptr 113 // pointer as hash_out. 114 TEST_F(FileDescriptorUtilsTest, CopyAndHashExtentsWithoutHashingTest) { 115 auto extents = CreateExtentList({{0, 5}}); 116 117 EXPECT_TRUE(fd_utils::CopyAndHashExtents( 118 source_, extents, target_, extents, 4, nullptr)); 119 ExpectTarget("00000001000200030004"); 120 } 121 122 // CopyAndHash() can take different number of extents in the source and target 123 // files, as long as the number of blocks is the same. Test that it handles it 124 // properly. 125 TEST_F(FileDescriptorUtilsTest, CopyAndHashExtentsManyToOneTest) { 126 brillo::Blob hash_out; 127 // Reorder the input as 1 4 2 3 0. 128 auto src_extents = CreateExtentList({{1, 1}, {4, 1}, {2, 2}, {0, 1}}); 129 auto tgt_extents = CreateExtentList({{0, 5}}); 130 131 EXPECT_TRUE(fd_utils::CopyAndHashExtents( 132 source_, src_extents, target_, tgt_extents, 4, &hash_out)); 133 const char kExpectedResult[] = "00010004000200030000"; 134 ExpectTarget(kExpectedResult); 135 136 brillo::Blob expected_hash; 137 EXPECT_TRUE(HashCalculator::RawHashOfBytes( 138 kExpectedResult, strlen(kExpectedResult), &expected_hash)); 139 EXPECT_EQ(expected_hash, hash_out); 140 } 141 142 TEST_F(FileDescriptorUtilsTest, CopyAndHashExtentsManyToManyTest) { 143 brillo::Blob hash_out; 144 auto src_extents = CreateExtentList({{1, 1}, {4, 1}, {2, 2}, {0, 1}}); 145 auto tgt_extents = CreateExtentList({{2, 3}, {0, 2}}); 146 147 EXPECT_TRUE(fd_utils::CopyAndHashExtents( 148 source_, src_extents, target_, tgt_extents, 4, &hash_out)); 149 // The reads always match the source extent list of blocks (up to the 150 // internal buffer size). 151 std::vector<std::pair<uint64_t, uint64_t>> kExpectedOps = { 152 {4, 4}, {16, 4}, {8, 8}, {0, 4}}; 153 EXPECT_EQ(kExpectedOps, fake_source_->GetReadOps()); 154 155 // The output here is as in the previous test but the first 3 4-byte blocks 156 // are at the end of the stream. The expected hash is as in the previous 157 // example anyway since the hash doesn't depend on the order of the target 158 // blocks. 159 const char kExpectedResult[] = "00030000000100040002"; 160 ExpectTarget(kExpectedResult); 161 162 // The data in the order that the reader processes (and hashes) it. 163 const char kExpectedOrderedData[] = "00010004000200030000"; 164 brillo::Blob expected_hash; 165 EXPECT_TRUE(HashCalculator::RawHashOfBytes( 166 kExpectedOrderedData, strlen(kExpectedOrderedData), &expected_hash)); 167 EXPECT_EQ(expected_hash, hash_out); 168 } 169 170 // Failing to read from the source should fail the hash calculation. 171 TEST_F(FileDescriptorUtilsTest, ReadAndHashExtentsReadFailureTest) { 172 auto extents = CreateExtentList({{0, 5}}); 173 fake_source_->AddFailureRange(10, 5); 174 brillo::Blob hash_out; 175 EXPECT_FALSE(fd_utils::ReadAndHashExtents(source_, extents, 4, &hash_out)); 176 } 177 178 // Test that if hash_out is null, it still works. 179 TEST_F(FileDescriptorUtilsTest, ReadAndHashExtentsWithoutHashingTest) { 180 auto extents = CreateExtentList({{0, 5}}); 181 EXPECT_TRUE(fd_utils::ReadAndHashExtents(source_, extents, 4, nullptr)); 182 } 183 184 // Tests that it can calculate the hash properly. 185 TEST_F(FileDescriptorUtilsTest, ReadAndHashExtentsTest) { 186 // Reorder the input as 1 4 2 3 0. 187 auto extents = CreateExtentList({{1, 1}, {4, 1}, {2, 2}, {0, 1}}); 188 brillo::Blob hash_out; 189 EXPECT_TRUE(fd_utils::ReadAndHashExtents(source_, extents, 4, &hash_out)); 190 191 const char kExpectedResult[] = "00010004000200030000"; 192 brillo::Blob expected_hash; 193 EXPECT_TRUE(HashCalculator::RawHashOfBytes( 194 kExpectedResult, strlen(kExpectedResult), &expected_hash)); 195 EXPECT_EQ(expected_hash, hash_out); 196 } 197 198 } // namespace chromeos_update_engine 199