aboutsummaryrefslogtreecommitdiff
path: root/tools/aconfig/aconfig_storage_read_api/src/flag_info_query.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tools/aconfig/aconfig_storage_read_api/src/flag_info_query.rs')
-rw-r--r--tools/aconfig/aconfig_storage_read_api/src/flag_info_query.rs123
1 files changed, 123 insertions, 0 deletions
diff --git a/tools/aconfig/aconfig_storage_read_api/src/flag_info_query.rs b/tools/aconfig/aconfig_storage_read_api/src/flag_info_query.rs
new file mode 100644
index 0000000000..6d03377683
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/src/flag_info_query.rs
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! flag value query module defines the flag value file read from mapped bytes
+
+use crate::{AconfigStorageError, FILE_VERSION};
+use aconfig_storage_file::{flag_info::FlagInfoHeader, read_u8_from_bytes, FlagValueType};
+use anyhow::anyhow;
+
+/// Get flag attribute bitfield
+pub fn find_flag_attribute(
+ buf: &[u8],
+ flag_type: FlagValueType,
+ flag_index: u32,
+) -> Result<u8, AconfigStorageError> {
+ let interpreted_header = FlagInfoHeader::from_bytes(buf)?;
+ if interpreted_header.version > crate::FILE_VERSION {
+ return Err(AconfigStorageError::HigherStorageFileVersion(anyhow!(
+ "Cannot read storage file with a higher version of {} with lib version {}",
+ interpreted_header.version,
+ FILE_VERSION
+ )));
+ }
+
+ // get byte offset to the flag info
+ let mut head = match flag_type {
+ FlagValueType::Boolean => (interpreted_header.boolean_flag_offset + flag_index) as usize,
+ };
+
+ if head >= interpreted_header.file_size as usize {
+ return Err(AconfigStorageError::InvalidStorageFileOffset(anyhow!(
+ "Flag info offset goes beyond the end of the file."
+ )));
+ }
+
+ let val = read_u8_from_bytes(buf, &mut head)?;
+ Ok(val)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use aconfig_storage_file::{test_utils::create_test_flag_info_list, FlagInfoBit};
+
+ #[test]
+ // this test point locks down query if flag has server override
+ fn test_is_flag_sticky() {
+ let flag_info_list = create_test_flag_info_list().into_bytes();
+ for offset in 0..8 {
+ let attribute =
+ find_flag_attribute(&flag_info_list[..], FlagValueType::Boolean, offset).unwrap();
+ assert_eq!((attribute & FlagInfoBit::HasServerOverride as u8) != 0u8, false);
+ }
+ }
+
+ #[test]
+ // this test point locks down query if flag is readwrite
+ fn test_is_flag_readwrite() {
+ let flag_info_list = create_test_flag_info_list().into_bytes();
+ let baseline: Vec<bool> = vec![true, false, true, true, false, false, false, true];
+ for offset in 0..8 {
+ let attribute =
+ find_flag_attribute(&flag_info_list[..], FlagValueType::Boolean, offset).unwrap();
+ assert_eq!(
+ (attribute & FlagInfoBit::IsReadWrite as u8) != 0u8,
+ baseline[offset as usize]
+ );
+ }
+ }
+
+ #[test]
+ // this test point locks down query if flag has local override
+ fn test_flag_has_override() {
+ let flag_info_list = create_test_flag_info_list().into_bytes();
+ for offset in 0..8 {
+ let attribute =
+ find_flag_attribute(&flag_info_list[..], FlagValueType::Boolean, offset).unwrap();
+ assert_eq!((attribute & FlagInfoBit::HasLocalOverride as u8) != 0u8, false);
+ }
+ }
+
+ #[test]
+ // this test point locks down query beyond the end of boolean section
+ fn test_boolean_out_of_range() {
+ let flag_info_list = create_test_flag_info_list().into_bytes();
+ let error =
+ find_flag_attribute(&flag_info_list[..], FlagValueType::Boolean, 8).unwrap_err();
+ assert_eq!(
+ format!("{:?}", error),
+ "InvalidStorageFileOffset(Flag info offset goes beyond the end of the file.)"
+ );
+ }
+
+ #[test]
+ // this test point locks down query error when file has a higher version
+ fn test_higher_version_storage_file() {
+ let mut info_list = create_test_flag_info_list();
+ info_list.header.version = crate::FILE_VERSION + 1;
+ let flag_info = info_list.into_bytes();
+ let error = find_flag_attribute(&flag_info[..], FlagValueType::Boolean, 4).unwrap_err();
+ assert_eq!(
+ format!("{:?}", error),
+ format!(
+ "HigherStorageFileVersion(Cannot read storage file with a higher version of {} with lib version {})",
+ crate::FILE_VERSION + 1,
+ crate::FILE_VERSION
+ )
+ );
+ }
+}