Merge "aconfig: move create flag info file api to aconfig_storage_write_api" into main am: acfb82cf73
Original change: https://android-review.googlesource.com/c/platform/build/+/3028943 Change-Id: I8d3b6f758ec3740928fc379d781a4e721c85a72e Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -12,7 +12,6 @@ rust_defaults {
|
|||||||
"libtempfile",
|
"libtempfile",
|
||||||
"libprotobuf",
|
"libprotobuf",
|
||||||
"libclap",
|
"libclap",
|
||||||
"libcxx",
|
|
||||||
"libaconfig_storage_protos",
|
"libaconfig_storage_protos",
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
@@ -70,46 +69,3 @@ cc_library_static {
|
|||||||
],
|
],
|
||||||
host_supported: true,
|
host_supported: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
// cxx source codegen from rust api
|
|
||||||
genrule {
|
|
||||||
name: "libcxx_aconfig_storage_file_bridge_code",
|
|
||||||
tools: ["cxxbridge"],
|
|
||||||
cmd: "$(location cxxbridge) $(in) > $(out)",
|
|
||||||
srcs: ["src/lib.rs"],
|
|
||||||
out: ["aconfig_storage/lib.rs.cc"],
|
|
||||||
}
|
|
||||||
|
|
||||||
// cxx header codegen from rust api
|
|
||||||
genrule {
|
|
||||||
name: "libcxx_aconfig_storage_file_bridge_header",
|
|
||||||
tools: ["cxxbridge"],
|
|
||||||
cmd: "$(location cxxbridge) $(in) --header > $(out)",
|
|
||||||
srcs: ["src/lib.rs"],
|
|
||||||
out: ["aconfig_storage/lib.rs.h"],
|
|
||||||
}
|
|
||||||
|
|
||||||
// a static cc lib based on generated code
|
|
||||||
rust_ffi_static {
|
|
||||||
name: "libaconfig_storage_file_cxx_bridge",
|
|
||||||
crate_name: "aconfig_storage_file_cxx_bridge",
|
|
||||||
host_supported: true,
|
|
||||||
srcs: ["src/lib.rs"],
|
|
||||||
defaults: ["aconfig_storage_file.defaults"],
|
|
||||||
}
|
|
||||||
|
|
||||||
// flag storage file cc interface
|
|
||||||
cc_library_static {
|
|
||||||
name: "libaconfig_storage_file_cc",
|
|
||||||
srcs: ["aconfig_storage_file.cpp"],
|
|
||||||
generated_headers: [
|
|
||||||
"cxx-bridge-header",
|
|
||||||
"libcxx_aconfig_storage_file_bridge_header",
|
|
||||||
],
|
|
||||||
generated_sources: ["libcxx_aconfig_storage_file_bridge_code"],
|
|
||||||
whole_static_libs: ["libaconfig_storage_file_cxx_bridge"],
|
|
||||||
export_include_dirs: ["include"],
|
|
||||||
static_libs: [
|
|
||||||
"libbase",
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
@@ -12,7 +12,6 @@ anyhow = "1.0.69"
|
|||||||
protobuf = "3.2.0"
|
protobuf = "3.2.0"
|
||||||
tempfile = "3.9.0"
|
tempfile = "3.9.0"
|
||||||
thiserror = "1.0.56"
|
thiserror = "1.0.56"
|
||||||
cxx = "1.0"
|
|
||||||
clap = { version = "4.1.8", features = ["derive"] }
|
clap = { version = "4.1.8", features = ["derive"] }
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
|
@@ -1,20 +0,0 @@
|
|||||||
#include "rust/cxx.h"
|
|
||||||
#include "aconfig_storage/lib.rs.h"
|
|
||||||
#include "aconfig_storage/aconfig_storage_file.hpp"
|
|
||||||
|
|
||||||
namespace aconfig_storage {
|
|
||||||
android::base::Result<void> create_flag_info(
|
|
||||||
std::string const& package_map,
|
|
||||||
std::string const& flag_map,
|
|
||||||
std::string const& flag_info_out) {
|
|
||||||
auto creation_cxx = create_flag_info_cxx(
|
|
||||||
rust::Str(package_map.c_str()),
|
|
||||||
rust::Str(flag_map.c_str()),
|
|
||||||
rust::Str(flag_info_out.c_str()));
|
|
||||||
if (creation_cxx.success) {
|
|
||||||
return {};
|
|
||||||
} else {
|
|
||||||
return android::base::Error() << creation_cxx.error_message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // namespace aconfig_storage
|
|
@@ -14,7 +14,4 @@ fn main() {
|
|||||||
.inputs(proto_files)
|
.inputs(proto_files)
|
||||||
.cargo_out_dir("aconfig_storage_protos")
|
.cargo_out_dir("aconfig_storage_protos")
|
||||||
.run_from_script();
|
.run_from_script();
|
||||||
|
|
||||||
let _ = cxx_build::bridge("src/lib.rs");
|
|
||||||
println!("cargo:rerun-if-changed=src/lib.rs");
|
|
||||||
}
|
}
|
||||||
|
@@ -1,16 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string>
|
|
||||||
#include <android-base/result.h>
|
|
||||||
|
|
||||||
namespace aconfig_storage {
|
|
||||||
/// Create flag info file based on package and flag map
|
|
||||||
/// \input package_map: package map file
|
|
||||||
/// \input flag_map: flag map file
|
|
||||||
/// \input flag_info_out: flag info file to be created
|
|
||||||
android::base::Result<void> create_flag_info(
|
|
||||||
std::string const& package_map,
|
|
||||||
std::string const& flag_map,
|
|
||||||
std::string const& flag_info_out);
|
|
||||||
} // namespace aconfig_storage
|
|
@@ -44,16 +44,14 @@ use std::cmp::Ordering;
|
|||||||
use std::collections::hash_map::DefaultHasher;
|
use std::collections::hash_map::DefaultHasher;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::io::{Read, Write};
|
use std::io::Read;
|
||||||
|
|
||||||
pub use crate::flag_info::{FlagInfoHeader, FlagInfoList, FlagInfoNode};
|
pub use crate::flag_info::{FlagInfoHeader, FlagInfoList, FlagInfoNode};
|
||||||
pub use crate::flag_table::{FlagTable, FlagTableHeader, FlagTableNode};
|
pub use crate::flag_table::{FlagTable, FlagTableHeader, FlagTableNode};
|
||||||
pub use crate::flag_value::{FlagValueHeader, FlagValueList};
|
pub use crate::flag_value::{FlagValueHeader, FlagValueList};
|
||||||
pub use crate::package_table::{PackageTable, PackageTableHeader, PackageTableNode};
|
pub use crate::package_table::{PackageTable, PackageTableHeader, PackageTableNode};
|
||||||
|
|
||||||
use crate::AconfigStorageError::{
|
use crate::AconfigStorageError::{BytesParseFail, HashTableSizeLimit, InvalidStoredFlagType};
|
||||||
BytesParseFail, FileCreationFail, HashTableSizeLimit, InvalidStoredFlagType,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Storage file version
|
/// Storage file version
|
||||||
pub const FILE_VERSION: u32 = 1;
|
pub const FILE_VERSION: u32 = 1;
|
||||||
@@ -279,104 +277,13 @@ pub fn list_flags(
|
|||||||
Ok(flags)
|
Ok(flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create flag info file
|
|
||||||
pub fn create_flag_info(
|
|
||||||
package_map: &str,
|
|
||||||
flag_map: &str,
|
|
||||||
flag_info_out: &str,
|
|
||||||
) -> Result<(), AconfigStorageError> {
|
|
||||||
let package_table = PackageTable::from_bytes(&read_file_to_bytes(package_map)?)?;
|
|
||||||
let flag_table = FlagTable::from_bytes(&read_file_to_bytes(flag_map)?)?;
|
|
||||||
|
|
||||||
if package_table.header.container != flag_table.header.container {
|
|
||||||
return Err(FileCreationFail(anyhow!(
|
|
||||||
"container for package map {} and flag map {} does not match",
|
|
||||||
package_table.header.container,
|
|
||||||
flag_table.header.container,
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut package_offsets = vec![0; package_table.header.num_packages as usize];
|
|
||||||
for node in package_table.nodes.iter() {
|
|
||||||
package_offsets[node.package_id as usize] = node.boolean_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut is_flag_rw = vec![false; flag_table.header.num_flags as usize];
|
|
||||||
for node in flag_table.nodes.iter() {
|
|
||||||
let flag_offset = package_offsets[node.package_id as usize] + node.flag_id as u32;
|
|
||||||
is_flag_rw[flag_offset as usize] = node.flag_type == StoredFlagType::ReadWriteBoolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut list = FlagInfoList {
|
|
||||||
header: FlagInfoHeader {
|
|
||||||
version: FILE_VERSION,
|
|
||||||
container: flag_table.header.container,
|
|
||||||
file_type: StorageFileType::FlagInfo as u8,
|
|
||||||
file_size: 0,
|
|
||||||
num_flags: flag_table.header.num_flags,
|
|
||||||
boolean_flag_offset: 0,
|
|
||||||
},
|
|
||||||
nodes: is_flag_rw.iter().map(|&rw| FlagInfoNode::create(rw)).collect(),
|
|
||||||
};
|
|
||||||
|
|
||||||
list.header.boolean_flag_offset = list.header.into_bytes().len() as u32;
|
|
||||||
list.header.file_size = list.into_bytes().len() as u32;
|
|
||||||
|
|
||||||
let mut file = File::create(flag_info_out).map_err(|errmsg| {
|
|
||||||
FileCreationFail(anyhow!("fail to create file {}: {}", flag_info_out, errmsg))
|
|
||||||
})?;
|
|
||||||
file.write_all(&list.into_bytes()).map_err(|errmsg| {
|
|
||||||
FileCreationFail(anyhow!("fail to write to file {}: {}", flag_info_out, errmsg))
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// *************************************** //
|
|
||||||
// CC INTERLOP
|
|
||||||
// *************************************** //
|
|
||||||
#[cxx::bridge]
|
|
||||||
mod ffi {
|
|
||||||
pub struct FlagInfoCreationCXX {
|
|
||||||
pub success: bool,
|
|
||||||
pub error_message: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "Rust" {
|
|
||||||
pub fn create_flag_info_cxx(
|
|
||||||
package_map: &str,
|
|
||||||
flag_map: &str,
|
|
||||||
flag_info_out: &str,
|
|
||||||
) -> FlagInfoCreationCXX;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create flag info file cc interlop
|
|
||||||
pub fn create_flag_info_cxx(
|
|
||||||
package_map: &str,
|
|
||||||
flag_map: &str,
|
|
||||||
flag_info_out: &str,
|
|
||||||
) -> ffi::FlagInfoCreationCXX {
|
|
||||||
match create_flag_info(package_map, flag_map, flag_info_out) {
|
|
||||||
Ok(()) => ffi::FlagInfoCreationCXX {
|
|
||||||
success: true,
|
|
||||||
error_message: String::from(""),
|
|
||||||
},
|
|
||||||
Err(errmsg) => ffi::FlagInfoCreationCXX {
|
|
||||||
success: false,
|
|
||||||
error_message: format!("{:?}", errmsg),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::test_utils::{
|
use crate::test_utils::{
|
||||||
create_test_flag_info_list, create_test_flag_table, create_test_flag_value_list,
|
create_test_flag_table, create_test_flag_value_list, create_test_package_table,
|
||||||
create_test_package_table, write_bytes_to_temp_file,
|
write_bytes_to_temp_file,
|
||||||
};
|
};
|
||||||
use tempfile::NamedTempFile;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
// this test point locks down the flag list api
|
// this test point locks down the flag list api
|
||||||
@@ -445,31 +352,4 @@ mod tests {
|
|||||||
];
|
];
|
||||||
assert_eq!(flags, expected);
|
assert_eq!(flags, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_empty_temp_file() -> Result<NamedTempFile, AconfigStorageError> {
|
|
||||||
let file = NamedTempFile::new().map_err(|_| {
|
|
||||||
AconfigStorageError::FileCreationFail(anyhow!("Failed to create temp file"))
|
|
||||||
})?;
|
|
||||||
Ok(file)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
// this test point locks down the flag info creation
|
|
||||||
fn test_create_flag_info() {
|
|
||||||
let package_table =
|
|
||||||
write_bytes_to_temp_file(&create_test_package_table().into_bytes()).unwrap();
|
|
||||||
let flag_table = write_bytes_to_temp_file(&create_test_flag_table().into_bytes()).unwrap();
|
|
||||||
let flag_info = create_empty_temp_file().unwrap();
|
|
||||||
|
|
||||||
let package_table_path = package_table.path().display().to_string();
|
|
||||||
let flag_table_path = flag_table.path().display().to_string();
|
|
||||||
let flag_info_path = flag_info.path().display().to_string();
|
|
||||||
|
|
||||||
assert!(create_flag_info(&package_table_path, &flag_table_path, &flag_info_path).is_ok());
|
|
||||||
|
|
||||||
let flag_info =
|
|
||||||
FlagInfoList::from_bytes(&read_file_to_bytes(&flag_info_path).unwrap()).unwrap();
|
|
||||||
let expected_flag_info = create_test_flag_info_list();
|
|
||||||
assert_eq!(flag_info, expected_flag_info);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -126,4 +126,18 @@ Result<void> set_boolean_flag_value(
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<void> create_flag_info(
|
||||||
|
std::string const& package_map,
|
||||||
|
std::string const& flag_map,
|
||||||
|
std::string const& flag_info_out) {
|
||||||
|
auto creation_cxx = create_flag_info_cxx(
|
||||||
|
rust::Str(package_map.c_str()),
|
||||||
|
rust::Str(flag_map.c_str()),
|
||||||
|
rust::Str(flag_info_out.c_str()));
|
||||||
|
if (creation_cxx.success) {
|
||||||
|
return {};
|
||||||
|
} else {
|
||||||
|
return android::base::Error() << creation_cxx.error_message;
|
||||||
|
}
|
||||||
|
}
|
||||||
} // namespace aconfig_storage
|
} // namespace aconfig_storage
|
||||||
|
@@ -34,4 +34,13 @@ Result<void> set_boolean_flag_value(
|
|||||||
uint32_t offset,
|
uint32_t offset,
|
||||||
bool value);
|
bool value);
|
||||||
|
|
||||||
|
/// Create flag info file based on package and flag map
|
||||||
|
/// \input package_map: package map file
|
||||||
|
/// \input flag_map: flag map file
|
||||||
|
/// \input flag_info_out: flag info file to be created
|
||||||
|
Result<void> create_flag_info(
|
||||||
|
std::string const& package_map,
|
||||||
|
std::string const& flag_map,
|
||||||
|
std::string const& flag_info_out);
|
||||||
|
|
||||||
} // namespace aconfig_storage
|
} // namespace aconfig_storage
|
||||||
|
@@ -23,10 +23,15 @@ pub mod mapped_file;
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test_utils;
|
mod test_utils;
|
||||||
|
|
||||||
use aconfig_storage_file::AconfigStorageError;
|
use aconfig_storage_file::{
|
||||||
|
AconfigStorageError, FlagInfoHeader, FlagInfoList, FlagInfoNode, FlagTable, PackageTable,
|
||||||
|
StorageFileType, StoredFlagType, FILE_VERSION,
|
||||||
|
};
|
||||||
|
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use memmap2::MmapMut;
|
use memmap2::MmapMut;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
/// Storage file location pb file
|
/// Storage file location pb file
|
||||||
pub const STORAGE_LOCATION_FILE: &str = "/metadata/aconfig/persistent_storage_file_records.pb";
|
pub const STORAGE_LOCATION_FILE: &str = "/metadata/aconfig/persistent_storage_file_records.pb";
|
||||||
@@ -65,6 +70,86 @@ pub fn set_boolean_flag_value(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Read in storage file as bytes
|
||||||
|
fn read_file_to_bytes(file_path: &str) -> Result<Vec<u8>, AconfigStorageError> {
|
||||||
|
let mut file = File::open(file_path).map_err(|errmsg| {
|
||||||
|
AconfigStorageError::FileReadFail(anyhow!("Failed to open file {}: {}", file_path, errmsg))
|
||||||
|
})?;
|
||||||
|
let mut buffer = Vec::new();
|
||||||
|
file.read_to_end(&mut buffer).map_err(|errmsg| {
|
||||||
|
AconfigStorageError::FileReadFail(anyhow!(
|
||||||
|
"Failed to read bytes from file {}: {}",
|
||||||
|
file_path,
|
||||||
|
errmsg
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
Ok(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create flag info file given package map file and flag map file
|
||||||
|
/// \input package_map: package map file
|
||||||
|
/// \input flag_map: flag map file
|
||||||
|
/// \output flag_info_out: created flag info file
|
||||||
|
pub fn create_flag_info(
|
||||||
|
package_map: &str,
|
||||||
|
flag_map: &str,
|
||||||
|
flag_info_out: &str,
|
||||||
|
) -> Result<(), AconfigStorageError> {
|
||||||
|
let package_table = PackageTable::from_bytes(&read_file_to_bytes(package_map)?)?;
|
||||||
|
let flag_table = FlagTable::from_bytes(&read_file_to_bytes(flag_map)?)?;
|
||||||
|
|
||||||
|
if package_table.header.container != flag_table.header.container {
|
||||||
|
return Err(AconfigStorageError::FileCreationFail(anyhow!(
|
||||||
|
"container for package map {} and flag map {} does not match",
|
||||||
|
package_table.header.container,
|
||||||
|
flag_table.header.container,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut package_offsets = vec![0; package_table.header.num_packages as usize];
|
||||||
|
for node in package_table.nodes.iter() {
|
||||||
|
package_offsets[node.package_id as usize] = node.boolean_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut is_flag_rw = vec![false; flag_table.header.num_flags as usize];
|
||||||
|
for node in flag_table.nodes.iter() {
|
||||||
|
let flag_offset = package_offsets[node.package_id as usize] + node.flag_id as u32;
|
||||||
|
is_flag_rw[flag_offset as usize] = node.flag_type == StoredFlagType::ReadWriteBoolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut list = FlagInfoList {
|
||||||
|
header: FlagInfoHeader {
|
||||||
|
version: FILE_VERSION,
|
||||||
|
container: flag_table.header.container,
|
||||||
|
file_type: StorageFileType::FlagInfo as u8,
|
||||||
|
file_size: 0,
|
||||||
|
num_flags: flag_table.header.num_flags,
|
||||||
|
boolean_flag_offset: 0,
|
||||||
|
},
|
||||||
|
nodes: is_flag_rw.iter().map(|&rw| FlagInfoNode::create(rw)).collect(),
|
||||||
|
};
|
||||||
|
|
||||||
|
list.header.boolean_flag_offset = list.header.into_bytes().len() as u32;
|
||||||
|
list.header.file_size = list.into_bytes().len() as u32;
|
||||||
|
|
||||||
|
let mut file = File::create(flag_info_out).map_err(|errmsg| {
|
||||||
|
AconfigStorageError::FileCreationFail(anyhow!(
|
||||||
|
"fail to create file {}: {}",
|
||||||
|
flag_info_out,
|
||||||
|
errmsg
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
file.write_all(&list.into_bytes()).map_err(|errmsg| {
|
||||||
|
AconfigStorageError::FileCreationFail(anyhow!(
|
||||||
|
"fail to write to file {}: {}",
|
||||||
|
flag_info_out,
|
||||||
|
errmsg
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
// *************************************** //
|
// *************************************** //
|
||||||
// CC INTERLOP
|
// CC INTERLOP
|
||||||
// *************************************** //
|
// *************************************** //
|
||||||
@@ -78,6 +163,12 @@ mod ffi {
|
|||||||
pub error_message: String,
|
pub error_message: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Flag info file creation return for cc interlop
|
||||||
|
pub struct FlagInfoCreationCXX {
|
||||||
|
pub success: bool,
|
||||||
|
pub error_message: String,
|
||||||
|
}
|
||||||
|
|
||||||
// Rust export to c++
|
// Rust export to c++
|
||||||
extern "Rust" {
|
extern "Rust" {
|
||||||
pub fn update_boolean_flag_value_cxx(
|
pub fn update_boolean_flag_value_cxx(
|
||||||
@@ -85,6 +176,12 @@ mod ffi {
|
|||||||
offset: u32,
|
offset: u32,
|
||||||
value: bool,
|
value: bool,
|
||||||
) -> BooleanFlagValueUpdateCXX;
|
) -> BooleanFlagValueUpdateCXX;
|
||||||
|
|
||||||
|
pub fn create_flag_info_cxx(
|
||||||
|
package_map: &str,
|
||||||
|
flag_map: &str,
|
||||||
|
flag_info_out: &str,
|
||||||
|
) -> FlagInfoCreationCXX;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,14 +201,33 @@ pub(crate) fn update_boolean_flag_value_cxx(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create flag info file cc interlop
|
||||||
|
pub(crate) fn create_flag_info_cxx(
|
||||||
|
package_map: &str,
|
||||||
|
flag_map: &str,
|
||||||
|
flag_info_out: &str,
|
||||||
|
) -> ffi::FlagInfoCreationCXX {
|
||||||
|
match create_flag_info(package_map, flag_map, flag_info_out) {
|
||||||
|
Ok(()) => ffi::FlagInfoCreationCXX { success: true, error_message: String::from("") },
|
||||||
|
Err(errmsg) => {
|
||||||
|
ffi::FlagInfoCreationCXX { success: false, error_message: format!("{:?}", errmsg) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::test_utils::copy_to_temp_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::protos::storage_record_pb::write_proto_to_temp_file;
|
||||||
|
use aconfig_storage_file::test_utils::{
|
||||||
|
create_test_flag_info_list, create_test_flag_table, create_test_package_table,
|
||||||
|
write_bytes_to_temp_file,
|
||||||
|
};
|
||||||
use aconfig_storage_read_api::flag_value_query::find_boolean_flag_value;
|
use aconfig_storage_read_api::flag_value_query::find_boolean_flag_value;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
use tempfile::NamedTempFile;
|
||||||
|
|
||||||
fn get_boolean_flag_value_at_offset(file: &str, offset: u32) -> bool {
|
fn get_boolean_flag_value_at_offset(file: &str, offset: u32) -> bool {
|
||||||
let mut f = File::open(&file).unwrap();
|
let mut f = File::open(&file).unwrap();
|
||||||
@@ -156,4 +272,31 @@ files {{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_empty_temp_file() -> Result<NamedTempFile, AconfigStorageError> {
|
||||||
|
let file = NamedTempFile::new().map_err(|_| {
|
||||||
|
AconfigStorageError::FileCreationFail(anyhow!("Failed to create temp file"))
|
||||||
|
})?;
|
||||||
|
Ok(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// this test point locks down the flag info creation
|
||||||
|
fn test_create_flag_info() {
|
||||||
|
let package_table =
|
||||||
|
write_bytes_to_temp_file(&create_test_package_table().into_bytes()).unwrap();
|
||||||
|
let flag_table = write_bytes_to_temp_file(&create_test_flag_table().into_bytes()).unwrap();
|
||||||
|
let flag_info = create_empty_temp_file().unwrap();
|
||||||
|
|
||||||
|
let package_table_path = package_table.path().display().to_string();
|
||||||
|
let flag_table_path = flag_table.path().display().to_string();
|
||||||
|
let flag_info_path = flag_info.path().display().to_string();
|
||||||
|
|
||||||
|
assert!(create_flag_info(&package_table_path, &flag_table_path, &flag_info_path).is_ok());
|
||||||
|
|
||||||
|
let flag_info =
|
||||||
|
FlagInfoList::from_bytes(&read_file_to_bytes(&flag_info_path).unwrap()).unwrap();
|
||||||
|
let expected_flag_info = create_test_flag_info_list();
|
||||||
|
assert_eq!(flag_info, expected_flag_info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -39,4 +39,5 @@ cc_test {
|
|||||||
"device-tests",
|
"device-tests",
|
||||||
"general-tests",
|
"general-tests",
|
||||||
],
|
],
|
||||||
|
ldflags: ["-Wl,--allow-multiple-definition"],
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user