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