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 #include <string>
18 #include <vector>
19 #include <cstdio>
20
21 #include <sys/stat.h>
22 #include "aconfig_storage/aconfig_storage_read_api.hpp"
23 #include "aconfig_storage/aconfig_storage_write_api.hpp"
24 #include <gtest/gtest.h>
25 #include <android-base/file.h>
26 #include <android-base/result.h>
27
28 using namespace android::base;
29
30 namespace api = aconfig_storage;
31 namespace private_api = aconfig_storage::private_internal_api;
32
33 class AconfigStorageTest : public ::testing::Test {
34 protected:
copy_to_rw_temp_file(std::string const & source_file)35 Result<std::string> copy_to_rw_temp_file(std::string const& source_file) {
36 auto temp_file = std::string(std::tmpnam(nullptr));
37 auto content = std::string();
38 if (!ReadFileToString(source_file, &content)) {
39 return Error() << "failed to read file: " << source_file;
40 }
41 if (!WriteStringToFile(content, temp_file)) {
42 return Error() << "failed to copy file: " << source_file;
43 }
44 if (chmod(temp_file.c_str(),
45 S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH) == -1) {
46 return Error() << "failed to chmod";
47 }
48 return temp_file;
49 }
50
SetUp()51 void SetUp() override {
52 auto const test_dir = android::base::GetExecutableDirectory();
53 flag_val = *copy_to_rw_temp_file(test_dir + "/flag.val");
54 flag_info = *copy_to_rw_temp_file(test_dir + "/flag.info");
55 }
56
TearDown()57 void TearDown() override {
58 std::remove(flag_val.c_str());
59 std::remove(flag_info.c_str());
60 }
61
62 std::string flag_val;
63 std::string flag_info;
64 };
65
66 /// Negative test to lock down the error when mapping a non writeable storage file
TEST_F(AconfigStorageTest,test_non_writable_storage_file_mapping)67 TEST_F(AconfigStorageTest, test_non_writable_storage_file_mapping) {
68 ASSERT_TRUE(chmod(flag_val.c_str(), S_IRUSR | S_IRGRP | S_IROTH) != -1);
69 auto mapped_file_result = api::map_mutable_storage_file(flag_val);
70 ASSERT_FALSE(mapped_file_result.ok());
71 auto it = mapped_file_result.error().message().find("cannot map nonwriteable file");
72 ASSERT_TRUE(it != std::string::npos) << mapped_file_result.error().message();
73 }
74
75 /// Test to lock down storage flag value update api
TEST_F(AconfigStorageTest,test_boolean_flag_value_update)76 TEST_F(AconfigStorageTest, test_boolean_flag_value_update) {
77 auto mapped_file_result = api::map_mutable_storage_file(flag_val);
78 ASSERT_TRUE(mapped_file_result.ok());
79 auto mapped_file = std::unique_ptr<api::MutableMappedStorageFile>(*mapped_file_result);
80
81 for (int offset = 0; offset < 8; ++offset) {
82 auto update_result = api::set_boolean_flag_value(*mapped_file, offset, true);
83 ASSERT_TRUE(update_result.ok());
84 auto value = api::get_boolean_flag_value(*mapped_file, offset);
85 ASSERT_TRUE(value.ok());
86 ASSERT_TRUE(*value);
87 }
88 }
89
90 /// Negative test to lock down the error when querying flag value out of range
TEST_F(AconfigStorageTest,test_invalid_boolean_flag_value_update)91 TEST_F(AconfigStorageTest, test_invalid_boolean_flag_value_update) {
92 auto mapped_file_result = api::map_mutable_storage_file(flag_val);
93 ASSERT_TRUE(mapped_file_result.ok());
94 auto mapped_file = std::unique_ptr<api::MutableMappedStorageFile>(*mapped_file_result);
95 auto update_result = api::set_boolean_flag_value(*mapped_file, 8, true);
96 ASSERT_FALSE(update_result.ok());
97 ASSERT_EQ(update_result.error().message(),
98 std::string("InvalidStorageFileOffset(Flag value offset goes beyond the end of the file.)"));
99 }
100
101 /// Test to lock down storage flag has server override update api
TEST_F(AconfigStorageTest,test_flag_has_server_override_update)102 TEST_F(AconfigStorageTest, test_flag_has_server_override_update) {
103 auto mapped_file_result = api::map_mutable_storage_file(flag_info);
104 ASSERT_TRUE(mapped_file_result.ok());
105 auto mapped_file = std::unique_ptr<api::MutableMappedStorageFile>(*mapped_file_result);
106
107 for (int offset = 0; offset < 8; ++offset) {
108 auto update_result = api::set_flag_has_server_override(
109 *mapped_file, api::FlagValueType::Boolean, offset, true);
110 ASSERT_TRUE(update_result.ok()) << update_result.error();
111 auto attribute = api::get_flag_attribute(
112 *mapped_file, api::FlagValueType::Boolean, offset);
113 ASSERT_TRUE(attribute.ok());
114 ASSERT_TRUE(*attribute & api::FlagInfoBit::HasServerOverride);
115
116 update_result = api::set_flag_has_server_override(
117 *mapped_file, api::FlagValueType::Boolean, offset, false);
118 ASSERT_TRUE(update_result.ok());
119 attribute = api::get_flag_attribute(
120 *mapped_file, api::FlagValueType::Boolean, offset);
121 ASSERT_TRUE(attribute.ok());
122 ASSERT_FALSE(*attribute & api::FlagInfoBit::HasServerOverride);
123 }
124 }
125
126 /// Test to lock down storage flag has local override update api
TEST_F(AconfigStorageTest,test_flag_has_local_override_update)127 TEST_F(AconfigStorageTest, test_flag_has_local_override_update) {
128 auto mapped_file_result = api::map_mutable_storage_file(flag_info);
129 ASSERT_TRUE(mapped_file_result.ok());
130 auto mapped_file = std::unique_ptr<api::MutableMappedStorageFile>(*mapped_file_result);
131
132 for (int offset = 0; offset < 8; ++offset) {
133 auto update_result = api::set_flag_has_local_override(
134 *mapped_file, api::FlagValueType::Boolean, offset, true);
135 ASSERT_TRUE(update_result.ok());
136 auto attribute = api::get_flag_attribute(
137 *mapped_file, api::FlagValueType::Boolean, offset);
138 ASSERT_TRUE(attribute.ok());
139 ASSERT_TRUE(*attribute & api::FlagInfoBit::HasLocalOverride);
140
141 update_result = api::set_flag_has_local_override(
142 *mapped_file, api::FlagValueType::Boolean, offset, false);
143 ASSERT_TRUE(update_result.ok());
144 attribute = api::get_flag_attribute(
145 *mapped_file, api::FlagValueType::Boolean, offset);
146 ASSERT_TRUE(attribute.ok());
147 ASSERT_FALSE(*attribute & api::FlagInfoBit::HasLocalOverride);
148 }
149 }
150