aws_lite_rs/api/
cloudfront.rs1use crate::{
8 AwsHttpClient, Result,
9 ops::cloudfront::CloudfrontOps,
10 types::cloudfront::{
11 Distribution, DistributionConfig, DistributionList, OriginAccessControl,
12 OriginAccessControlConfig,
13 },
14};
15
16pub struct CloudfrontClient<'a> {
18 ops: CloudfrontOps<'a>,
19}
20
21impl<'a> CloudfrontClient<'a> {
22 pub(crate) fn new(client: &'a AwsHttpClient) -> Self {
24 Self {
25 ops: CloudfrontOps::new(client),
26 }
27 }
28
29 pub async fn list_distributions(&self) -> Result<DistributionList> {
31 self.ops.list_distributions().await
32 }
33
34 pub async fn get_distribution_config(&self, id: &str) -> Result<DistributionConfig> {
36 self.ops.get_distribution_config(id).await
37 }
38
39 pub async fn update_distribution(
41 &self,
42 id: &str,
43 body: &DistributionConfig,
44 ) -> Result<Distribution> {
45 self.ops.update_distribution(id, body).await
46 }
47
48 pub async fn create_origin_access_control(
50 &self,
51 body: &OriginAccessControlConfig,
52 ) -> Result<OriginAccessControl> {
53 self.ops.create_origin_access_control(body).await
54 }
55
56 pub async fn create_distribution(&self, body: &DistributionConfig) -> Result<Distribution> {
58 self.ops.create_distribution(body).await
59 }
60}
61
62#[cfg(test)]
63mod tests {
64 use crate::AwsHttpClient;
65 use crate::mock_client::MockClient;
66 use crate::test_support::cloudfront_mock_helpers::CloudfrontMockHelpers;
67
68 #[tokio::test]
69 async fn list_distributions_returns_parsed_response() {
70 let mut mock = MockClient::new();
71 mock.expect_list_distributions().returning_bytes(
72 b"<DistributionList>\
73 <Marker></Marker>\
74 <MaxItems>100</MaxItems>\
75 <IsTruncated>false</IsTruncated>\
76 <Quantity>1</Quantity>\
77 <Items>\
78 <DistributionSummary>\
79 <Id>E1ABC2DEF3GHIJ</Id>\
80 <ARN>arn:aws:cloudfront::123456789012:distribution/E1ABC2DEF3GHIJ</ARN>\
81 <Status>Deployed</Status>\
82 <DomainName>d111111abcdef8.cloudfront.net</DomainName>\
83 <Origins><Quantity>1</Quantity></Origins>\
84 <DefaultCacheBehavior>\
85 <TargetOriginId>myS3Origin</TargetOriginId>\
86 <ViewerProtocolPolicy>redirect-to-https</ViewerProtocolPolicy>\
87 </DefaultCacheBehavior>\
88 <PriceClass>PriceClass_100</PriceClass>\
89 <Enabled>true</Enabled>\
90 <Comment>Test distribution</Comment>\
91 </DistributionSummary>\
92 </Items>\
93 </DistributionList>"
94 .to_vec(),
95 );
96
97 let client = AwsHttpClient::from_mock(mock);
98 let list = client.cloudfront().list_distributions().await.unwrap();
99
100 assert_eq!(list.quantity, 1);
101 assert!(!list.is_truncated);
102 assert_eq!(list.items.len(), 1);
103
104 let dist = &list.items[0];
105 assert_eq!(dist.id, "E1ABC2DEF3GHIJ");
106 assert_eq!(
107 dist.arn,
108 "arn:aws:cloudfront::123456789012:distribution/E1ABC2DEF3GHIJ"
109 );
110 assert_eq!(dist.status, "Deployed");
111 assert_eq!(dist.domain_name, "d111111abcdef8.cloudfront.net");
112 assert_eq!(dist.price_class, "PriceClass_100");
113 assert!(dist.enabled);
114 assert_eq!(
115 dist.default_cache_behavior.viewer_protocol_policy,
116 "redirect-to-https"
117 );
118 }
119
120 #[tokio::test]
121 async fn list_distributions_empty_returns_zero_items() {
122 let mut mock = MockClient::new();
123 mock.expect_list_distributions().returning_bytes(
124 b"<DistributionList>\
125 <Marker></Marker>\
126 <MaxItems>100</MaxItems>\
127 <IsTruncated>false</IsTruncated>\
128 <Quantity>0</Quantity>\
129 </DistributionList>"
130 .to_vec(),
131 );
132
133 let client = AwsHttpClient::from_mock(mock);
134 let list = client.cloudfront().list_distributions().await.unwrap();
135
136 assert_eq!(list.quantity, 0);
137 assert!(list.items.is_empty());
138 }
139
140 #[tokio::test]
141 async fn get_distribution_config_returns_parsed_response() {
142 let mut mock = MockClient::new();
143 mock.expect_get_distribution_config("E1ABC2DEF3GHIJ")
144 .returning_bytes(
145 b"<DistributionConfig>\
146 <CallerReference>unique-ref-123</CallerReference>\
147 <Origins>\
148 <Quantity>1</Quantity>\
149 <Items>\
150 <Origin>\
151 <Id>myS3Origin</Id>\
152 <DomainName>mybucket.s3.amazonaws.com</DomainName>\
153 </Origin>\
154 </Items>\
155 </Origins>\
156 <DefaultCacheBehavior>\
157 <TargetOriginId>myS3Origin</TargetOriginId>\
158 <ViewerProtocolPolicy>https-only</ViewerProtocolPolicy>\
159 </DefaultCacheBehavior>\
160 <Comment>My CloudFront distribution</Comment>\
161 <Enabled>true</Enabled>\
162 </DistributionConfig>"
163 .to_vec(),
164 );
165
166 let client = AwsHttpClient::from_mock(mock);
167 let config = client
168 .cloudfront()
169 .get_distribution_config("E1ABC2DEF3GHIJ")
170 .await
171 .unwrap();
172
173 assert_eq!(config.caller_reference, "unique-ref-123");
174 assert_eq!(config.comment, "My CloudFront distribution");
175 assert!(config.enabled);
176 assert_eq!(config.origins.quantity, 1);
177 assert_eq!(config.origins.items.len(), 1);
178 assert_eq!(config.origins.items[0].id, "myS3Origin");
179 assert_eq!(
180 config.origins.items[0].domain_name,
181 "mybucket.s3.amazonaws.com"
182 );
183 assert_eq!(
184 config.default_cache_behavior.viewer_protocol_policy,
185 "https-only"
186 );
187 }
188
189 #[tokio::test]
190 async fn get_distribution_config_parses_aliases_default_root_object_viewer_certificate() {
191 let mut mock = MockClient::new();
192 mock.expect_get_distribution_config("E2XYZ3CUSTOM456")
193 .returning_bytes(
194 b"<DistributionConfig>\
195 <CallerReference>ref-with-custom-domain</CallerReference>\
196 <Aliases>\
197 <Quantity>2</Quantity>\
198 <Items>\
199 <CNAME>www.example.com</CNAME>\
200 <CNAME>example.com</CNAME>\
201 </Items>\
202 </Aliases>\
203 <DefaultRootObject>index.html</DefaultRootObject>\
204 <Origins>\
205 <Quantity>1</Quantity>\
206 </Origins>\
207 <DefaultCacheBehavior>\
208 <TargetOriginId>myOrigin</TargetOriginId>\
209 <ViewerProtocolPolicy>redirect-to-https</ViewerProtocolPolicy>\
210 </DefaultCacheBehavior>\
211 <Comment>Custom domain distribution</Comment>\
212 <Enabled>true</Enabled>\
213 <ViewerCertificate>\
214 <ACMCertificateArn>arn:aws:acm:us-east-1:123456789012:certificate/abc123</ACMCertificateArn>\
215 <SSLSupportMethod>sni-only</SSLSupportMethod>\
216 <MinimumProtocolVersion>TLSv1.2_2021</MinimumProtocolVersion>\
217 <CloudFrontDefaultCertificate>false</CloudFrontDefaultCertificate>\
218 </ViewerCertificate>\
219 </DistributionConfig>"
220 .to_vec(),
221 );
222
223 let client = AwsHttpClient::from_mock(mock);
224 let config = client
225 .cloudfront()
226 .get_distribution_config("E2XYZ3CUSTOM456")
227 .await
228 .unwrap();
229
230 let aliases = config.aliases.as_ref().expect("aliases should be present");
232 assert_eq!(aliases.quantity, 2);
233 assert_eq!(aliases.items, vec!["www.example.com", "example.com"]);
234
235 assert_eq!(config.default_root_object.as_deref(), Some("index.html"));
237
238 let vc = config
240 .viewer_certificate
241 .as_ref()
242 .expect("viewer_certificate should be present");
243 assert_eq!(
244 vc.acm_certificate_arn.as_deref(),
245 Some("arn:aws:acm:us-east-1:123456789012:certificate/abc123")
246 );
247 assert_eq!(vc.ssl_support_method.as_deref(), Some("sni-only"));
248 assert_eq!(vc.minimum_protocol_version.as_deref(), Some("TLSv1.2_2021"));
249 assert_eq!(vc.cloud_front_default_certificate, Some(false));
250 }
251
252 #[tokio::test]
253 async fn get_distribution_config_uses_cloudfront_default_cert_when_no_custom_domain() {
254 let mut mock = MockClient::new();
255 mock.expect_get_distribution_config("E3DEFAULT789")
256 .returning_bytes(
257 b"<DistributionConfig>\
258 <CallerReference>ref-default-cert</CallerReference>\
259 <Origins><Quantity>1</Quantity></Origins>\
260 <DefaultCacheBehavior>\
261 <TargetOriginId>origin</TargetOriginId>\
262 <ViewerProtocolPolicy>allow-all</ViewerProtocolPolicy>\
263 </DefaultCacheBehavior>\
264 <Comment></Comment>\
265 <Enabled>true</Enabled>\
266 <ViewerCertificate>\
267 <CloudFrontDefaultCertificate>true</CloudFrontDefaultCertificate>\
268 </ViewerCertificate>\
269 </DistributionConfig>"
270 .to_vec(),
271 );
272
273 let client = AwsHttpClient::from_mock(mock);
274 let config = client
275 .cloudfront()
276 .get_distribution_config("E3DEFAULT789")
277 .await
278 .unwrap();
279
280 assert!(config.aliases.is_none());
282 assert!(config.default_root_object.is_none());
283
284 let vc = config
286 .viewer_certificate
287 .as_ref()
288 .expect("viewer_certificate should be present");
289 assert_eq!(vc.cloud_front_default_certificate, Some(true));
290 assert!(vc.acm_certificate_arn.is_none());
291 assert!(vc.ssl_support_method.is_none());
292 }
293
294 #[tokio::test]
295 async fn create_origin_access_control_returns_parsed_response() {
296 let mut mock = MockClient::new();
297 mock.expect_create_origin_access_control().returning_bytes(
298 b"<OriginAccessControl>\
299 <Id>E1XYZ2ABC3DEFG</Id>\
300 <OriginAccessControlConfig>\
301 <Name>test-oac</Name>\
302 <Description>Test OAC</Description>\
303 <SigningProtocol>sigv4</SigningProtocol>\
304 <SigningBehavior>always</SigningBehavior>\
305 <OriginAccessControlOriginType>s3</OriginAccessControlOriginType>\
306 </OriginAccessControlConfig>\
307 </OriginAccessControl>"
308 .to_vec(),
309 );
310
311 let client = AwsHttpClient::from_mock(mock);
312 let oac_config = crate::types::cloudfront::OriginAccessControlConfig {
313 name: "test-oac".to_string(),
314 description: Some("Test OAC".to_string()),
315 signing_protocol: "sigv4".to_string(),
316 signing_behavior: "always".to_string(),
317 origin_access_control_origin_type: "s3".to_string(),
318 };
319 let oac = client
320 .cloudfront()
321 .create_origin_access_control(&oac_config)
322 .await
323 .unwrap();
324
325 assert_eq!(oac.id, "E1XYZ2ABC3DEFG");
326 let config = oac
327 .origin_access_control_config
328 .as_ref()
329 .expect("OAC config should be present");
330 assert_eq!(config.name, "test-oac");
331 assert_eq!(config.signing_protocol, "sigv4");
332 assert_eq!(config.signing_behavior, "always");
333 assert_eq!(config.origin_access_control_origin_type, "s3");
334 }
335}