blob: 4b46c4254217b7e223441e0caec050e5a92e21f3 [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
17use anyhow::{anyhow, Result};
18use serde::{Deserialize, Serialize};
19use std::io::{Read, Write};
20
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +020021use crate::aconfig::{Flag, FlagState, Override, Permission};
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020022use crate::commands::Source;
23
Mårten Kongstad416330b2023-05-05 11:10:01 +020024#[derive(Serialize, Deserialize, Debug)]
Mårten Kongstad30950782023-05-09 13:31:29 +020025pub struct Tracepoint {
Mårten Kongstad76adff22023-05-08 10:57:24 +020026 pub source: Source,
27 pub state: FlagState,
28 pub permission: Permission,
29}
30
31#[derive(Serialize, Deserialize, Debug)]
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020032pub struct Item {
Mårten Kongstad30950782023-05-09 13:31:29 +020033 // TODO: duplicating the Cache.namespace as Item.namespace makes the internal representation
34 // closer to the proto message `parsed_flag`; hopefully this will enable us to replace the Item
35 // struct and use a newtype instead once aconfig has matured. Until then, namespace should
36 // really be a Cow<String>.
37 pub namespace: String,
38 pub name: String,
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020039 pub description: String,
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +020040 pub state: FlagState,
Mårten Kongstad416330b2023-05-05 11:10:01 +020041 pub permission: Permission,
Mårten Kongstad30950782023-05-09 13:31:29 +020042 pub trace: Vec<Tracepoint>,
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020043}
44
Mårten Kongstad416330b2023-05-05 11:10:01 +020045#[derive(Serialize, Deserialize, Debug)]
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020046pub struct Cache {
Mårten Kongstad09c28d12023-05-04 13:29:26 +020047 build_id: u32,
Mårten Kongstad30950782023-05-09 13:31:29 +020048 namespace: String,
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020049 items: Vec<Item>,
50}
51
52impl Cache {
Mårten Kongstad30950782023-05-09 13:31:29 +020053 pub fn new(build_id: u32, namespace: String) -> Cache {
54 Cache { build_id, namespace, items: vec![] }
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020055 }
56
57 pub fn read_from_reader(reader: impl Read) -> Result<Cache> {
58 serde_json::from_reader(reader).map_err(|e| e.into())
59 }
60
61 pub fn write_to_writer(&self, writer: impl Write) -> Result<()> {
62 serde_json::to_writer(writer, self).map_err(|e| e.into())
63 }
64
65 pub fn add_flag(&mut self, source: Source, flag: Flag) -> Result<()> {
Mårten Kongstad30950782023-05-09 13:31:29 +020066 if self.items.iter().any(|item| item.name == flag.name) {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020067 return Err(anyhow!(
Mårten Kongstad09c28d12023-05-04 13:29:26 +020068 "failed to add flag {} from {}: flag already defined",
Mårten Kongstad30950782023-05-09 13:31:29 +020069 flag.name,
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020070 source,
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020071 ));
72 }
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +020073 let (state, permission) = flag.resolve(self.build_id);
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020074 self.items.push(Item {
Mårten Kongstad30950782023-05-09 13:31:29 +020075 namespace: self.namespace.clone(),
76 name: flag.name.clone(),
Mårten Kongstad09c28d12023-05-04 13:29:26 +020077 description: flag.description,
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +020078 state,
Mårten Kongstad416330b2023-05-05 11:10:01 +020079 permission,
Mårten Kongstad30950782023-05-09 13:31:29 +020080 trace: vec![Tracepoint { source, state, permission }],
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020081 });
82 Ok(())
83 }
84
85 pub fn add_override(&mut self, source: Source, override_: Override) -> Result<()> {
Mårten Kongstad30950782023-05-09 13:31:29 +020086 if override_.namespace != self.namespace {
87 // TODO: print warning?
88 return Ok(());
89 }
90 let Some(existing_item) = self.items.iter_mut().find(|item| item.name == override_.name) else {
91 return Err(anyhow!("failed to override flag {}: unknown flag", override_.name));
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020092 };
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +020093 existing_item.state = override_.state;
Mårten Kongstad416330b2023-05-05 11:10:01 +020094 existing_item.permission = override_.permission;
Mårten Kongstad30950782023-05-09 13:31:29 +020095 existing_item.trace.push(Tracepoint {
Mårten Kongstad76adff22023-05-08 10:57:24 +020096 source,
97 state: override_.state,
98 permission: override_.permission,
99 });
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200100 Ok(())
101 }
102
103 pub fn iter(&self) -> impl Iterator<Item = &Item> {
104 self.items.iter()
105 }
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200106
Mårten Kongstada1029092023-05-08 11:51:59 +0200107 pub fn into_iter(self) -> impl Iterator<Item = Item> {
108 self.items.into_iter()
109 }
110}
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200111
112#[cfg(test)]
113mod tests {
114 use super::*;
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200115 use crate::aconfig::{FlagState, Permission, Value};
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200116
117 #[test]
118 fn test_add_flag() {
Mårten Kongstad30950782023-05-09 13:31:29 +0200119 let mut cache = Cache::new(1, "ns".to_string());
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200120 cache
121 .add_flag(
122 Source::File("first.txt".to_string()),
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200123 Flag {
Mårten Kongstad30950782023-05-09 13:31:29 +0200124 name: "foo".to_string(),
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200125 description: "desc".to_string(),
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200126 values: vec![Value::default(FlagState::Enabled, Permission::ReadOnly)],
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200127 },
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200128 )
129 .unwrap();
130 let error = cache
131 .add_flag(
132 Source::File("second.txt".to_string()),
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200133 Flag {
Mårten Kongstad30950782023-05-09 13:31:29 +0200134 name: "foo".to_string(),
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200135 description: "desc".to_string(),
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200136 values: vec![Value::default(FlagState::Disabled, Permission::ReadOnly)],
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200137 },
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200138 )
139 .unwrap_err();
140 assert_eq!(
141 &format!("{:?}", error),
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200142 "failed to add flag foo from second.txt: flag already defined"
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200143 );
144 }
145
146 #[test]
147 fn test_add_override() {
Mårten Kongstad30950782023-05-09 13:31:29 +0200148 fn check(cache: &Cache, name: &str, expected: (FlagState, Permission)) -> bool {
149 let item = cache.iter().find(|&item| item.name == name).unwrap();
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200150 item.state == expected.0 && item.permission == expected.1
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200151 }
152
Mårten Kongstad30950782023-05-09 13:31:29 +0200153 let mut cache = Cache::new(1, "ns".to_string());
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200154 let error = cache
Mårten Kongstad416330b2023-05-05 11:10:01 +0200155 .add_override(
156 Source::Memory,
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200157 Override {
Mårten Kongstad30950782023-05-09 13:31:29 +0200158 namespace: "ns".to_string(),
159 name: "foo".to_string(),
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200160 state: FlagState::Enabled,
161 permission: Permission::ReadOnly,
162 },
Mårten Kongstad416330b2023-05-05 11:10:01 +0200163 )
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200164 .unwrap_err();
165 assert_eq!(&format!("{:?}", error), "failed to override flag foo: unknown flag");
166
167 cache
168 .add_flag(
169 Source::File("first.txt".to_string()),
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200170 Flag {
Mårten Kongstad30950782023-05-09 13:31:29 +0200171 name: "foo".to_string(),
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200172 description: "desc".to_string(),
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200173 values: vec![Value::default(FlagState::Enabled, Permission::ReadOnly)],
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200174 },
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200175 )
176 .unwrap();
Mårten Kongstad416330b2023-05-05 11:10:01 +0200177 dbg!(&cache);
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200178 assert!(check(&cache, "foo", (FlagState::Enabled, Permission::ReadOnly)));
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200179
180 cache
Mårten Kongstad416330b2023-05-05 11:10:01 +0200181 .add_override(
182 Source::Memory,
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200183 Override {
Mårten Kongstad30950782023-05-09 13:31:29 +0200184 namespace: "ns".to_string(),
185 name: "foo".to_string(),
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200186 state: FlagState::Disabled,
187 permission: Permission::ReadWrite,
188 },
Mårten Kongstad416330b2023-05-05 11:10:01 +0200189 )
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200190 .unwrap();
Mårten Kongstad416330b2023-05-05 11:10:01 +0200191 dbg!(&cache);
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200192 assert!(check(&cache, "foo", (FlagState::Disabled, Permission::ReadWrite)));
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200193
194 cache
Mårten Kongstad416330b2023-05-05 11:10:01 +0200195 .add_override(
196 Source::Memory,
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200197 Override {
Mårten Kongstad30950782023-05-09 13:31:29 +0200198 namespace: "ns".to_string(),
199 name: "foo".to_string(),
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200200 state: FlagState::Enabled,
201 permission: Permission::ReadWrite,
202 },
Mårten Kongstad416330b2023-05-05 11:10:01 +0200203 )
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200204 .unwrap();
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200205 assert!(check(&cache, "foo", (FlagState::Enabled, Permission::ReadWrite)));
Mårten Kongstad30950782023-05-09 13:31:29 +0200206
207 // different namespace -> no-op
208 cache
209 .add_override(
210 Source::Memory,
211 Override {
212 namespace: "some-other-namespace".to_string(),
213 name: "foo".to_string(),
214 state: FlagState::Enabled,
215 permission: Permission::ReadOnly,
216 },
217 )
218 .unwrap();
219 assert!(check(&cache, "foo", (FlagState::Enabled, Permission::ReadWrite)));
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200220 }
221}