1aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
2aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Copyright (C) 2009 The Android Open Source Project
3aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
4aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Licensed under the Apache License, Version 2.0 (the "License");
5aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// you may not use this file except in compliance with the License.
6aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// You may obtain a copy of the License at
7aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
8aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//      http://www.apache.org/licenses/LICENSE-2.0
9aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
10aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Unless required by applicable law or agreed to in writing, software
11aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// distributed under the License is distributed on an "AS IS" BASIS,
12aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// See the License for the specific language governing permissions and
14aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// limitations under the License.
15aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
168006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes
1739910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo#include "update_engine/payload_consumer/bzip_extent_writer.h"
18aab50e31f0b80ed53a9b8d5dbabcf943974bd32cAlex Deymo
194eccae2ffd51c1e76ccd6463212c8e3addbb873eXiyuan Xia#include <fcntl.h>
204eccae2ffd51c1e76ccd6463212c8e3addbb873eXiyuan Xia
218006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes#include <algorithm>
228006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes#include <string>
238006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes#include <vector>
2405322879380a15f7042f4023b4ce4fec4b8bf50bAlex Deymo
253f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenko#include <brillo/make_unique_ptr.h>
268006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes#include <gtest/gtest.h>
2705322879380a15f7042f4023b4ce4fec4b8bf50bAlex Deymo
2839910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo#include "update_engine/common/test_utils.h"
2939910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo#include "update_engine/common/utils.h"
308006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes
318006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyesusing std::min;
328006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyesusing std::string;
338006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyesusing std::vector;
348006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes
358006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyesnamespace chromeos_update_engine {
368006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes
378006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyesnamespace {
3809e56d64202d2148b95008c5bd18cf719ec0f40cAndrew de los Reyesconst uint32_t kBlockSize = 4096;
398006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes}
408006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes
418006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyesclass BzipExtentWriterTest : public ::testing::Test {
428006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes protected:
43610277efc6f7e5239158dfa4bb3b1021804326e0Alex Deymo  void SetUp() override {
44f1d582e1a39e170d1a7e20bd21cad25b3f70f96aNam T. Nguyen    fd_.reset(new EintrSafeFileDescriptor);
45bffa06080ec8bd5d196cbfadf2023f78b6e89169Alex Deymo    ASSERT_TRUE(fd_->Open(temp_file_.path().c_str(), O_RDWR, 0600));
468006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes  }
47610277efc6f7e5239158dfa4bb3b1021804326e0Alex Deymo  void TearDown() override {
48f1d582e1a39e170d1a7e20bd21cad25b3f70f96aNam T. Nguyen    fd_->Close();
498006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes  }
508006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes  void WriteAlignedExtents(size_t chunk_size, size_t first_chunk_size);
518006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes  void TestZeroPad(bool aligned_size);
52f1d582e1a39e170d1a7e20bd21cad25b3f70f96aNam T. Nguyen
53f1d582e1a39e170d1a7e20bd21cad25b3f70f96aNam T. Nguyen  FileDescriptorPtr fd_;
54bffa06080ec8bd5d196cbfadf2023f78b6e89169Alex Deymo  test_utils::ScopedTempFile temp_file_{"BzipExtentWriterTest-file.XXXXXX"};
558006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes};
568006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes
578006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los ReyesTEST_F(BzipExtentWriterTest, SimpleTest) {
588006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes  vector<Extent> extents;
598006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes  Extent extent;
608006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes  extent.set_start_block(0);
618006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes  extent.set_num_blocks(1);
628006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes  extents.push_back(extent);
638006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes
648006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes  // 'echo test | bzip2 | hexdump' yields:
65e0622398a00e884db6d488011d8f7ecd293eb04bDarin Petkov  static const char test_uncompressed[] = "test\n";
66f68bbbc952aa9a71898e4939b5f36187fa564a50Alex Vakulenko  static const uint8_t test[] = {
678006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes    0x42, 0x5a, 0x68, 0x39, 0x31, 0x41, 0x59, 0x26, 0x53, 0x59, 0xcc, 0xc3,
688006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes    0x71, 0xd4, 0x00, 0x00, 0x02, 0x41, 0x80, 0x00, 0x10, 0x02, 0x00, 0x0c,
698006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes    0x00, 0x20, 0x00, 0x21, 0x9a, 0x68, 0x33, 0x4d, 0x19, 0x97, 0x8b, 0xb9,
70e1d1e98ef34337645a6d10551c2b0485340e3d8cGilad Arnold    0x22, 0x9c, 0x28, 0x48, 0x66, 0x61, 0xb8, 0xea, 0x00,
718006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes  };
72e1d1e98ef34337645a6d10551c2b0485340e3d8cGilad Arnold
7305322879380a15f7042f4023b4ce4fec4b8bf50bAlex Deymo  BzipExtentWriter bzip_writer(
743f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenko      brillo::make_unique_ptr(new DirectExtentWriter()));
75f1d582e1a39e170d1a7e20bd21cad25b3f70f96aNam T. Nguyen  EXPECT_TRUE(bzip_writer.Init(fd_, extents, kBlockSize));
768006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes  EXPECT_TRUE(bzip_writer.Write(test, sizeof(test)));
778006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes  EXPECT_TRUE(bzip_writer.End());
78e1d1e98ef34337645a6d10551c2b0485340e3d8cGilad Arnold
793f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenko  brillo::Blob buf;
80bffa06080ec8bd5d196cbfadf2023f78b6e89169Alex Deymo  EXPECT_TRUE(utils::ReadFile(temp_file_.path(), &buf));
81f1d582e1a39e170d1a7e20bd21cad25b3f70f96aNam T. Nguyen  EXPECT_EQ(strlen(test_uncompressed), buf.size());
82f68bbbc952aa9a71898e4939b5f36187fa564a50Alex Vakulenko  EXPECT_EQ(string(buf.begin(), buf.end()), string(test_uncompressed));
838006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes}
848006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes
858006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los ReyesTEST_F(BzipExtentWriterTest, ChunkedTest) {
86bffa06080ec8bd5d196cbfadf2023f78b6e89169Alex Deymo  // Generated with:
874eccae2ffd51c1e76ccd6463212c8e3addbb873eXiyuan Xia  //   yes "ABC" | head -c 819200 | bzip2 -9 |
884eccae2ffd51c1e76ccd6463212c8e3addbb873eXiyuan Xia  //     hexdump -v -e '"      " 11/1 "0x%02x, " "\n"'
89bffa06080ec8bd5d196cbfadf2023f78b6e89169Alex Deymo  static const uint8_t kCompressedData[] = {
90bffa06080ec8bd5d196cbfadf2023f78b6e89169Alex Deymo      0x42, 0x5a, 0x68, 0x39, 0x31, 0x41, 0x59, 0x26, 0x53, 0x59, 0xbe,
91bffa06080ec8bd5d196cbfadf2023f78b6e89169Alex Deymo      0x1c, 0xda, 0xee, 0x03, 0x1f, 0xff, 0xc4, 0x00, 0x00, 0x10, 0x38,
92bffa06080ec8bd5d196cbfadf2023f78b6e89169Alex Deymo      0x00, 0x20, 0x00, 0x50, 0x66, 0x9a, 0x05, 0x28, 0x38, 0x00, 0x11,
93bffa06080ec8bd5d196cbfadf2023f78b6e89169Alex Deymo      0x60, 0x00, 0x22, 0xd0, 0x00, 0x45, 0xc0, 0x00, 0x8b, 0xc5, 0xdc,
94bffa06080ec8bd5d196cbfadf2023f78b6e89169Alex Deymo      0x91, 0x4e, 0x14, 0x24, 0x2f, 0x87, 0x36, 0xbb, 0x80};
95bffa06080ec8bd5d196cbfadf2023f78b6e89169Alex Deymo  brillo::Blob compressed_data(std::begin(kCompressedData),
96bffa06080ec8bd5d196cbfadf2023f78b6e89169Alex Deymo                               std::end(kCompressedData));
97bffa06080ec8bd5d196cbfadf2023f78b6e89169Alex Deymo
98bffa06080ec8bd5d196cbfadf2023f78b6e89169Alex Deymo  const brillo::Blob::size_type kDecompressedLength = 800 * 1024;  // 800 KiB
998006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes  const size_t kChunkSize = 3;
100e1d1e98ef34337645a6d10551c2b0485340e3d8cGilad Arnold
101bffa06080ec8bd5d196cbfadf2023f78b6e89169Alex Deymo  brillo::Blob decompressed_data(kDecompressedLength);
102bffa06080ec8bd5d196cbfadf2023f78b6e89169Alex Deymo  for (size_t i = 0; i < decompressed_data.size(); ++i)
103bffa06080ec8bd5d196cbfadf2023f78b6e89169Alex Deymo    decompressed_data[i] = static_cast<uint8_t>("ABC\n"[i % 4]);
104bffa06080ec8bd5d196cbfadf2023f78b6e89169Alex Deymo
1058006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes  vector<Extent> extents;
1068006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes  Extent extent;
1078006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes  extent.set_start_block(0);
108bffa06080ec8bd5d196cbfadf2023f78b6e89169Alex Deymo  extent.set_num_blocks((kDecompressedLength + kBlockSize - 1) / kBlockSize);
1098006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes  extents.push_back(extent);
1108006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes
11105322879380a15f7042f4023b4ce4fec4b8bf50bAlex Deymo  BzipExtentWriter bzip_writer(
1123f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenko      brillo::make_unique_ptr(new DirectExtentWriter()));
113f1d582e1a39e170d1a7e20bd21cad25b3f70f96aNam T. Nguyen  EXPECT_TRUE(bzip_writer.Init(fd_, extents, kBlockSize));
1148006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes
1153f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenko  brillo::Blob original_compressed_data = compressed_data;
1163f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenko  for (brillo::Blob::size_type i = 0; i < compressed_data.size();
1178006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes       i += kChunkSize) {
1188006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes    size_t this_chunk_size = min(kChunkSize, compressed_data.size() - i);
1198006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes    EXPECT_TRUE(bzip_writer.Write(&compressed_data[i], this_chunk_size));
1208006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes  }
1218006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes  EXPECT_TRUE(bzip_writer.End());
122e0622398a00e884db6d488011d8f7ecd293eb04bDarin Petkov
123e0622398a00e884db6d488011d8f7ecd293eb04bDarin Petkov  // Check that the const input has not been clobbered.
12410875d90cf67f883ba7c9ed13bc8d706aa8c6fbcAlex Deymo  test_utils::ExpectVectorsEq(original_compressed_data, compressed_data);
125e1d1e98ef34337645a6d10551c2b0485340e3d8cGilad Arnold
1263f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenko  brillo::Blob output;
127bffa06080ec8bd5d196cbfadf2023f78b6e89169Alex Deymo  EXPECT_TRUE(utils::ReadFile(temp_file_.path(), &output));
128f1d582e1a39e170d1a7e20bd21cad25b3f70f96aNam T. Nguyen  EXPECT_EQ(kDecompressedLength, output.size());
12910875d90cf67f883ba7c9ed13bc8d706aa8c6fbcAlex Deymo  test_utils::ExpectVectorsEq(decompressed_data, output);
1308006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes}
1318006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes
1328006106bd8dea3761d7f4dd8c8aa82d43c35bd17Andrew de los Reyes}  // namespace chromeos_update_engine
133