]> git.proxmox.com Git - proxmox-backup.git/blob - tests/verify-api.rs
move acl to pbs_config workspaces, pbs_api_types cleanups
[proxmox-backup.git] / tests / verify-api.rs
1 use std::collections::HashSet;
2
3 use anyhow::{bail, format_err, Error};
4
5 use proxmox_backup::api2;
6 use proxmox::api::*;
7 use proxmox::api::schema::*;
8
9 // Simply test if api lookup tables inside Routers and Schemas are
10 // correctly sorted.
11
12 fn verify_object_schema(schema: &ObjectSchema) -> Result<(), Error> {
13
14 let map = schema.properties;
15
16 if !map.is_empty() {
17
18 for i in 1..map.len() {
19
20 if map[i].0 <= map[i-1].0 {
21 for (name, _, _) in map.iter() {
22 eprintln!("{}", name);
23 }
24 bail!("found unsorted property map ({} <= {})", map[i].0, map[i-1].0);
25 }
26 }
27 }
28
29 for (_name, _, sub_schema) in map.iter() {
30 verify_schema(sub_schema)?;
31 }
32
33 Ok(())
34 }
35
36 // verify entries in an AllOf schema are actually object schemas and that they don't contain
37 // duplicate keys
38 fn verify_all_of_schema(schema: &AllOfSchema) -> Result<(), Error> {
39 for entry in schema.list {
40 match entry {
41 Schema::Object(obj) => verify_object_schema(obj)?,
42 Schema::AllOf(allof) => verify_all_of_schema(allof)?,
43 _ => bail!("AllOf schema with a non-object schema entry!"),
44 }
45 }
46
47 let mut keys = HashSet::<&'static str>::new();
48 let mut dupes = String::new();
49 for property in schema.properties() {
50 if !keys.insert(property.0) {
51 if !dupes.is_empty() {
52 dupes.push_str(", ");
53 }
54 dupes.push_str(property.0);
55 }
56 }
57 if !dupes.is_empty() {
58 bail!("Duplicate keys found in AllOf schema: {}", dupes);
59 }
60
61 Ok(())
62 }
63
64 fn verify_schema(schema: &Schema) -> Result<(), Error> {
65 match schema {
66 Schema::Object(obj_schema) => {
67 verify_object_schema(obj_schema)?;
68 }
69 Schema::AllOf(all_of_schema) => {
70 verify_all_of_schema(all_of_schema)?;
71 }
72 Schema::Array(arr_schema) => {
73 verify_schema(arr_schema.items)?;
74 }
75 _ => {}
76 }
77 Ok(())
78 }
79
80 fn verify_access_permissions(permission: &Permission) -> Result<(), Error> {
81
82 match permission {
83 Permission::Or(list) => {
84 for perm in list.iter() { verify_access_permissions(perm)?; }
85 }
86 Permission::And(list) => {
87 for perm in list.iter() { verify_access_permissions(perm)?; }
88 }
89 Permission::Privilege(path_comp, ..)=> {
90 let path = format!("/{}", path_comp.join("/"));
91 pbs_config::acl::check_acl_path(&path)?;
92 }
93 _ => {}
94 }
95 Ok(())
96 }
97
98 fn verify_api_method(
99 method: &str,
100 path: &str,
101 info: &ApiMethod
102 ) -> Result<(), Error>
103 {
104 match &info.parameters {
105 ParameterSchema::Object(obj) => {
106 verify_object_schema(obj)
107 .map_err(|err| format_err!("{} {} parameters: {}", method, path, err))?;
108 }
109 ParameterSchema::AllOf(all_of) => {
110 verify_all_of_schema(all_of)
111 .map_err(|err| format_err!("{} {} parameters: {}", method, path, err))?;
112 }
113 }
114
115 verify_schema(info.returns.schema)
116 .map_err(|err| format_err!("{} {} returns: {}", method, path, err))?;
117
118 verify_access_permissions(info.access.permission)
119 .map_err(|err| format_err!("{} {} access: {}", method, path, err))?;
120
121 Ok(())
122 }
123
124 fn verify_dirmap(
125 path: &str,
126 dirmap: SubdirMap,
127 ) -> Result<(), Error> {
128
129 if !dirmap.is_empty() {
130
131 for i in 1..dirmap.len() {
132
133 if dirmap[i].0 <= dirmap[i-1].0 {
134 for (name, _) in dirmap.iter() {
135 eprintln!("{}/{}", path, name);
136 }
137 bail!("found unsorted dirmap at {:?} ({} <= {})", path, dirmap[i].0, dirmap[i-1].0);
138 }
139
140 }
141 }
142
143 for (name, router) in dirmap.iter() {
144 let sub_path = format!("{}/{}", path, name);
145 verify_router(&sub_path, router)?;
146 }
147
148 Ok(())
149 }
150
151 fn verify_router(path: &str, router: &Router) -> Result<(), Error> {
152
153 println!("Verify {}", path);
154
155 if let Some(api_method) = router.get {
156 verify_api_method("GET", path, api_method)?;
157 }
158 if let Some(api_method) = router.put {
159 verify_api_method("PUT", path, api_method)?;
160 }
161 if let Some(api_method) = router.post {
162 verify_api_method("POST", path, api_method)?;
163 }
164 if let Some(api_method) = router.delete {
165 verify_api_method("DELETE", path, api_method)?;
166 }
167
168 match router.subroute {
169 Some(SubRoute::Map(dirmap)) => {
170 verify_dirmap(path, dirmap)?;
171 }
172 Some(SubRoute::MatchAll { router, param_name }) => {
173 let path = format!("{}/{{{}}}", path, param_name);
174 verify_router(&path, router)?;
175 }
176 None => {}
177 }
178
179 Ok(())
180 }
181
182 #[test]
183 fn verify_backup_api() -> Result<(), Error> {
184
185 let api = &api2::backup::BACKUP_API_ROUTER;
186 verify_router("backup-api", api)?;
187
188 Ok(())
189 }
190
191 #[test]
192 fn verify_reader_api() -> Result<(), Error> {
193
194 let api = &api2::reader::READER_API_ROUTER;
195 verify_router("reader-api", api)?;
196
197 Ok(())
198 }
199
200 #[test]
201 fn verify_root_api() -> Result<(), Error> {
202
203 let api = &api2::ROUTER;
204 verify_router("root", api)?;
205
206 Ok(())
207 }