Merge "aconfig: update storage read api" into main am: 7b09e95c89
Original change: https://android-review.googlesource.com/c/platform/build/+/3096736 Change-Id: Id013800ce502c1eaed1e9669b25d94b24347de08 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -9,8 +9,6 @@ rust_defaults {
|
||||
srcs: ["src/lib.rs"],
|
||||
rustlibs: [
|
||||
"libanyhow",
|
||||
"libonce_cell",
|
||||
"libtempfile",
|
||||
"libmemmap2",
|
||||
"libcxx",
|
||||
"libthiserror",
|
||||
@@ -34,6 +32,9 @@ rust_test_host {
|
||||
name: "aconfig_storage_read_api.test",
|
||||
test_suites: ["general-tests"],
|
||||
defaults: ["aconfig_storage_read_api.defaults"],
|
||||
rustlibs: [
|
||||
"librand",
|
||||
],
|
||||
data: [
|
||||
"tests/package.map",
|
||||
"tests/flag.map",
|
||||
|
@@ -8,10 +8,9 @@ default = ["cargo"]
|
||||
cargo = []
|
||||
|
||||
[dependencies]
|
||||
rand = "0.8.5"
|
||||
anyhow = "1.0.69"
|
||||
memmap2 = "0.8.0"
|
||||
once_cell = "1.19.0"
|
||||
tempfile = "3.9.0"
|
||||
cxx = "1.0"
|
||||
thiserror = "1.0.56"
|
||||
aconfig_storage_file = { path = "../aconfig_storage_file" }
|
||||
|
@@ -42,9 +42,6 @@ pub mod flag_value_query;
|
||||
pub mod mapped_file;
|
||||
pub mod package_table_query;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_utils;
|
||||
|
||||
pub use aconfig_storage_file::{AconfigStorageError, FlagValueType, StorageFileType};
|
||||
pub use flag_table_query::FlagReadContext;
|
||||
pub use package_table_query::PackageReadContext;
|
||||
@@ -60,8 +57,8 @@ use memmap2::Mmap;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
|
||||
/// Storage file location pb file
|
||||
pub const STORAGE_LOCATION_FILE: &str = "/metadata/aconfig/boot/available_storage_file_records.pb";
|
||||
/// Storage file location
|
||||
pub const STORAGE_LOCATION: &str = "/metadata/aconfig";
|
||||
|
||||
/// Get read only mapped storage files.
|
||||
///
|
||||
@@ -78,7 +75,7 @@ pub unsafe fn get_mapped_storage_file(
|
||||
container: &str,
|
||||
file_type: StorageFileType,
|
||||
) -> Result<Mmap, AconfigStorageError> {
|
||||
unsafe { crate::mapped_file::get_mapped_file(STORAGE_LOCATION_FILE, container, file_type) }
|
||||
unsafe { crate::mapped_file::get_mapped_file(STORAGE_LOCATION, container, file_type) }
|
||||
}
|
||||
|
||||
/// Get package read context for a specific package.
|
||||
@@ -394,45 +391,41 @@ pub fn get_storage_file_version_cxx(file_path: &str) -> ffi::VersionNumberQueryC
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::mapped_file::get_mapped_file;
|
||||
use crate::test_utils::copy_to_temp_file;
|
||||
use aconfig_storage_file::protos::storage_record_pb::write_proto_to_temp_file;
|
||||
use aconfig_storage_file::{FlagInfoBit, StoredFlagType};
|
||||
use tempfile::NamedTempFile;
|
||||
use rand::Rng;
|
||||
use std::fs;
|
||||
|
||||
fn create_test_storage_files() -> [NamedTempFile; 5] {
|
||||
let package_map = copy_to_temp_file("./tests/package.map").unwrap();
|
||||
let flag_map = copy_to_temp_file("./tests/flag.map").unwrap();
|
||||
let flag_val = copy_to_temp_file("./tests/flag.val").unwrap();
|
||||
let flag_info = copy_to_temp_file("./tests/flag.info").unwrap();
|
||||
fn create_test_storage_files() -> String {
|
||||
let mut rng = rand::thread_rng();
|
||||
let number: u32 = rng.gen();
|
||||
let storage_dir = String::from("/tmp/") + &number.to_string();
|
||||
if std::fs::metadata(&storage_dir).is_ok() {
|
||||
fs::remove_dir_all(&storage_dir).unwrap();
|
||||
}
|
||||
let maps_dir = storage_dir.clone() + "/maps";
|
||||
let boot_dir = storage_dir.clone() + "/boot";
|
||||
fs::create_dir(&storage_dir).unwrap();
|
||||
fs::create_dir(&maps_dir).unwrap();
|
||||
fs::create_dir(&boot_dir).unwrap();
|
||||
|
||||
let text_proto = format!(
|
||||
r#"
|
||||
files {{
|
||||
version: 0
|
||||
container: "mockup"
|
||||
package_map: "{}"
|
||||
flag_map: "{}"
|
||||
flag_val: "{}"
|
||||
flag_info: "{}"
|
||||
timestamp: 12345
|
||||
}}
|
||||
"#,
|
||||
package_map.path().display(),
|
||||
flag_map.path().display(),
|
||||
flag_val.path().display(),
|
||||
flag_info.path().display()
|
||||
);
|
||||
let pb_file = write_proto_to_temp_file(&text_proto).unwrap();
|
||||
[package_map, flag_map, flag_val, flag_info, pb_file]
|
||||
let package_map = storage_dir.clone() + "/maps/mockup.package.map";
|
||||
let flag_map = storage_dir.clone() + "/maps/mockup.flag.map";
|
||||
let flag_val = storage_dir.clone() + "/boot/mockup.val";
|
||||
let flag_info = storage_dir.clone() + "/boot/mockup.info";
|
||||
fs::copy("./tests/package.map", &package_map).unwrap();
|
||||
fs::copy("./tests/flag.map", &flag_map).unwrap();
|
||||
fs::copy("./tests/flag.val", &flag_val).unwrap();
|
||||
fs::copy("./tests/flag.info", &flag_info).unwrap();
|
||||
|
||||
return storage_dir;
|
||||
}
|
||||
|
||||
#[test]
|
||||
// this test point locks down flag package read context query
|
||||
fn test_package_context_query() {
|
||||
let [_package_map, _flag_map, _flag_val, _flag_info, pb_file] = create_test_storage_files();
|
||||
let pb_file_path = pb_file.path().display().to_string();
|
||||
let storage_dir = create_test_storage_files();
|
||||
let package_mapped_file = unsafe {
|
||||
get_mapped_file(&pb_file_path, "mockup", StorageFileType::PackageMap).unwrap()
|
||||
get_mapped_file(&storage_dir, "mockup", StorageFileType::PackageMap).unwrap()
|
||||
};
|
||||
|
||||
let package_context =
|
||||
@@ -460,10 +453,9 @@ files {{
|
||||
#[test]
|
||||
// this test point locks down flag read context query
|
||||
fn test_flag_context_query() {
|
||||
let [_package_map, _flag_map, _flag_val, _flag_info, pb_file] = create_test_storage_files();
|
||||
let pb_file_path = pb_file.path().display().to_string();
|
||||
let storage_dir = create_test_storage_files();
|
||||
let flag_mapped_file =
|
||||
unsafe { get_mapped_file(&pb_file_path, "mockup", StorageFileType::FlagMap).unwrap() };
|
||||
unsafe { get_mapped_file(&storage_dir, "mockup", StorageFileType::FlagMap).unwrap() };
|
||||
|
||||
let baseline = vec![
|
||||
(0, "enabled_ro", StoredFlagType::ReadOnlyBoolean, 1u16),
|
||||
@@ -486,10 +478,9 @@ files {{
|
||||
#[test]
|
||||
// this test point locks down flag value query
|
||||
fn test_flag_value_query() {
|
||||
let [_package_map, _flag_map, _flag_val, _flag_info, pb_file] = create_test_storage_files();
|
||||
let pb_file_path = pb_file.path().display().to_string();
|
||||
let storage_dir = create_test_storage_files();
|
||||
let flag_value_file =
|
||||
unsafe { get_mapped_file(&pb_file_path, "mockup", StorageFileType::FlagVal).unwrap() };
|
||||
unsafe { get_mapped_file(&storage_dir, "mockup", StorageFileType::FlagVal).unwrap() };
|
||||
let baseline: Vec<bool> = vec![false, true, true, false, true, true, true, true];
|
||||
for (offset, expected_value) in baseline.into_iter().enumerate() {
|
||||
let flag_value = get_boolean_flag_value(&flag_value_file, offset as u32).unwrap();
|
||||
@@ -500,10 +491,9 @@ files {{
|
||||
#[test]
|
||||
// this test point locks donw flag info query
|
||||
fn test_flag_info_query() {
|
||||
let [_package_map, _flag_map, _flag_val, _flag_info, pb_file] = create_test_storage_files();
|
||||
let pb_file_path = pb_file.path().display().to_string();
|
||||
let storage_dir = create_test_storage_files();
|
||||
let flag_info_file =
|
||||
unsafe { get_mapped_file(&pb_file_path, "mockup", StorageFileType::FlagInfo).unwrap() };
|
||||
unsafe { get_mapped_file(&storage_dir, "mockup", StorageFileType::FlagInfo).unwrap() };
|
||||
let is_rw: Vec<bool> = vec![true, false, true, true, false, false, false, true];
|
||||
for (offset, expected_value) in is_rw.into_iter().enumerate() {
|
||||
let attribute =
|
||||
|
@@ -14,47 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::{BufReader, Read};
|
||||
|
||||
use anyhow::anyhow;
|
||||
use memmap2::Mmap;
|
||||
use std::fs::File;
|
||||
|
||||
use crate::AconfigStorageError::{
|
||||
self, FileReadFail, MapFileFail, ProtobufParseFail, StorageFileNotFound,
|
||||
};
|
||||
use crate::AconfigStorageError::{self, FileReadFail, MapFileFail, StorageFileNotFound};
|
||||
use crate::StorageFileType;
|
||||
use aconfig_storage_file::protos::{
|
||||
storage_record_pb::try_from_binary_proto, ProtoStorageFileInfo, ProtoStorageFiles,
|
||||
};
|
||||
|
||||
/// Find where storage files are stored for a particular container
|
||||
pub fn find_container_storage_location(
|
||||
location_pb_file: &str,
|
||||
container: &str,
|
||||
) -> Result<ProtoStorageFileInfo, AconfigStorageError> {
|
||||
let file = File::open(location_pb_file).map_err(|errmsg| {
|
||||
FileReadFail(anyhow!("Failed to open file {}: {}", location_pb_file, errmsg))
|
||||
})?;
|
||||
let mut reader = BufReader::new(file);
|
||||
let mut bytes = Vec::new();
|
||||
reader.read_to_end(&mut bytes).map_err(|errmsg| {
|
||||
FileReadFail(anyhow!("Failed to read file {}: {}", location_pb_file, errmsg))
|
||||
})?;
|
||||
let storage_locations: ProtoStorageFiles = try_from_binary_proto(&bytes).map_err(|errmsg| {
|
||||
ProtobufParseFail(anyhow!(
|
||||
"Failed to parse storage location pb file {}: {}",
|
||||
location_pb_file,
|
||||
errmsg
|
||||
))
|
||||
})?;
|
||||
for location_info in storage_locations.files.iter() {
|
||||
if location_info.container() == container {
|
||||
return Ok(location_info.clone());
|
||||
}
|
||||
}
|
||||
Err(StorageFileNotFound(anyhow!("Storage file does not exist for {}", container)))
|
||||
}
|
||||
|
||||
/// Get the read only memory mapping of a storage file
|
||||
///
|
||||
@@ -82,123 +47,70 @@ unsafe fn map_file(file_path: &str) -> Result<Mmap, AconfigStorageError> {
|
||||
/// file after being mapped. Ensure no writes can happen to this file while this
|
||||
/// mapping stays alive.
|
||||
pub unsafe fn get_mapped_file(
|
||||
location_pb_file: &str,
|
||||
storage_dir: &str,
|
||||
container: &str,
|
||||
file_type: StorageFileType,
|
||||
) -> Result<Mmap, AconfigStorageError> {
|
||||
let files_location = find_container_storage_location(location_pb_file, container)?;
|
||||
match file_type {
|
||||
StorageFileType::PackageMap => unsafe { map_file(files_location.package_map()) },
|
||||
StorageFileType::FlagMap => unsafe { map_file(files_location.flag_map()) },
|
||||
StorageFileType::FlagVal => unsafe { map_file(files_location.flag_val()) },
|
||||
StorageFileType::FlagInfo => unsafe { map_file(files_location.flag_info()) },
|
||||
let storage_file = match file_type {
|
||||
StorageFileType::PackageMap => {
|
||||
String::from(storage_dir) + "/maps/" + container + ".package.map"
|
||||
}
|
||||
StorageFileType::FlagMap => String::from(storage_dir) + "/maps/" + container + ".flag.map",
|
||||
StorageFileType::FlagVal => String::from(storage_dir) + "/boot/" + container + ".val",
|
||||
StorageFileType::FlagInfo => String::from(storage_dir) + "/boot/" + container + ".info",
|
||||
};
|
||||
if std::fs::metadata(&storage_file).is_err() {
|
||||
return Err(StorageFileNotFound(anyhow!("storage file {} does not exist", storage_file)));
|
||||
}
|
||||
unsafe { map_file(&storage_file) }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::test_utils::copy_to_temp_file;
|
||||
use aconfig_storage_file::protos::storage_record_pb::write_proto_to_temp_file;
|
||||
use tempfile::NamedTempFile;
|
||||
use rand::Rng;
|
||||
use std::fs;
|
||||
use std::io::Read;
|
||||
|
||||
#[test]
|
||||
fn test_find_storage_file_location() {
|
||||
let text_proto = r#"
|
||||
files {
|
||||
version: 0
|
||||
container: "system"
|
||||
package_map: "/system/etc/package.map"
|
||||
flag_map: "/system/etc/flag.map"
|
||||
flag_val: "/metadata/aconfig/system.val"
|
||||
timestamp: 12345
|
||||
}
|
||||
files {
|
||||
version: 1
|
||||
container: "product"
|
||||
package_map: "/product/etc/package.map"
|
||||
flag_map: "/product/etc/flag.map"
|
||||
flag_val: "/metadata/aconfig/product.val"
|
||||
timestamp: 54321
|
||||
}
|
||||
"#;
|
||||
let file = write_proto_to_temp_file(&text_proto).unwrap();
|
||||
let file_full_path = file.path().display().to_string();
|
||||
let file_info = find_container_storage_location(&file_full_path, "system").unwrap();
|
||||
assert_eq!(file_info.version(), 0);
|
||||
assert_eq!(file_info.container(), "system");
|
||||
assert_eq!(file_info.package_map(), "/system/etc/package.map");
|
||||
assert_eq!(file_info.flag_map(), "/system/etc/flag.map");
|
||||
assert_eq!(file_info.flag_val(), "/metadata/aconfig/system.val");
|
||||
assert_eq!(file_info.timestamp(), 12345);
|
||||
|
||||
let file_info = find_container_storage_location(&file_full_path, "product").unwrap();
|
||||
assert_eq!(file_info.version(), 1);
|
||||
assert_eq!(file_info.container(), "product");
|
||||
assert_eq!(file_info.package_map(), "/product/etc/package.map");
|
||||
assert_eq!(file_info.flag_map(), "/product/etc/flag.map");
|
||||
assert_eq!(file_info.flag_val(), "/metadata/aconfig/product.val");
|
||||
assert_eq!(file_info.timestamp(), 54321);
|
||||
|
||||
let err = find_container_storage_location(&file_full_path, "vendor").unwrap_err();
|
||||
assert_eq!(
|
||||
format!("{:?}", err),
|
||||
"StorageFileNotFound(Storage file does not exist for vendor)"
|
||||
);
|
||||
}
|
||||
|
||||
fn map_and_verify(location_pb_file: &str, file_type: StorageFileType, actual_file: &str) {
|
||||
fn map_and_verify(storage_dir: &str, file_type: StorageFileType, actual_file: &str) {
|
||||
let mut opened_file = File::open(actual_file).unwrap();
|
||||
let mut content = Vec::new();
|
||||
opened_file.read_to_end(&mut content).unwrap();
|
||||
|
||||
let mmaped_file =
|
||||
unsafe { get_mapped_file(location_pb_file, "system", file_type).unwrap() };
|
||||
let mmaped_file = unsafe { get_mapped_file(storage_dir, "mockup", file_type).unwrap() };
|
||||
assert_eq!(mmaped_file[..], content[..]);
|
||||
}
|
||||
|
||||
fn create_test_storage_files() -> [NamedTempFile; 4] {
|
||||
let package_map = copy_to_temp_file("./tests/package.map").unwrap();
|
||||
let flag_map = copy_to_temp_file("./tests/flag.map").unwrap();
|
||||
let flag_val = copy_to_temp_file("./tests/package.map").unwrap();
|
||||
fn create_test_storage_files() -> String {
|
||||
let mut rng = rand::thread_rng();
|
||||
let number: u32 = rng.gen();
|
||||
let storage_dir = String::from("/tmp/") + &number.to_string();
|
||||
if std::fs::metadata(&storage_dir).is_ok() {
|
||||
fs::remove_dir_all(&storage_dir).unwrap();
|
||||
}
|
||||
let maps_dir = storage_dir.clone() + "/maps";
|
||||
let boot_dir = storage_dir.clone() + "/boot";
|
||||
fs::create_dir(&storage_dir).unwrap();
|
||||
fs::create_dir(&maps_dir).unwrap();
|
||||
fs::create_dir(&boot_dir).unwrap();
|
||||
|
||||
let text_proto = format!(
|
||||
r#"
|
||||
files {{
|
||||
version: 0
|
||||
container: "system"
|
||||
package_map: "{}"
|
||||
flag_map: "{}"
|
||||
flag_val: "{}"
|
||||
timestamp: 12345
|
||||
}}
|
||||
"#,
|
||||
package_map.path().display(),
|
||||
flag_map.path().display(),
|
||||
flag_val.path().display()
|
||||
);
|
||||
let pb_file = write_proto_to_temp_file(&text_proto).unwrap();
|
||||
[package_map, flag_map, flag_val, pb_file]
|
||||
let package_map = storage_dir.clone() + "/maps/mockup.package.map";
|
||||
let flag_map = storage_dir.clone() + "/maps/mockup.flag.map";
|
||||
let flag_val = storage_dir.clone() + "/boot/mockup.val";
|
||||
let flag_info = storage_dir.clone() + "/boot/mockup.info";
|
||||
fs::copy("./tests/package.map", &package_map).unwrap();
|
||||
fs::copy("./tests/flag.map", &flag_map).unwrap();
|
||||
fs::copy("./tests/flag.val", &flag_val).unwrap();
|
||||
fs::copy("./tests/flag.info", &flag_info).unwrap();
|
||||
|
||||
return storage_dir;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mapped_file_contents() {
|
||||
let [package_map, flag_map, flag_val, pb_file] = create_test_storage_files();
|
||||
let pb_file_path = pb_file.path().display().to_string();
|
||||
map_and_verify(
|
||||
&pb_file_path,
|
||||
StorageFileType::PackageMap,
|
||||
&package_map.path().display().to_string(),
|
||||
);
|
||||
map_and_verify(
|
||||
&pb_file_path,
|
||||
StorageFileType::FlagMap,
|
||||
&flag_map.path().display().to_string(),
|
||||
);
|
||||
map_and_verify(
|
||||
&pb_file_path,
|
||||
StorageFileType::FlagVal,
|
||||
&flag_val.path().display().to_string(),
|
||||
);
|
||||
let storage_dir = create_test_storage_files();
|
||||
map_and_verify(&storage_dir, StorageFileType::PackageMap, "./tests/package.map");
|
||||
map_and_verify(&storage_dir, StorageFileType::FlagMap, "./tests/flag.map");
|
||||
map_and_verify(&storage_dir, StorageFileType::FlagVal, "./tests/flag.val");
|
||||
map_and_verify(&storage_dir, StorageFileType::FlagInfo, "./tests/flag.info");
|
||||
}
|
||||
}
|
||||
|
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.
|
||||
*/
|
||||
|
||||
use anyhow::Result;
|
||||
use std::fs;
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
/// Create temp file copy
|
||||
pub(crate) fn copy_to_temp_file(source_file: &str) -> Result<NamedTempFile> {
|
||||
let file = NamedTempFile::new()?;
|
||||
fs::copy(source_file, file.path())?;
|
||||
Ok(file)
|
||||
}
|
@@ -7,8 +7,7 @@ rust_test {
|
||||
"libanyhow",
|
||||
"libaconfig_storage_file",
|
||||
"libaconfig_storage_read_api",
|
||||
"libprotobuf",
|
||||
"libtempfile",
|
||||
"librand",
|
||||
],
|
||||
data: [
|
||||
"package.map",
|
||||
@@ -26,8 +25,6 @@ cc_test {
|
||||
],
|
||||
static_libs: [
|
||||
"libgmock",
|
||||
"libaconfig_storage_protos_cc",
|
||||
"libprotobuf-cpp-lite",
|
||||
"libaconfig_storage_read_api_cc",
|
||||
"libbase",
|
||||
"liblog",
|
||||
|
@@ -22,11 +22,9 @@
|
||||
#include <sys/stat.h>
|
||||
#include "aconfig_storage/aconfig_storage_read_api.hpp"
|
||||
#include <gtest/gtest.h>
|
||||
#include <protos/aconfig_storage_metadata.pb.h>
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/result.h>
|
||||
|
||||
using android::aconfig_storage_metadata::storage_files;
|
||||
using namespace android::base;
|
||||
|
||||
namespace api = aconfig_storage;
|
||||
@@ -34,49 +32,33 @@ namespace private_api = aconfig_storage::private_internal_api;
|
||||
|
||||
class AconfigStorageTest : public ::testing::Test {
|
||||
protected:
|
||||
Result<std::string> copy_to_temp_file(std::string const& source_file) {
|
||||
auto temp_file = std::string(std::tmpnam(nullptr));
|
||||
Result<void> copy_file(std::string const& src_file,
|
||||
std::string const& dst_file) {
|
||||
auto content = std::string();
|
||||
if (!ReadFileToString(source_file, &content)) {
|
||||
return Error() << "failed to read file: " << source_file;
|
||||
if (!ReadFileToString(src_file, &content)) {
|
||||
return Error() << "failed to read file: " << src_file;
|
||||
}
|
||||
if (!WriteStringToFile(content, temp_file)) {
|
||||
return Error() << "failed to copy file: " << source_file;
|
||||
if (!WriteStringToFile(content, dst_file)) {
|
||||
return Error() << "failed to copy file: " << dst_file;
|
||||
}
|
||||
return temp_file;
|
||||
}
|
||||
|
||||
Result<std::string> write_storage_location_pb_file(std::string const& package_map,
|
||||
std::string const& flag_map,
|
||||
std::string const& flag_val,
|
||||
std::string const& flag_info) {
|
||||
auto temp_file = std::tmpnam(nullptr);
|
||||
auto proto = storage_files();
|
||||
auto* info = proto.add_files();
|
||||
info->set_version(0);
|
||||
info->set_container("mockup");
|
||||
info->set_package_map(package_map);
|
||||
info->set_flag_map(flag_map);
|
||||
info->set_flag_val(flag_val);
|
||||
info->set_flag_info(flag_info);
|
||||
info->set_timestamp(12345);
|
||||
|
||||
auto content = std::string();
|
||||
proto.SerializeToString(&content);
|
||||
if (!WriteStringToFile(content, temp_file)) {
|
||||
return Error() << "failed to write storage records pb file";
|
||||
}
|
||||
return temp_file;
|
||||
return {};
|
||||
}
|
||||
|
||||
void SetUp() override {
|
||||
auto const test_dir = android::base::GetExecutableDirectory();
|
||||
package_map = *copy_to_temp_file(test_dir + "/package.map");
|
||||
flag_map = *copy_to_temp_file(test_dir + "/flag.map");
|
||||
flag_val = *copy_to_temp_file(test_dir + "/flag.val");
|
||||
flag_info = *copy_to_temp_file(test_dir + "/flag.info");
|
||||
storage_record_pb = *write_storage_location_pb_file(
|
||||
package_map, flag_map, flag_val, flag_info);
|
||||
storage_dir = std::string(root_dir.path);
|
||||
auto maps_dir = storage_dir + "/maps";
|
||||
auto boot_dir = storage_dir + "/boot";
|
||||
mkdir(maps_dir.c_str(), 0775);
|
||||
mkdir(boot_dir.c_str(), 0775);
|
||||
package_map = std::string(maps_dir) + "/mockup.package.map";
|
||||
flag_map = std::string(maps_dir) + "/mockup.flag.map";
|
||||
flag_val = std::string(boot_dir) + "/mockup.val";
|
||||
flag_info = std::string(boot_dir) + "/mockup.info";
|
||||
copy_file(test_dir + "/package.map", package_map);
|
||||
copy_file(test_dir + "/flag.map", flag_map);
|
||||
copy_file(test_dir + "/flag.val", flag_val);
|
||||
copy_file(test_dir + "/flag.info", flag_info);
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
@@ -84,14 +66,14 @@ class AconfigStorageTest : public ::testing::Test {
|
||||
std::remove(flag_map.c_str());
|
||||
std::remove(flag_val.c_str());
|
||||
std::remove(flag_info.c_str());
|
||||
std::remove(storage_record_pb.c_str());
|
||||
}
|
||||
|
||||
TemporaryDir root_dir;
|
||||
std::string storage_dir;
|
||||
std::string package_map;
|
||||
std::string flag_map;
|
||||
std::string flag_val;
|
||||
std::string flag_info;
|
||||
std::string storage_record_pb;
|
||||
};
|
||||
|
||||
/// Test to lock down storage file version query api
|
||||
@@ -113,16 +95,17 @@ TEST_F(AconfigStorageTest, test_storage_version_query) {
|
||||
/// Negative test to lock down the error when mapping none exist storage files
|
||||
TEST_F(AconfigStorageTest, test_none_exist_storage_file_mapping) {
|
||||
auto mapped_file_result = private_api::get_mapped_file_impl(
|
||||
storage_record_pb, "vendor", api::StorageFileType::package_map);
|
||||
storage_dir, "vendor", api::StorageFileType::package_map);
|
||||
ASSERT_FALSE(mapped_file_result.ok());
|
||||
ASSERT_EQ(mapped_file_result.error().message(),
|
||||
"Unable to find storage files for container vendor");
|
||||
std::string("failed to open ") + storage_dir
|
||||
+ "/maps/vendor.package.map: No such file or directory");
|
||||
}
|
||||
|
||||
/// Test to lock down storage package context query api
|
||||
TEST_F(AconfigStorageTest, test_package_context_query) {
|
||||
auto mapped_file_result = private_api::get_mapped_file_impl(
|
||||
storage_record_pb, "mockup", api::StorageFileType::package_map);
|
||||
storage_dir, "mockup", api::StorageFileType::package_map);
|
||||
ASSERT_TRUE(mapped_file_result.ok());
|
||||
auto mapped_file = std::unique_ptr<api::MappedStorageFile>(*mapped_file_result);
|
||||
|
||||
@@ -151,7 +134,7 @@ TEST_F(AconfigStorageTest, test_package_context_query) {
|
||||
/// Test to lock down when querying none exist package
|
||||
TEST_F(AconfigStorageTest, test_none_existent_package_context_query) {
|
||||
auto mapped_file_result = private_api::get_mapped_file_impl(
|
||||
storage_record_pb, "mockup", api::StorageFileType::package_map);
|
||||
storage_dir, "mockup", api::StorageFileType::package_map);
|
||||
ASSERT_TRUE(mapped_file_result.ok());
|
||||
auto mapped_file = std::unique_ptr<api::MappedStorageFile>(*mapped_file_result);
|
||||
|
||||
@@ -164,7 +147,7 @@ TEST_F(AconfigStorageTest, test_none_existent_package_context_query) {
|
||||
/// Test to lock down storage flag context query api
|
||||
TEST_F(AconfigStorageTest, test_flag_context_query) {
|
||||
auto mapped_file_result = private_api::get_mapped_file_impl(
|
||||
storage_record_pb, "mockup", api::StorageFileType::flag_map);
|
||||
storage_dir, "mockup", api::StorageFileType::flag_map);
|
||||
ASSERT_TRUE(mapped_file_result.ok());
|
||||
auto mapped_file = std::unique_ptr<api::MappedStorageFile>(*mapped_file_result);
|
||||
|
||||
@@ -190,7 +173,7 @@ TEST_F(AconfigStorageTest, test_flag_context_query) {
|
||||
/// Test to lock down when querying none exist flag
|
||||
TEST_F(AconfigStorageTest, test_none_existent_flag_context_query) {
|
||||
auto mapped_file_result = private_api::get_mapped_file_impl(
|
||||
storage_record_pb, "mockup", api::StorageFileType::flag_map);
|
||||
storage_dir, "mockup", api::StorageFileType::flag_map);
|
||||
ASSERT_TRUE(mapped_file_result.ok());
|
||||
auto mapped_file = std::unique_ptr<api::MappedStorageFile>(*mapped_file_result);
|
||||
|
||||
@@ -206,7 +189,7 @@ TEST_F(AconfigStorageTest, test_none_existent_flag_context_query) {
|
||||
/// Test to lock down storage flag value query api
|
||||
TEST_F(AconfigStorageTest, test_boolean_flag_value_query) {
|
||||
auto mapped_file_result = private_api::get_mapped_file_impl(
|
||||
storage_record_pb, "mockup", api::StorageFileType::flag_val);
|
||||
storage_dir, "mockup", api::StorageFileType::flag_val);
|
||||
ASSERT_TRUE(mapped_file_result.ok());
|
||||
auto mapped_file = std::unique_ptr<api::MappedStorageFile>(*mapped_file_result);
|
||||
|
||||
@@ -222,7 +205,7 @@ TEST_F(AconfigStorageTest, test_boolean_flag_value_query) {
|
||||
/// Negative test to lock down the error when querying flag value out of range
|
||||
TEST_F(AconfigStorageTest, test_invalid_boolean_flag_value_query) {
|
||||
auto mapped_file_result = private_api::get_mapped_file_impl(
|
||||
storage_record_pb, "mockup", api::StorageFileType::flag_val);
|
||||
storage_dir, "mockup", api::StorageFileType::flag_val);
|
||||
ASSERT_TRUE(mapped_file_result.ok());
|
||||
auto mapped_file = std::unique_ptr<api::MappedStorageFile>(*mapped_file_result);
|
||||
|
||||
@@ -235,7 +218,7 @@ TEST_F(AconfigStorageTest, test_invalid_boolean_flag_value_query) {
|
||||
/// Test to lock down storage flag info query api
|
||||
TEST_F(AconfigStorageTest, test_boolean_flag_info_query) {
|
||||
auto mapped_file_result = private_api::get_mapped_file_impl(
|
||||
storage_record_pb, "mockup", api::StorageFileType::flag_info);
|
||||
storage_dir, "mockup", api::StorageFileType::flag_info);
|
||||
ASSERT_TRUE(mapped_file_result.ok());
|
||||
auto mapped_file = std::unique_ptr<api::MappedStorageFile>(*mapped_file_result);
|
||||
|
||||
@@ -254,7 +237,7 @@ TEST_F(AconfigStorageTest, test_boolean_flag_info_query) {
|
||||
/// Negative test to lock down the error when querying flag info out of range
|
||||
TEST_F(AconfigStorageTest, test_invalid_boolean_flag_info_query) {
|
||||
auto mapped_file_result = private_api::get_mapped_file_impl(
|
||||
storage_record_pb, "mockup", api::StorageFileType::flag_info);
|
||||
storage_dir, "mockup", api::StorageFileType::flag_info);
|
||||
ASSERT_TRUE(mapped_file_result.ok());
|
||||
auto mapped_file = std::unique_ptr<api::MappedStorageFile>(*mapped_file_result);
|
||||
|
||||
|
@@ -1,71 +1,63 @@
|
||||
#[cfg(not(feature = "cargo"))]
|
||||
mod aconfig_storage_rust_test {
|
||||
use aconfig_storage_file::protos::storage_record_pb::write_proto_to_temp_file;
|
||||
use aconfig_storage_file::{FlagInfoBit, FlagValueType, StorageFileType, StoredFlagType};
|
||||
use aconfig_storage_read_api::{
|
||||
get_boolean_flag_value, get_flag_attribute, get_flag_read_context,
|
||||
get_package_read_context, get_storage_file_version, mapped_file::get_mapped_file,
|
||||
PackageReadContext,
|
||||
};
|
||||
use rand::Rng;
|
||||
use std::fs;
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
pub fn copy_to_temp_file(source_file: &str) -> NamedTempFile {
|
||||
let file = NamedTempFile::new().unwrap();
|
||||
fs::copy(source_file, file.path()).unwrap();
|
||||
file
|
||||
}
|
||||
fn create_test_storage_files() -> String {
|
||||
let mut rng = rand::thread_rng();
|
||||
let number: u32 = rng.gen();
|
||||
let storage_dir = String::from("/tmp/") + &number.to_string();
|
||||
if std::fs::metadata(&storage_dir).is_ok() {
|
||||
fs::remove_dir_all(&storage_dir).unwrap();
|
||||
}
|
||||
let maps_dir = storage_dir.clone() + "/maps";
|
||||
let boot_dir = storage_dir.clone() + "/boot";
|
||||
fs::create_dir(&storage_dir).unwrap();
|
||||
fs::create_dir(maps_dir).unwrap();
|
||||
fs::create_dir(boot_dir).unwrap();
|
||||
|
||||
fn create_test_storage_files() -> [NamedTempFile; 5] {
|
||||
let package_map = copy_to_temp_file("./package.map");
|
||||
let flag_map = copy_to_temp_file("./flag.map");
|
||||
let flag_val = copy_to_temp_file("./flag.val");
|
||||
let flag_info = copy_to_temp_file("./flag.info");
|
||||
let package_map = storage_dir.clone() + "/maps/mockup.package.map";
|
||||
let flag_map = storage_dir.clone() + "/maps/mockup.flag.map";
|
||||
let flag_val = storage_dir.clone() + "/boot/mockup.val";
|
||||
let flag_info = storage_dir.clone() + "/boot/mockup.info";
|
||||
fs::copy("./package.map", package_map).unwrap();
|
||||
fs::copy("./flag.map", flag_map).unwrap();
|
||||
fs::copy("./flag.val", flag_val).unwrap();
|
||||
fs::copy("./flag.info", flag_info).unwrap();
|
||||
|
||||
let text_proto = format!(
|
||||
r#"
|
||||
files {{
|
||||
version: 0
|
||||
container: "mockup"
|
||||
package_map: "{}"
|
||||
flag_map: "{}"
|
||||
flag_val: "{}"
|
||||
flag_info: "{}"
|
||||
timestamp: 12345
|
||||
}}
|
||||
"#,
|
||||
package_map.path().display(),
|
||||
flag_map.path().display(),
|
||||
flag_val.path().display(),
|
||||
flag_info.path().display()
|
||||
);
|
||||
let pb_file = write_proto_to_temp_file(&text_proto).unwrap();
|
||||
[package_map, flag_map, flag_val, flag_info, pb_file]
|
||||
storage_dir
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_unavailable_stoarge() {
|
||||
let [_package_map, _flag_map, _flag_val, _flag_info, pb_file] = create_test_storage_files();
|
||||
let pb_file_path = pb_file.path().display().to_string();
|
||||
let storage_dir = create_test_storage_files();
|
||||
// SAFETY:
|
||||
// The safety here is ensured as the test process will not write to temp storage file
|
||||
let err = unsafe {
|
||||
get_mapped_file(&pb_file_path, "vendor", StorageFileType::PackageMap).unwrap_err()
|
||||
get_mapped_file(&storage_dir, "vendor", StorageFileType::PackageMap).unwrap_err()
|
||||
};
|
||||
assert_eq!(
|
||||
format!("{:?}", err),
|
||||
"StorageFileNotFound(Storage file does not exist for vendor)"
|
||||
format!(
|
||||
"StorageFileNotFound(storage file {}/maps/vendor.package.map does not exist)",
|
||||
storage_dir
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_package_context_query() {
|
||||
let [_package_map, _flag_map, _flag_val, _flag_info, pb_file] = create_test_storage_files();
|
||||
let pb_file_path = pb_file.path().display().to_string();
|
||||
let storage_dir = create_test_storage_files();
|
||||
// SAFETY:
|
||||
// The safety here is ensured as the test process will not write to temp storage file
|
||||
let package_mapped_file = unsafe {
|
||||
get_mapped_file(&pb_file_path, "mockup", StorageFileType::PackageMap).unwrap()
|
||||
get_mapped_file(&storage_dir, "mockup", StorageFileType::PackageMap).unwrap()
|
||||
};
|
||||
|
||||
let package_context =
|
||||
@@ -92,12 +84,11 @@ files {{
|
||||
|
||||
#[test]
|
||||
fn test_none_exist_package_context_query() {
|
||||
let [_package_map, _flag_map, _flag_val, _flag_info, pb_file] = create_test_storage_files();
|
||||
let pb_file_path = pb_file.path().display().to_string();
|
||||
let storage_dir = create_test_storage_files();
|
||||
// SAFETY:
|
||||
// The safety here is ensured as the test process will not write to temp storage file
|
||||
let package_mapped_file = unsafe {
|
||||
get_mapped_file(&pb_file_path, "mockup", StorageFileType::PackageMap).unwrap()
|
||||
get_mapped_file(&storage_dir, "mockup", StorageFileType::PackageMap).unwrap()
|
||||
};
|
||||
|
||||
let package_context_option =
|
||||
@@ -108,12 +99,11 @@ files {{
|
||||
|
||||
#[test]
|
||||
fn test_flag_context_query() {
|
||||
let [_package_map, _flag_map, _flag_val, _flag_info, pb_file] = create_test_storage_files();
|
||||
let pb_file_path = pb_file.path().display().to_string();
|
||||
let storage_dir = create_test_storage_files();
|
||||
// SAFETY:
|
||||
// The safety here is ensured as the test process will not write to temp storage file
|
||||
let flag_mapped_file =
|
||||
unsafe { get_mapped_file(&pb_file_path, "mockup", StorageFileType::FlagMap).unwrap() };
|
||||
unsafe { get_mapped_file(&storage_dir, "mockup", StorageFileType::FlagMap).unwrap() };
|
||||
|
||||
let baseline = vec![
|
||||
(0, "enabled_ro", StoredFlagType::ReadOnlyBoolean, 1u16),
|
||||
@@ -135,12 +125,11 @@ files {{
|
||||
|
||||
#[test]
|
||||
fn test_none_exist_flag_context_query() {
|
||||
let [_package_map, _flag_map, _flag_val, _flag_info, pb_file] = create_test_storage_files();
|
||||
let pb_file_path = pb_file.path().display().to_string();
|
||||
let storage_dir = create_test_storage_files();
|
||||
// SAFETY:
|
||||
// The safety here is ensured as the test process will not write to temp storage file
|
||||
let flag_mapped_file =
|
||||
unsafe { get_mapped_file(&pb_file_path, "mockup", StorageFileType::FlagMap).unwrap() };
|
||||
unsafe { get_mapped_file(&storage_dir, "mockup", StorageFileType::FlagMap).unwrap() };
|
||||
let flag_context_option =
|
||||
get_flag_read_context(&flag_mapped_file, 0, "none_exist").unwrap();
|
||||
assert_eq!(flag_context_option, None);
|
||||
@@ -152,12 +141,11 @@ files {{
|
||||
|
||||
#[test]
|
||||
fn test_boolean_flag_value_query() {
|
||||
let [_package_map, _flag_map, _flag_val, _flag_info, pb_file] = create_test_storage_files();
|
||||
let pb_file_path = pb_file.path().display().to_string();
|
||||
let storage_dir = create_test_storage_files();
|
||||
// SAFETY:
|
||||
// The safety here is ensured as the test process will not write to temp storage file
|
||||
let flag_value_file =
|
||||
unsafe { get_mapped_file(&pb_file_path, "mockup", StorageFileType::FlagVal).unwrap() };
|
||||
unsafe { get_mapped_file(&storage_dir, "mockup", StorageFileType::FlagVal).unwrap() };
|
||||
let baseline: Vec<bool> = vec![false, true, true, false, true, true, true, true];
|
||||
for (offset, expected_value) in baseline.into_iter().enumerate() {
|
||||
let flag_value = get_boolean_flag_value(&flag_value_file, offset as u32).unwrap();
|
||||
@@ -167,12 +155,11 @@ files {{
|
||||
|
||||
#[test]
|
||||
fn test_invalid_boolean_flag_value_query() {
|
||||
let [_package_map, _flag_map, _flag_val, _flag_info, pb_file] = create_test_storage_files();
|
||||
let pb_file_path = pb_file.path().display().to_string();
|
||||
let storage_dir = create_test_storage_files();
|
||||
// SAFETY:
|
||||
// The safety here is ensured as the test process will not write to temp storage file
|
||||
let flag_value_file =
|
||||
unsafe { get_mapped_file(&pb_file_path, "mockup", StorageFileType::FlagVal).unwrap() };
|
||||
unsafe { get_mapped_file(&storage_dir, "mockup", StorageFileType::FlagVal).unwrap() };
|
||||
let err = get_boolean_flag_value(&flag_value_file, 8u32).unwrap_err();
|
||||
assert_eq!(
|
||||
format!("{:?}", err),
|
||||
@@ -182,12 +169,11 @@ files {{
|
||||
|
||||
#[test]
|
||||
fn test_flag_info_query() {
|
||||
let [_package_map, _flag_map, _flag_val, _flag_info, pb_file] = create_test_storage_files();
|
||||
let pb_file_path = pb_file.path().display().to_string();
|
||||
let storage_dir = create_test_storage_files();
|
||||
// SAFETY:
|
||||
// The safety here is ensured as the test process will not write to temp storage file
|
||||
let flag_info_file =
|
||||
unsafe { get_mapped_file(&pb_file_path, "mockup", StorageFileType::FlagInfo).unwrap() };
|
||||
unsafe { get_mapped_file(&storage_dir, "mockup", StorageFileType::FlagInfo).unwrap() };
|
||||
let is_rw: Vec<bool> = vec![true, false, true, true, false, false, false, true];
|
||||
for (offset, expected_value) in is_rw.into_iter().enumerate() {
|
||||
let attribute =
|
||||
@@ -200,12 +186,11 @@ files {{
|
||||
|
||||
#[test]
|
||||
fn test_invalid_boolean_flag_info_query() {
|
||||
let [_package_map, _flag_map, _flag_val, _flag_info, pb_file] = create_test_storage_files();
|
||||
let pb_file_path = pb_file.path().display().to_string();
|
||||
let storage_dir = create_test_storage_files();
|
||||
// SAFETY:
|
||||
// The safety here is ensured as the test process will not write to temp storage file
|
||||
let flag_info_file =
|
||||
unsafe { get_mapped_file(&pb_file_path, "mockup", StorageFileType::FlagInfo).unwrap() };
|
||||
unsafe { get_mapped_file(&storage_dir, "mockup", StorageFileType::FlagInfo).unwrap() };
|
||||
let err = get_flag_attribute(&flag_info_file, FlagValueType::Boolean, 8u32).unwrap_err();
|
||||
assert_eq!(
|
||||
format!("{:?}", err),
|
||||
|
@@ -77,7 +77,6 @@ cc_library_static {
|
||||
export_include_dirs: ["include"],
|
||||
static_libs: [
|
||||
"libaconfig_storage_read_api_cc",
|
||||
"libaconfig_storage_protos_cc",
|
||||
"libprotobuf-cpp-lite",
|
||||
"libbase",
|
||||
],
|
||||
|
@@ -13,7 +13,6 @@ cxx = "1.0"
|
||||
memmap2 = "0.8.0"
|
||||
tempfile = "3.9.0"
|
||||
thiserror = "1.0.56"
|
||||
protobuf = "3.2.0"
|
||||
aconfig_storage_file = { path = "../aconfig_storage_file" }
|
||||
aconfig_storage_read_api = { path = "../aconfig_storage_read_api" }
|
||||
|
||||
|
@@ -1,7 +1,6 @@
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <protos/aconfig_storage_metadata.pb.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -11,8 +10,6 @@
|
||||
#include "aconfig_storage/lib.rs.h"
|
||||
#include "aconfig_storage/aconfig_storage_write_api.hpp"
|
||||
|
||||
using storage_records_pb = android::aconfig_storage_metadata::storage_files;
|
||||
using storage_record_pb = android::aconfig_storage_metadata::storage_file_info;
|
||||
using namespace android::base;
|
||||
|
||||
namespace aconfig_storage {
|
||||
|
@@ -25,8 +25,6 @@ cc_test {
|
||||
],
|
||||
static_libs: [
|
||||
"libgmock",
|
||||
"libaconfig_storage_protos_cc",
|
||||
"libprotobuf-cpp-lite",
|
||||
"libaconfig_storage_read_api_cc",
|
||||
"libaconfig_storage_write_api_cc",
|
||||
"libbase",
|
||||
|
@@ -22,11 +22,9 @@
|
||||
#include "aconfig_storage/aconfig_storage_read_api.hpp"
|
||||
#include "aconfig_storage/aconfig_storage_write_api.hpp"
|
||||
#include <gtest/gtest.h>
|
||||
#include <protos/aconfig_storage_metadata.pb.h>
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/result.h>
|
||||
|
||||
using android::aconfig_storage_metadata::storage_files;
|
||||
using namespace android::base;
|
||||
|
||||
namespace api = aconfig_storage;
|
||||
|
Reference in New Issue
Block a user