openstack_sdk/api/compute/v2/flavor/extra_spec/
create.rs1use derive_builder::Builder;
26use http::{HeaderMap, HeaderName, HeaderValue};
27
28use crate::api::rest_endpoint_prelude::*;
29
30use std::borrow::Cow;
31use std::collections::BTreeMap;
32
33#[derive(Builder, Debug, Clone)]
34#[builder(setter(strip_option))]
35pub struct Request<'a> {
36 #[builder(private, setter(into, name = "_extra_specs"))]
40 pub(crate) extra_specs: BTreeMap<Cow<'a, str>, Cow<'a, str>>,
41
42 #[builder(default, setter(into))]
45 flavor_id: Cow<'a, str>,
46
47 #[builder(setter(name = "_headers"), default, private)]
48 _headers: Option<HeaderMap>,
49}
50impl<'a> Request<'a> {
51 pub fn builder() -> RequestBuilder<'a> {
53 RequestBuilder::default()
54 }
55}
56
57impl<'a> RequestBuilder<'a> {
58 pub fn extra_specs<I, K, V>(&mut self, iter: I) -> &mut Self
62 where
63 I: Iterator<Item = (K, V)>,
64 K: Into<Cow<'a, str>>,
65 V: Into<Cow<'a, str>>,
66 {
67 self.extra_specs
68 .get_or_insert_with(BTreeMap::new)
69 .extend(iter.map(|(k, v)| (k.into(), v.into())));
70 self
71 }
72
73 pub fn header<K, V>(&mut self, header_name: K, header_value: V) -> &mut Self
75 where
76 K: Into<HeaderName>,
77 V: Into<HeaderValue>,
78 {
79 self._headers
80 .get_or_insert(None)
81 .get_or_insert_with(HeaderMap::new)
82 .insert(header_name.into(), header_value.into());
83 self
84 }
85
86 pub fn headers<I, T>(&mut self, iter: I) -> &mut Self
88 where
89 I: Iterator<Item = T>,
90 T: Into<(Option<HeaderName>, HeaderValue)>,
91 {
92 self._headers
93 .get_or_insert(None)
94 .get_or_insert_with(HeaderMap::new)
95 .extend(iter.map(Into::into));
96 self
97 }
98}
99
100impl RestEndpoint for Request<'_> {
101 fn method(&self) -> http::Method {
102 http::Method::POST
103 }
104
105 fn endpoint(&self) -> Cow<'static, str> {
106 format!(
107 "flavors/{flavor_id}/os-extra_specs",
108 flavor_id = self.flavor_id.as_ref(),
109 )
110 .into()
111 }
112
113 fn parameters(&self) -> QueryParams<'_> {
114 QueryParams::default()
115 }
116
117 fn body(&self) -> Result<Option<(&'static str, Vec<u8>)>, BodyError> {
118 let mut params = JsonBodyParams::default();
119
120 params.push("extra_specs", serde_json::to_value(&self.extra_specs)?);
121
122 params.into_body()
123 }
124
125 fn service_type(&self) -> ServiceType {
126 ServiceType::Compute
127 }
128
129 fn response_key(&self) -> Option<Cow<'static, str>> {
130 Some("extra_specs".into())
131 }
132
133 fn request_headers(&self) -> Option<&HeaderMap> {
135 self._headers.as_ref()
136 }
137
138 fn api_version(&self) -> Option<ApiVersion> {
140 Some(ApiVersion::new(2, 1))
141 }
142}
143
144#[cfg(test)]
145mod tests {
146 use super::*;
147 #[cfg(feature = "sync")]
148 use crate::api::Query;
149 use crate::test::client::FakeOpenStackClient;
150 use crate::types::ServiceType;
151 use http::{HeaderName, HeaderValue};
152 use httpmock::MockServer;
153 use serde_json::json;
154
155 #[test]
156 fn test_service_type() {
157 assert_eq!(
158 Request::builder()
159 .extra_specs(BTreeMap::<String, String>::new().into_iter())
160 .build()
161 .unwrap()
162 .service_type(),
163 ServiceType::Compute
164 );
165 }
166
167 #[test]
168 fn test_response_key() {
169 assert_eq!(
170 Request::builder()
171 .extra_specs(BTreeMap::<String, String>::new().into_iter())
172 .build()
173 .unwrap()
174 .response_key()
175 .unwrap(),
176 "extra_specs"
177 );
178 }
179
180 #[cfg(feature = "sync")]
181 #[test]
182 fn endpoint() {
183 let server = MockServer::start();
184 let client = FakeOpenStackClient::new(server.base_url());
185 let mock = server.mock(|when, then| {
186 when.method(httpmock::Method::POST).path(format!(
187 "/flavors/{flavor_id}/os-extra_specs",
188 flavor_id = "flavor_id",
189 ));
190
191 then.status(200)
192 .header("content-type", "application/json")
193 .json_body(json!({ "extra_specs": {} }));
194 });
195
196 let endpoint = Request::builder()
197 .flavor_id("flavor_id")
198 .extra_specs(BTreeMap::<String, String>::new().into_iter())
199 .build()
200 .unwrap();
201 let _: serde_json::Value = endpoint.query(&client).unwrap();
202 mock.assert();
203 }
204
205 #[cfg(feature = "sync")]
206 #[test]
207 fn endpoint_headers() {
208 let server = MockServer::start();
209 let client = FakeOpenStackClient::new(server.base_url());
210 let mock = server.mock(|when, then| {
211 when.method(httpmock::Method::POST)
212 .path(format!(
213 "/flavors/{flavor_id}/os-extra_specs",
214 flavor_id = "flavor_id",
215 ))
216 .header("foo", "bar")
217 .header("not_foo", "not_bar");
218 then.status(200)
219 .header("content-type", "application/json")
220 .json_body(json!({ "extra_specs": {} }));
221 });
222
223 let endpoint = Request::builder()
224 .flavor_id("flavor_id")
225 .extra_specs(BTreeMap::<String, String>::new().into_iter())
226 .headers(
227 [(
228 Some(HeaderName::from_static("foo")),
229 HeaderValue::from_static("bar"),
230 )]
231 .into_iter(),
232 )
233 .header(
234 HeaderName::from_static("not_foo"),
235 HeaderValue::from_static("not_bar"),
236 )
237 .build()
238 .unwrap();
239 let _: serde_json::Value = endpoint.query(&client).unwrap();
240 mock.assert();
241 }
242}