blob: 5ef18290f370c3253f1bb246632f35336da6f711 [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 Kongstade66b89f2023-05-15 10:29:25 +020017use anyhow::{bail, ensure, Result};
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020018use serde::{Deserialize, Serialize};
19use std::io::{Read, Write};
20
Mårten Kongstadfa23d292023-05-11 14:47:02 +020021use crate::aconfig::{FlagDeclaration, FlagState, FlagValue, Permission};
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020022use crate::commands::Source;
23
Mårten Kongstadfa23d292023-05-11 14:47:02 +020024const DEFAULT_FLAG_STATE: FlagState = FlagState::Disabled;
25const DEFAULT_FLAG_PERMISSION: Permission = Permission::ReadWrite;
26
Mårten Kongstad416330b2023-05-05 11:10:01 +020027#[derive(Serialize, Deserialize, Debug)]
Mårten Kongstad30950782023-05-09 13:31:29 +020028pub struct Tracepoint {
Mårten Kongstad76adff22023-05-08 10:57:24 +020029 pub source: Source,
30 pub state: FlagState,
31 pub permission: Permission,
32}
33
34#[derive(Serialize, Deserialize, Debug)]
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020035pub struct Item {
Mårten Kongstad30950782023-05-09 13:31:29 +020036 // TODO: duplicating the Cache.namespace as Item.namespace makes the internal representation
37 // closer to the proto message `parsed_flag`; hopefully this will enable us to replace the Item
38 // struct and use a newtype instead once aconfig has matured. Until then, namespace should
39 // really be a Cow<String>.
40 pub namespace: String,
41 pub name: String,
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020042 pub description: String,
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +020043 pub state: FlagState,
Mårten Kongstad416330b2023-05-05 11:10:01 +020044 pub permission: Permission,
Mårten Kongstad30950782023-05-09 13:31:29 +020045 pub trace: Vec<Tracepoint>,
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020046}
47
Mårten Kongstad416330b2023-05-05 11:10:01 +020048#[derive(Serialize, Deserialize, Debug)]
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020049pub struct Cache {
Mårten Kongstad30950782023-05-09 13:31:29 +020050 namespace: String,
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020051 items: Vec<Item>,
52}
53
54impl Cache {
Mårten Kongstadfa23d292023-05-11 14:47:02 +020055 pub fn new(namespace: String) -> Cache {
56 Cache { namespace, items: vec![] }
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020057 }
58
59 pub fn read_from_reader(reader: impl Read) -> Result<Cache> {
60 serde_json::from_reader(reader).map_err(|e| e.into())
61 }
62
63 pub fn write_to_writer(&self, writer: impl Write) -> Result<()> {
64 serde_json::to_writer(writer, self).map_err(|e| e.into())
65 }
66
Mårten Kongstadfa23d292023-05-11 14:47:02 +020067 pub fn add_flag_declaration(
68 &mut self,
69 source: Source,
70 declaration: FlagDeclaration,
71 ) -> Result<()> {
Mårten Kongstade66b89f2023-05-15 10:29:25 +020072 ensure!(
73 self.items.iter().all(|item| item.name != declaration.name),
74 "failed to declare flag {} from {}: flag already declared",
75 declaration.name,
76 source
77 );
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020078 self.items.push(Item {
Mårten Kongstad30950782023-05-09 13:31:29 +020079 namespace: self.namespace.clone(),
Mårten Kongstadfa23d292023-05-11 14:47:02 +020080 name: declaration.name.clone(),
81 description: declaration.description,
82 state: DEFAULT_FLAG_STATE,
83 permission: DEFAULT_FLAG_PERMISSION,
84 trace: vec![Tracepoint {
85 source,
86 state: DEFAULT_FLAG_STATE,
87 permission: DEFAULT_FLAG_PERMISSION,
88 }],
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020089 });
90 Ok(())
91 }
92
Mårten Kongstadfa23d292023-05-11 14:47:02 +020093 pub fn add_flag_value(&mut self, source: Source, value: FlagValue) -> Result<()> {
94 ensure!(
95 value.namespace == self.namespace,
96 "failed to set values for flag {}/{} from {}: expected namespace {}",
97 value.namespace,
98 value.name,
99 source,
100 self.namespace
101 );
102 let Some(existing_item) = self.items.iter_mut().find(|item| item.name == value.name) else {
103 bail!("failed to set values for flag {}/{} from {}: flag not declared", value.namespace, value.name, source);
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200104 };
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200105 existing_item.state = value.state;
106 existing_item.permission = value.permission;
Mårten Kongstad30950782023-05-09 13:31:29 +0200107 existing_item.trace.push(Tracepoint {
Mårten Kongstad76adff22023-05-08 10:57:24 +0200108 source,
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200109 state: value.state,
110 permission: value.permission,
Mårten Kongstad76adff22023-05-08 10:57:24 +0200111 });
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200112 Ok(())
113 }
114
115 pub fn iter(&self) -> impl Iterator<Item = &Item> {
116 self.items.iter()
117 }
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200118
Mårten Kongstada1029092023-05-08 11:51:59 +0200119 pub fn into_iter(self) -> impl Iterator<Item = Item> {
120 self.items.into_iter()
121 }
Mårten Kongstad6b9e3822023-05-16 11:19:58 +0200122
123 pub fn namespace(&self) -> &str {
124 &self.namespace
125 }
Mårten Kongstada1029092023-05-08 11:51:59 +0200126}
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200127
128#[cfg(test)]
129mod tests {
130 use super::*;
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200131 use crate::aconfig::{FlagState, Permission};
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200132
133 #[test]
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200134 fn test_add_flag_declaration() {
135 let mut cache = Cache::new("ns".to_string());
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200136 cache
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200137 .add_flag_declaration(
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200138 Source::File("first.txt".to_string()),
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200139 FlagDeclaration { name: "foo".to_string(), description: "desc".to_string() },
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200140 )
141 .unwrap();
142 let error = cache
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200143 .add_flag_declaration(
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200144 Source::File("second.txt".to_string()),
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200145 FlagDeclaration { name: "foo".to_string(), description: "desc".to_string() },
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200146 )
147 .unwrap_err();
148 assert_eq!(
149 &format!("{:?}", error),
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200150 "failed to declare flag foo from second.txt: flag already declared"
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200151 );
152 }
153
154 #[test]
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200155 fn test_add_flag_value() {
Mårten Kongstad30950782023-05-09 13:31:29 +0200156 fn check(cache: &Cache, name: &str, expected: (FlagState, Permission)) -> bool {
157 let item = cache.iter().find(|&item| item.name == name).unwrap();
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200158 item.state == expected.0 && item.permission == expected.1
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200159 }
160
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200161 let mut cache = Cache::new("ns".to_string());
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200162 let error = cache
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200163 .add_flag_value(
Mårten Kongstad416330b2023-05-05 11:10:01 +0200164 Source::Memory,
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200165 FlagValue {
Mårten Kongstad30950782023-05-09 13:31:29 +0200166 namespace: "ns".to_string(),
167 name: "foo".to_string(),
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200168 state: FlagState::Enabled,
169 permission: Permission::ReadOnly,
170 },
Mårten Kongstad416330b2023-05-05 11:10:01 +0200171 )
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200172 .unwrap_err();
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200173 assert_eq!(
174 &format!("{:?}", error),
175 "failed to set values for flag ns/foo from <memory>: flag not declared"
176 );
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200177
178 cache
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200179 .add_flag_declaration(
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200180 Source::File("first.txt".to_string()),
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200181 FlagDeclaration { name: "foo".to_string(), description: "desc".to_string() },
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200182 )
183 .unwrap();
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200184 assert!(check(&cache, "foo", (DEFAULT_FLAG_STATE, DEFAULT_FLAG_PERMISSION)));
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200185
186 cache
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200187 .add_flag_value(
Mårten Kongstad416330b2023-05-05 11:10:01 +0200188 Source::Memory,
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200189 FlagValue {
Mårten Kongstad30950782023-05-09 13:31:29 +0200190 namespace: "ns".to_string(),
191 name: "foo".to_string(),
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200192 state: FlagState::Disabled,
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200193 permission: Permission::ReadOnly,
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200194 },
Mårten Kongstad416330b2023-05-05 11:10:01 +0200195 )
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200196 .unwrap();
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200197 assert!(check(&cache, "foo", (FlagState::Disabled, Permission::ReadOnly)));
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200198
199 cache
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200200 .add_flag_value(
Mårten Kongstad416330b2023-05-05 11:10:01 +0200201 Source::Memory,
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200202 FlagValue {
Mårten Kongstad30950782023-05-09 13:31:29 +0200203 namespace: "ns".to_string(),
204 name: "foo".to_string(),
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200205 state: FlagState::Enabled,
206 permission: Permission::ReadWrite,
207 },
Mårten Kongstad416330b2023-05-05 11:10:01 +0200208 )
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200209 .unwrap();
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200210 assert!(check(&cache, "foo", (FlagState::Enabled, Permission::ReadWrite)));
Mårten Kongstad30950782023-05-09 13:31:29 +0200211
212 // different namespace -> no-op
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200213 let error = cache
214 .add_flag_value(
Mårten Kongstad30950782023-05-09 13:31:29 +0200215 Source::Memory,
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200216 FlagValue {
Mårten Kongstad30950782023-05-09 13:31:29 +0200217 namespace: "some-other-namespace".to_string(),
218 name: "foo".to_string(),
219 state: FlagState::Enabled,
220 permission: Permission::ReadOnly,
221 },
222 )
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200223 .unwrap_err();
224 assert_eq!(&format!("{:?}", error), "failed to set values for flag some-other-namespace/foo from <memory>: expected namespace ns");
Mårten Kongstad30950782023-05-09 13:31:29 +0200225 assert!(check(&cache, "foo", (FlagState::Enabled, Permission::ReadWrite)));
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200226 }
227}