1 /*
2 * Copyright (C) 2024 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
18 #include <android-base/file.h>
19 #include <android-base/logging.h>
20 #include <android-base/properties.h>
21 #include <flag_macros.h>
22 #include <gtest/gtest.h>
23
24 #include "aconfigd_test_mock.h"
25 #include "aconfigd_util.h"
26
27 namespace android {
28 namespace aconfigd {
29
30 class AconfigdProtonColliderTest : public ::testing::Test {
31 protected:
32
list_container_storage_message(const std::string & container)33 StorageRequestMessage list_container_storage_message(const std::string& container) {
34 auto message = StorageRequestMessage();
35 auto* msg = message.mutable_list_storage_message();
36 msg->set_container(container);
37 return message;
38 }
39
ota_flag_staging_message(const std::string & build_id,const std::vector<std::tuple<std::string,std::string,std::string>> flags)40 StorageRequestMessage ota_flag_staging_message(
41 const std::string& build_id,
42 const std::vector<std::tuple<std::string, std::string, std::string>> flags) {
43 auto message = StorageRequestMessage();
44 auto* msg = message.mutable_ota_staging_message();
45 msg->set_build_id(build_id);
46 for (auto const& [package_name, flag_name, flag_value] : flags) {
47 auto* flag = msg->add_overrides();
48 flag->set_package_name(package_name);
49 flag->set_flag_name(flag_name);
50 flag->set_flag_value(flag_value);
51 }
52 return message;
53 }
54
verify_ota_staging_return_message(base::Result<StorageReturnMessage> msg_result)55 void verify_ota_staging_return_message(base::Result<StorageReturnMessage> msg_result) {
56 ASSERT_TRUE(msg_result.ok()) << msg_result.error();
57 auto msg = *msg_result;
58 ASSERT_TRUE(msg.has_ota_staging_message()) << msg.error_message();
59 }
60
verify_error_message(base::Result<StorageReturnMessage> msg_result,const std::string & errmsg)61 void verify_error_message(base::Result<StorageReturnMessage> msg_result,
62 const std::string& errmsg) {
63 ASSERT_FALSE(msg_result.ok());
64 ASSERT_TRUE(msg_result.error().message().find(errmsg) != std::string::npos)
65 << msg_result.error().message();
66 }
67 }; // class AconfigdProtonColliderTest
68
69
TEST_F(AconfigdProtonColliderTest,ota_flag_staging)70 TEST_F(AconfigdProtonColliderTest, ota_flag_staging) {
71 auto a_mock = AconfigdMock();
72 auto request_msg = ota_flag_staging_message(
73 "mock_build_id",
74 {{"package_1", "flag_1", "true"},
75 {"package_2", "flag_1", "false"}});
76 auto return_msg = a_mock.SendRequestToSocket(request_msg);
77 verify_ota_staging_return_message(return_msg);
78 ASSERT_TRUE(FileExists(a_mock.flags_dir + "/ota.pb"));
79 auto pb = ReadPbFromFile<StorageRequestMessage::OTAFlagStagingMessage>(
80 a_mock.flags_dir + "/ota.pb");
81 ASSERT_TRUE(pb.ok());
82 ASSERT_EQ(pb->build_id(), "mock_build_id");
83 auto flags = pb->overrides();
84 ASSERT_EQ(flags.size(), 2);
85 auto flag = pb->overrides(0);
86 ASSERT_EQ(flag.package_name(), "package_1");
87 ASSERT_EQ(flag.flag_name(), "flag_1");
88 ASSERT_EQ(flag.flag_value(), "true");
89 flag = pb->overrides(1);
90 ASSERT_EQ(flag.package_name(), "package_2");
91 ASSERT_EQ(flag.flag_name(), "flag_1");
92 ASSERT_EQ(flag.flag_value(), "false");
93 }
94
TEST_F(AconfigdProtonColliderTest,ota_flag_unstaging)95 TEST_F(AconfigdProtonColliderTest, ota_flag_unstaging) {
96 // cerate mock aconfigd and initialize platform storage
97 auto a_mock = AconfigdMock();
98 auto init_result = a_mock.aconfigd.InitializePlatformStorage();
99 ASSERT_TRUE(init_result.ok()) << init_result.error();
100
101 auto flags_to_stage =
102 std::vector<std::tuple<std::string, std::string, std::string>>();
103
104 // for fake OTA flag overrides, flip all RW flag value
105 auto request_msg = list_container_storage_message("system");
106 auto return_msg = a_mock.SendRequestToSocket(request_msg);
107 ASSERT_TRUE(return_msg.ok()) << return_msg.error();
108 auto flags_msg = return_msg->list_storage_message();
109
110 for (auto const& flag : flags_msg.flags()) {
111 if (flag.is_readwrite()) {
112 flags_to_stage.push_back({
113 flag.package_name(),
114 flag.flag_name(),
115 flag.server_flag_value() == "true" ? "false" : "true"
116 });
117 }
118 }
119
120 // fake an OTA staging request, using current build id
121 auto build_id = base::GetProperty("ro.build.fingerprint", "");
122 request_msg = ota_flag_staging_message(build_id, flags_to_stage);
123 return_msg = a_mock.SendRequestToSocket(request_msg);
124 verify_ota_staging_return_message(return_msg);
125 ASSERT_TRUE(FileExists(a_mock.flags_dir + "/ota.pb"));
126
127 init_result = a_mock.aconfigd.InitializePlatformStorage();
128 ASSERT_TRUE(init_result.ok()) << init_result.error();
129 ASSERT_FALSE(FileExists(a_mock.flags_dir + "/ota.pb"));
130
131 // list container
132 request_msg = list_container_storage_message("system");
133 return_msg = a_mock.SendRequestToSocket(request_msg);
134 ASSERT_TRUE(return_msg.ok()) << return_msg.error();
135 flags_msg = return_msg->list_storage_message();
136
137 size_t i = 0;
138 for (auto const& flag : flags_msg.flags()) {
139 if (flag.is_readwrite()) {
140 ASSERT_EQ(flag.package_name(), std::get<0>(flags_to_stage[i]));
141 ASSERT_EQ(flag.flag_name(), std::get<1>(flags_to_stage[i]));
142 ASSERT_EQ(flag.server_flag_value(), std::get<2>(flags_to_stage[i]));
143 ++i;
144 }
145 }
146 }
147
TEST_F(AconfigdProtonColliderTest,ota_flag_unstaging_negative)148 TEST_F(AconfigdProtonColliderTest, ota_flag_unstaging_negative) {
149 // cerate mock aconfigd and initialize platform storage
150 auto a_mock = AconfigdMock();
151 auto init_result = a_mock.aconfigd.InitializePlatformStorage();
152 ASSERT_TRUE(init_result.ok()) << init_result.error();
153
154 // fake an OTA staging request, using fake build id
155 auto request_msg = ota_flag_staging_message(
156 "some_fake_build_id",
157 {{"abc", "def", "true"}});
158 auto return_msg = a_mock.SendRequestToSocket(request_msg);
159 verify_ota_staging_return_message(return_msg);
160 ASSERT_TRUE(FileExists(a_mock.flags_dir + "/ota.pb"));
161
162 init_result = a_mock.aconfigd.InitializePlatformStorage();
163 ASSERT_TRUE(init_result.ok()) << init_result.error();
164
165 // the ota overrides file should still exist
166 ASSERT_TRUE(FileExists(a_mock.flags_dir + "/ota.pb"));
167 }
168
169 } // namespace aconfigd
170 } // namespace android
171