blob: 2c80a4a898894faf5eef406b27f8dfe9a865d853 [file] [log] [blame]
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +02001/*
2 * Copyright (C) 2023 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
Mårten Kongstad30950782023-05-09 13:31:29 +020017use anyhow::{ensure, Context, Result};
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020018use clap::ValueEnum;
Mårten Kongstada1029092023-05-08 11:51:59 +020019use protobuf::Message;
Mårten Kongstad76adff22023-05-08 10:57:24 +020020use serde::{Deserialize, Serialize};
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020021use std::fmt;
22use std::io::Read;
23
Mårten Kongstad30950782023-05-09 13:31:29 +020024use crate::aconfig::{Namespace, Override};
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020025use crate::cache::Cache;
Mårten Kongstad30950782023-05-09 13:31:29 +020026use crate::protos::ProtoParsedFlags;
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020027
Mårten Kongstad76adff22023-05-08 10:57:24 +020028#[derive(Serialize, Deserialize, Clone, Debug)]
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020029pub enum Source {
30 #[allow(dead_code)] // only used in unit tests
31 Memory,
32 File(String),
33}
34
35impl fmt::Display for Source {
36 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
37 match self {
38 Self::Memory => write!(f, "<memory>"),
39 Self::File(path) => write!(f, "{}", path),
40 }
41 }
42}
43
44pub struct Input {
45 pub source: Source,
46 pub reader: Box<dyn Read>,
47}
48
Mårten Kongstad30950782023-05-09 13:31:29 +020049pub fn create_cache(
50 build_id: u32,
51 namespace: &str,
52 aconfigs: Vec<Input>,
53 overrides: Vec<Input>,
54) -> Result<Cache> {
55 let mut cache = Cache::new(build_id, namespace.to_owned());
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020056
57 for mut input in aconfigs {
58 let mut contents = String::new();
59 input.reader.read_to_string(&mut contents)?;
Mårten Kongstad30950782023-05-09 13:31:29 +020060 let ns = Namespace::try_from_text_proto(&contents)
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020061 .with_context(|| format!("Failed to parse {}", input.source))?;
Mårten Kongstad30950782023-05-09 13:31:29 +020062 ensure!(
63 namespace == ns.namespace,
64 "Failed to parse {}: expected namespace {}, got {}",
65 input.source,
66 namespace,
67 ns.namespace
68 );
69 for flag in ns.flags.into_iter() {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020070 cache.add_flag(input.source.clone(), flag)?;
71 }
72 }
73
74 for mut input in overrides {
75 let mut contents = String::new();
76 input.reader.read_to_string(&mut contents)?;
77 let overrides = Override::try_from_text_proto_list(&contents)
78 .with_context(|| format!("Failed to parse {}", input.source))?;
79 for override_ in overrides {
80 cache.add_override(input.source.clone(), override_)?;
81 }
82 }
83
84 Ok(cache)
85}
86
87#[derive(Copy, Clone, Debug, PartialEq, Eq, ValueEnum)]
88pub enum Format {
89 Text,
90 Debug,
Mårten Kongstada1029092023-05-08 11:51:59 +020091 Protobuf,
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020092}
93
Mårten Kongstada1029092023-05-08 11:51:59 +020094pub fn dump_cache(cache: Cache, format: Format) -> Result<Vec<u8>> {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020095 match format {
96 Format::Text => {
Mårten Kongstada1029092023-05-08 11:51:59 +020097 let mut lines = vec![];
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020098 for item in cache.iter() {
Mårten Kongstad30950782023-05-09 13:31:29 +020099 lines.push(format!("{}: {:?}\n", item.name, item.state));
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200100 }
Mårten Kongstada1029092023-05-08 11:51:59 +0200101 Ok(lines.concat().into())
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200102 }
103 Format::Debug => {
Mårten Kongstada1029092023-05-08 11:51:59 +0200104 let mut lines = vec![];
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200105 for item in cache.iter() {
Mårten Kongstada1029092023-05-08 11:51:59 +0200106 lines.push(format!("{:?}\n", item));
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200107 }
Mårten Kongstada1029092023-05-08 11:51:59 +0200108 Ok(lines.concat().into())
109 }
110 Format::Protobuf => {
Mårten Kongstad30950782023-05-09 13:31:29 +0200111 let parsed_flags: ProtoParsedFlags = cache.into();
Mårten Kongstada1029092023-05-08 11:51:59 +0200112 let mut output = vec![];
Mårten Kongstad30950782023-05-09 13:31:29 +0200113 parsed_flags.write_to_vec(&mut output)?;
Mårten Kongstada1029092023-05-08 11:51:59 +0200114 Ok(output)
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200115 }
116 }
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200122 use crate::aconfig::{FlagState, Permission};
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200123
Mårten Kongstada1029092023-05-08 11:51:59 +0200124 fn create_test_cache() -> Cache {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200125 let s = r#"
Mårten Kongstad30950782023-05-09 13:31:29 +0200126 namespace: "ns"
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200127 flag {
Mårten Kongstad30950782023-05-09 13:31:29 +0200128 name: "a"
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200129 description: "Description of a"
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200130 value {
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200131 state: ENABLED
132 permission: READ_WRITE
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200133 }
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200134 }
Mårten Kongstada1029092023-05-08 11:51:59 +0200135 flag {
Mårten Kongstad30950782023-05-09 13:31:29 +0200136 name: "b"
Mårten Kongstada1029092023-05-08 11:51:59 +0200137 description: "Description of b"
138 value {
139 state: ENABLED
140 permission: READ_ONLY
141 }
142 }
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200143 "#;
144 let aconfigs = vec![Input { source: Source::Memory, reader: Box::new(s.as_bytes()) }];
145 let o = r#"
Mårten Kongstad30950782023-05-09 13:31:29 +0200146 flag_override {
147 namespace: "ns"
148 name: "a"
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200149 state: DISABLED
Mårten Kongstad416330b2023-05-05 11:10:01 +0200150 permission: READ_ONLY
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200151 }
152 "#;
153 let overrides = vec![Input { source: Source::Memory, reader: Box::new(o.as_bytes()) }];
Mårten Kongstad30950782023-05-09 13:31:29 +0200154 create_cache(1, "ns", aconfigs, overrides).unwrap()
Mårten Kongstada1029092023-05-08 11:51:59 +0200155 }
156
157 #[test]
158 fn test_create_cache() {
159 let cache = create_test_cache(); // calls create_cache
Mårten Kongstad30950782023-05-09 13:31:29 +0200160 let item = cache.iter().find(|&item| item.name == "a").unwrap();
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200161 assert_eq!(FlagState::Disabled, item.state);
162 assert_eq!(Permission::ReadOnly, item.permission);
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200163 }
Mårten Kongstada1029092023-05-08 11:51:59 +0200164
165 #[test]
166 fn test_dump_text_format() {
167 let cache = create_test_cache();
168 let bytes = dump_cache(cache, Format::Text).unwrap();
169 let text = std::str::from_utf8(&bytes).unwrap();
170 assert!(text.contains("a: Disabled"));
171 }
172
173 #[test]
174 fn test_dump_protobuf_format() {
Mårten Kongstad30950782023-05-09 13:31:29 +0200175 use crate::protos::{ProtoFlagPermission, ProtoFlagState, ProtoTracepoint};
Mårten Kongstada1029092023-05-08 11:51:59 +0200176 use protobuf::Message;
177
178 let cache = create_test_cache();
179 let bytes = dump_cache(cache, Format::Protobuf).unwrap();
Mårten Kongstad30950782023-05-09 13:31:29 +0200180 let actual = ProtoParsedFlags::parse_from_bytes(&bytes).unwrap();
Mårten Kongstada1029092023-05-08 11:51:59 +0200181
182 assert_eq!(
183 vec!["a".to_string(), "b".to_string()],
Mårten Kongstad30950782023-05-09 13:31:29 +0200184 actual.parsed_flag.iter().map(|item| item.name.clone().unwrap()).collect::<Vec<_>>()
Mårten Kongstada1029092023-05-08 11:51:59 +0200185 );
Mårten Kongstad30950782023-05-09 13:31:29 +0200186
187 let item =
188 actual.parsed_flag.iter().find(|item| item.name == Some("b".to_string())).unwrap();
189 assert_eq!(item.namespace(), "ns");
190 assert_eq!(item.name(), "b");
191 assert_eq!(item.description(), "Description of b");
192 assert_eq!(item.state(), ProtoFlagState::ENABLED);
193 assert_eq!(item.permission(), ProtoFlagPermission::READ_ONLY);
194 let mut tp = ProtoTracepoint::new();
195 tp.set_source("<memory>".to_string());
196 tp.set_state(ProtoFlagState::ENABLED);
197 tp.set_permission(ProtoFlagPermission::READ_ONLY);
198 assert_eq!(item.trace, vec![tp]);
Mårten Kongstada1029092023-05-08 11:51:59 +0200199 }
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200200}