blob: 7b6edc599bf2eac6b48f0b5d4a423cfc2e551695 [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 }
122}
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200123
124#[cfg(test)]
125mod tests {
126 use super::*;
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200127 use crate::aconfig::{FlagState, Permission};
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200128
129 #[test]
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200130 fn test_add_flag_declaration() {
131 let mut cache = Cache::new("ns".to_string());
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200132 cache
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200133 .add_flag_declaration(
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200134 Source::File("first.txt".to_string()),
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200135 FlagDeclaration { name: "foo".to_string(), description: "desc".to_string() },
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200136 )
137 .unwrap();
138 let error = cache
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200139 .add_flag_declaration(
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200140 Source::File("second.txt".to_string()),
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200141 FlagDeclaration { name: "foo".to_string(), description: "desc".to_string() },
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200142 )
143 .unwrap_err();
144 assert_eq!(
145 &format!("{:?}", error),
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200146 "failed to declare flag foo from second.txt: flag already declared"
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200147 );
148 }
149
150 #[test]
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200151 fn test_add_flag_value() {
Mårten Kongstad30950782023-05-09 13:31:29 +0200152 fn check(cache: &Cache, name: &str, expected: (FlagState, Permission)) -> bool {
153 let item = cache.iter().find(|&item| item.name == name).unwrap();
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200154 item.state == expected.0 && item.permission == expected.1
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200155 }
156
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200157 let mut cache = Cache::new("ns".to_string());
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200158 let error = cache
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200159 .add_flag_value(
Mårten Kongstad416330b2023-05-05 11:10:01 +0200160 Source::Memory,
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200161 FlagValue {
Mårten Kongstad30950782023-05-09 13:31:29 +0200162 namespace: "ns".to_string(),
163 name: "foo".to_string(),
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200164 state: FlagState::Enabled,
165 permission: Permission::ReadOnly,
166 },
Mårten Kongstad416330b2023-05-05 11:10:01 +0200167 )
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200168 .unwrap_err();
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200169 assert_eq!(
170 &format!("{:?}", error),
171 "failed to set values for flag ns/foo from <memory>: flag not declared"
172 );
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200173
174 cache
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200175 .add_flag_declaration(
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200176 Source::File("first.txt".to_string()),
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200177 FlagDeclaration { name: "foo".to_string(), description: "desc".to_string() },
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200178 )
179 .unwrap();
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200180 assert!(check(&cache, "foo", (DEFAULT_FLAG_STATE, DEFAULT_FLAG_PERMISSION)));
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200181
182 cache
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200183 .add_flag_value(
Mårten Kongstad416330b2023-05-05 11:10:01 +0200184 Source::Memory,
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200185 FlagValue {
Mårten Kongstad30950782023-05-09 13:31:29 +0200186 namespace: "ns".to_string(),
187 name: "foo".to_string(),
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200188 state: FlagState::Disabled,
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200189 permission: Permission::ReadOnly,
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200190 },
Mårten Kongstad416330b2023-05-05 11:10:01 +0200191 )
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200192 .unwrap();
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200193 assert!(check(&cache, "foo", (FlagState::Disabled, Permission::ReadOnly)));
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200194
195 cache
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200196 .add_flag_value(
Mårten Kongstad416330b2023-05-05 11:10:01 +0200197 Source::Memory,
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200198 FlagValue {
Mårten Kongstad30950782023-05-09 13:31:29 +0200199 namespace: "ns".to_string(),
200 name: "foo".to_string(),
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200201 state: FlagState::Enabled,
202 permission: Permission::ReadWrite,
203 },
Mårten Kongstad416330b2023-05-05 11:10:01 +0200204 )
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200205 .unwrap();
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200206 assert!(check(&cache, "foo", (FlagState::Enabled, Permission::ReadWrite)));
Mårten Kongstad30950782023-05-09 13:31:29 +0200207
208 // different namespace -> no-op
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200209 let error = cache
210 .add_flag_value(
Mårten Kongstad30950782023-05-09 13:31:29 +0200211 Source::Memory,
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200212 FlagValue {
Mårten Kongstad30950782023-05-09 13:31:29 +0200213 namespace: "some-other-namespace".to_string(),
214 name: "foo".to_string(),
215 state: FlagState::Enabled,
216 permission: Permission::ReadOnly,
217 },
218 )
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200219 .unwrap_err();
220 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 +0200221 assert!(check(&cache, "foo", (FlagState::Enabled, Permission::ReadWrite)));
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200222 }
223}