mithril_common/
api_version.rs

1//! API Version provider service
2include!(concat!(env!("OUT_DIR"), "/open_api.rs"));
3use anyhow::anyhow;
4use semver::{Version, VersionReq};
5use std::collections::HashMap;
6use std::sync::Arc;
7
8use crate::era::EraChecker;
9use crate::StdResult;
10
11/// API Version provider
12#[derive(Clone)]
13pub struct APIVersionProvider {
14    era_checker: Arc<EraChecker>,
15    open_api_versions: HashMap<OpenAPIFileName, Version>,
16}
17
18impl APIVersionProvider {
19    /// Version provider factory
20    pub fn new(era_checker: Arc<EraChecker>) -> Self {
21        Self {
22            era_checker,
23            open_api_versions: get_open_api_versions_mapping(),
24        }
25    }
26
27    /// Compute the current api version
28    pub fn compute_current_version(&self) -> StdResult<Version> {
29        let current_era = self.era_checker.current_era();
30        let open_api_spec_file_name_default = "openapi.yaml";
31        let open_api_spec_file_name_era = &format!("openapi-{current_era}.yaml");
32        let open_api_version = self
33            .open_api_versions
34            .get(open_api_spec_file_name_era)
35            .unwrap_or(
36                self.open_api_versions
37                    .get(open_api_spec_file_name_default)
38                    .ok_or_else(|| anyhow!("Missing default API version"))?,
39            );
40
41        Ok(open_api_version.clone())
42    }
43
44    /// Compute the current api version requirement
45    pub fn compute_current_version_requirement(&self) -> StdResult<VersionReq> {
46        let version = &self.compute_current_version()?;
47        let version_req = if version.major > 0 {
48            format!("={}", version.major)
49        } else {
50            format!("={}.{}", version.major, version.minor)
51        };
52
53        Ok(VersionReq::parse(&version_req)?)
54    }
55
56    /// Compute all the sorted list of all versions
57    pub fn compute_all_versions_sorted() -> StdResult<Vec<Version>> {
58        let mut versions: Vec<Version> = get_open_api_versions_mapping().into_values().collect();
59        versions.sort();
60        Ok(versions)
61    }
62
63    /// Update open api versions. Test only
64    pub fn update_open_api_versions(
65        &mut self,
66        open_api_versions: HashMap<OpenAPIFileName, Version>,
67    ) {
68        self.open_api_versions = open_api_versions;
69    }
70}
71
72#[cfg(test)]
73mod test {
74    use semver::Version;
75    use std::{collections::HashMap, sync::Arc};
76
77    use crate::{
78        api_version::APIVersionProvider,
79        entities::Epoch,
80        era::{EraChecker, SupportedEra},
81    };
82
83    #[test]
84    fn test_compute_current_version_default() {
85        let era_checker = EraChecker::new(SupportedEra::dummy(), Epoch(1));
86        let mut version_provider = APIVersionProvider::new(Arc::new(era_checker));
87        let mut open_api_versions = HashMap::new();
88        open_api_versions.insert("openapi.yaml".to_string(), Version::new(1, 2, 3));
89        version_provider.update_open_api_versions(open_api_versions);
90        let api_version_provider = Arc::new(version_provider);
91
92        assert_eq!(
93            "1.2.3".to_string(),
94            api_version_provider
95                .compute_current_version()
96                .unwrap()
97                .to_string()
98        )
99    }
100
101    #[test]
102    fn test_compute_current_version_era_specific() {
103        let era_checker = EraChecker::new(SupportedEra::dummy(), Epoch(1));
104        let mut version_provider = APIVersionProvider::new(Arc::new(era_checker));
105        let mut open_api_versions = HashMap::new();
106        open_api_versions.insert("openapi.yaml".to_string(), Version::new(1, 2, 3));
107        open_api_versions.insert(
108            format!("openapi-{}.yaml", SupportedEra::dummy()),
109            Version::new(2, 1, 0),
110        );
111        version_provider.update_open_api_versions(open_api_versions);
112        let api_version_provider = Arc::new(version_provider);
113
114        assert_eq!(
115            "2.1.0".to_string(),
116            api_version_provider
117                .compute_current_version()
118                .unwrap()
119                .to_string()
120        )
121    }
122
123    #[test]
124    fn test_compute_current_version_requirement_beta() {
125        let era_checker = EraChecker::new(SupportedEra::dummy(), Epoch(1));
126        let mut version_provider = APIVersionProvider::new(Arc::new(era_checker));
127        let mut open_api_versions = HashMap::new();
128        open_api_versions.insert("openapi.yaml".to_string(), Version::new(0, 2, 3));
129        version_provider.update_open_api_versions(open_api_versions);
130        let api_version_provider = Arc::new(version_provider);
131
132        assert_eq!(
133            "=0.2".to_string(),
134            api_version_provider
135                .compute_current_version_requirement()
136                .unwrap()
137                .to_string()
138        )
139    }
140
141    #[test]
142    fn test_compute_current_version_requirement_stable() {
143        let era_checker = EraChecker::new(SupportedEra::dummy(), Epoch(1));
144        let mut version_provider = APIVersionProvider::new(Arc::new(era_checker));
145        let mut open_api_versions = HashMap::new();
146        open_api_versions.insert("openapi.yaml".to_string(), Version::new(3, 2, 1));
147        version_provider.update_open_api_versions(open_api_versions);
148        let api_version_provider = Arc::new(version_provider);
149
150        assert_eq!(
151            "=3".to_string(),
152            api_version_provider
153                .compute_current_version_requirement()
154                .unwrap()
155                .to_string()
156        )
157    }
158
159    #[test]
160    fn test_compute_all_versions_sorted() {
161        let all_versions_sorted = APIVersionProvider::compute_all_versions_sorted()
162            .expect("Computing the list of all sorted versions should not fail");
163
164        assert!(!all_versions_sorted.is_empty());
165    }
166}