1 //
2 // Copyright (C) 2019 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_generator/payload_properties.h"
18
19 #include <memory>
20 #include <string>
21 #include <vector>
22
23 #include <base/files/file_util.h>
24 #include <base/files/scoped_file.h>
25 #include <base/files/scoped_temp_dir.h>
26 #include <base/rand_util.h>
27 #include <base/strings/stringprintf.h>
28 #include <brillo/data_encoding.h>
29
30 #include <gtest/gtest.h>
31
32 #include "update_engine/common/hash_calculator.h"
33 #include "update_engine/common/test_utils.h"
34 #include "update_engine/common/utils.h"
35 #include "update_engine/payload_consumer/install_plan.h"
36 #include "update_engine/payload_generator/delta_diff_generator.h"
37 #include "update_engine/payload_generator/delta_diff_utils.h"
38 #include "update_engine/payload_generator/full_update_generator.h"
39 #include "update_engine/payload_generator/operations_generator.h"
40 #include "update_engine/payload_generator/payload_file.h"
41 #include "update_engine/payload_generator/payload_generation_config.h"
42
43 using std::string;
44 using std::unique_ptr;
45 using std::vector;
46
47 namespace chromeos_update_engine {
48
49 // TODO(kimjae): current implementation is very specific to a static way of
50 // producing a deterministic test. It would definitely be beneficial to
51 // extend the |PayloadPropertiesTest::SetUp()| into a generic helper or
52 // seperate class that can handle creation of different |PayloadFile|s.
53 class PayloadPropertiesTest : public ::testing::Test {
54 protected:
SetUp()55 void SetUp() override {
56 PayloadGenerationConfig config;
57 config.version.major = kBrilloMajorPayloadVersion;
58 config.version.minor = kSourceMinorPayloadVersion;
59 PayloadFile payload;
60 EXPECT_TRUE(payload.Init(config));
61
62 const auto SetupPartitionConfig =
63 [](PartitionConfig* config, const string& path, size_t size) {
64 config->path = path;
65 config->size = size;
66 };
67 const auto WriteZerosToFile = [](const char path[], size_t size) {
68 string zeros(size, '\0');
69 EXPECT_TRUE(utils::WriteFile(path, zeros.c_str(), zeros.size()));
70 };
71 ScopedTempFile old_part_file("old_part.XXXXXX");
72 ScopedTempFile new_part_file("new_part.XXXXXX");
73 PartitionConfig old_part(kPartitionNameRoot);
74 PartitionConfig new_part(kPartitionNameRoot);
75 SetupPartitionConfig(&old_part, old_part_file.path(), 0);
76 SetupPartitionConfig(&new_part, new_part_file.path(), 10000);
77 WriteZerosToFile(old_part_file.path().c_str(), old_part.size);
78 WriteZerosToFile(new_part_file.path().c_str(), new_part.size);
79
80 // Select payload generation strategy based on the config.
81 unique_ptr<OperationsGenerator> strategy(new FullUpdateGenerator());
82
83 vector<AnnotatedOperation> aops;
84 off_t data_file_size = 0;
85 ScopedTempFile data_file("temp_data.XXXXXX", true);
86 BlobFileWriter blob_file_writer(data_file.fd(), &data_file_size);
87 // Generate the operations using the strategy we selected above.
88 EXPECT_TRUE(strategy->GenerateOperations(
89 config, old_part, new_part, &blob_file_writer, &aops));
90
91 payload.AddPartition(old_part, new_part, aops, {}, 0);
92
93 uint64_t metadata_size;
94 EXPECT_TRUE(payload.WritePayload(
95 payload_file_.path(), data_file.path(), "", &metadata_size));
96 }
97
98 ScopedTempFile payload_file_{"payload_file.XXXXXX"};
99 };
100
101 // Validate the hash of file exists within the output.
TEST_F(PayloadPropertiesTest,GetPropertiesAsJsonTestHash)102 TEST_F(PayloadPropertiesTest, GetPropertiesAsJsonTestHash) {
103 constexpr char kJsonProperties[] =
104 "{"
105 R"("is_delta":true,)"
106 R"("metadata_signature":"",)"
107 R"("metadata_size":165,)"
108 R"("sha256_hex":"cV7kfZBH3K0B6QJHxxykDh6b6x0WgVOmc63whPLOy7U=",)"
109 R"("size":211,)"
110 R"("version":2)"
111 "}";
112 string json;
113 EXPECT_TRUE(
114 PayloadProperties(payload_file_.path()).GetPropertiesAsJson(&json));
115 EXPECT_EQ(kJsonProperties, json) << "JSON contents:\n" << json;
116 }
117
118 // Validate the hash of file and metadata are within the output.
TEST_F(PayloadPropertiesTest,GetPropertiesAsKeyValueTestHash)119 TEST_F(PayloadPropertiesTest, GetPropertiesAsKeyValueTestHash) {
120 constexpr char kKeyValueProperties[] =
121 "FILE_HASH=cV7kfZBH3K0B6QJHxxykDh6b6x0WgVOmc63whPLOy7U=\n"
122 "FILE_SIZE=211\n"
123 "METADATA_HASH=aEKYyzJt2E8Gz8fzB+gmekN5mriotZCSq6R+kDfdeV4=\n"
124 "METADATA_SIZE=165\n";
125 string key_value;
126 EXPECT_TRUE(PayloadProperties{payload_file_.path()}.GetPropertiesAsKeyValue(
127 &key_value));
128 EXPECT_EQ(kKeyValueProperties, key_value) << "Key Value contents:\n"
129 << key_value;
130 }
131
132 } // namespace chromeos_update_engine
133