1#[derive(Deserialize, Debug)]
2pub struct InitiateMultipartUploadResponse {
3 #[serde(rename = "Bucket")]
4 _bucket: String,
5 #[serde(rename = "Key")]
6 pub key: String,
7 #[serde(rename = "UploadId")]
8 pub upload_id: String,
9}
10
11#[derive(Deserialize, Debug, Clone)]
13pub struct Owner {
14 #[serde(rename = "DisplayName")]
15 pub display_name: Option<String>,
17 #[serde(rename = "ID")]
18 pub id: String,
20}
21
22#[derive(Deserialize, Debug)]
50pub struct GetObjectAttributesOutput {
51 #[serde(rename = "ETag")]
52 pub etag: String,
53 #[serde(rename = "Checksum")]
54 pub checksum: Checksum,
55 #[serde(rename = "ObjectParts")]
56 pub object_parts: ObjectParts,
57 #[serde(rename = "StorageClass")]
58 pub storage_class: String,
59 #[serde(rename = "ObjectSize")]
60 pub object_size: u64,
61}
62
63#[derive(Deserialize, Debug)]
64pub struct Checksum {
65 #[serde(rename = "ChecksumCRC32")]
66 pub checksum_crc32: String,
67 #[serde(rename = "ChecksumCRC32C")]
68 pub checksum_crc32c: String,
69 #[serde(rename = "ChecksumSHA1")]
70 pub checksum_sha1: String,
71 #[serde(rename = "ChecksumSHA256")]
72 pub checksum_sha256: String,
73}
74
75#[derive(Deserialize, Debug)]
76pub struct ObjectParts {
77 #[serde(rename = "IsTruncated")]
78 pub is_truncated: bool,
79 #[serde(rename = "MaxParts")]
80 pub max_parts: i32,
81 #[serde(rename = "NextPartNumberMarker")]
82 pub next_part_number_marker: i32,
83 #[serde(rename = "PartNumberMarker")]
84 pub part_number_marker: i32,
85 #[serde(rename = "Part")]
86 pub part: Vec<AttributesPart>,
87 #[serde(rename = "PartsCount")]
88 pub parts_count: u64,
89}
90
91#[derive(Deserialize, Debug)]
92pub struct AttributesPart {
93 #[serde(rename = "ChecksumCRC32")]
94 pub checksum_crc32: String,
95 #[serde(rename = "ChecksumCRC32C")]
96 pub checksum_crc32c: String,
97 #[serde(rename = "ChecksumSHA1")]
98 pub checksum_sha1: String,
99 #[serde(rename = "ChecksumSHA256")]
100 pub checksum_sha256: String,
101 #[serde(rename = "PartNumber")]
102 pub part_number: i32,
103 #[serde(rename = "Size")]
104 pub size: u64,
105}
106
107#[derive(Deserialize, Debug, Clone)]
109pub struct Object {
110 #[serde(rename = "LastModified")]
111 pub last_modified: String,
113 #[serde(rename = "ETag")]
114 pub e_tag: Option<String>,
117 #[serde(rename = "StorageClass")]
118 pub storage_class: Option<String>,
120 #[serde(rename = "Key")]
121 pub key: String,
123 #[serde(rename = "Owner")]
124 pub owner: Option<Owner>,
126 #[serde(rename = "Size")]
127 pub size: u64,
129}
130
131#[derive(Deserialize, Debug, Clone)]
133pub struct MultipartUpload {
134 #[serde(rename = "Initiated")]
135 pub initiated: String,
137 #[serde(rename = "StorageClass")]
138 pub storage_class: String,
140 #[serde(rename = "Key")]
141 pub key: String,
143 #[serde(rename = "Owner")]
144 pub owner: Option<Owner>,
146 #[serde(rename = "UploadId")]
147 pub id: String,
149}
150
151use std::fmt::{self};
152
153impl fmt::Display for CompleteMultipartUploadData {
154 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
155 let mut parts = String::new();
156 for part in self.parts.clone() {
157 parts.push_str(&part.to_string())
158 }
159 write!(
160 f,
161 "<CompleteMultipartUpload>{}</CompleteMultipartUpload>",
162 parts
163 )
164 }
165}
166
167impl CompleteMultipartUploadData {
168 pub fn len(&self) -> usize {
169 self.to_string().len()
170 }
171
172 pub fn is_empty(&self) -> bool {
173 self.to_string().len() == 0
174 }
175}
176
177#[derive(Debug, Clone)]
178pub struct CompleteMultipartUploadData {
179 pub parts: Vec<Part>,
180}
181
182#[derive(Debug, Clone, Serialize)]
183pub struct Part {
184 #[serde(rename = "PartNumber")]
185 pub part_number: u32,
186 #[serde(rename = "ETag")]
187 pub etag: String,
188}
189
190impl fmt::Display for Part {
191 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
192 write!(f, "<Part>").expect("Can't fail");
193 write!(f, "<PartNumber>{}</PartNumber>", self.part_number).expect("Can't fail");
194 write!(f, "<ETag>{}</ETag>", self.etag).expect("Can't fail");
195 write!(f, "</Part>")
196 }
197}
198
199#[derive(Deserialize, Debug, Clone)]
200pub struct BucketLocationResult {
201 #[serde(rename = "$value")]
202 pub region: String,
203}
204
205#[derive(Deserialize, Debug, Clone)]
209pub struct ListBucketResult {
210 #[serde(rename = "Name")]
211 pub name: String,
213 #[serde(rename = "Delimiter")]
214 pub delimiter: Option<String>,
216 #[serde(rename = "MaxKeys")]
217 pub max_keys: Option<i32>,
219 #[serde(rename = "Prefix")]
220 pub prefix: Option<String>,
222 #[serde(rename = "ContinuationToken")] #[serde(alias = "Marker")] pub continuation_token: Option<String>,
227 #[serde(rename = "EncodingType")]
228 pub encoding_type: Option<String>,
230 #[serde(
231 default,
232 rename = "IsTruncated",
233 deserialize_with = "super::deserializer::bool_deserializer"
234 )]
235 pub is_truncated: bool,
244 #[serde(rename = "NextContinuationToken", default)] #[serde(alias = "NextMarker")] pub next_continuation_token: Option<String>,
247 #[serde(rename = "Contents", default)]
248 pub contents: Vec<Object>,
250 #[serde(rename = "CommonPrefixes", default)]
251 pub common_prefixes: Option<Vec<CommonPrefix>>,
254}
255
256#[derive(Deserialize, Debug, Clone)]
258pub struct ListMultipartUploadsResult {
259 #[serde(rename = "Bucket")]
260 pub name: String,
262 #[serde(rename = "NextKeyMarker")]
263 pub next_marker: Option<String>,
268 #[serde(rename = "Prefix")]
269 pub prefix: Option<String>,
272 #[serde(rename = "KeyMarker")]
273 pub marker: Option<String>,
275 #[serde(rename = "EncodingType")]
276 pub encoding_type: Option<String>,
278 #[serde(
279 rename = "IsTruncated",
280 deserialize_with = "super::deserializer::bool_deserializer"
281 )]
282 pub is_truncated: bool,
286 #[serde(rename = "Upload", default)]
287 pub uploads: Vec<MultipartUpload>,
289 #[serde(rename = "CommonPrefixes", default)]
290 pub common_prefixes: Option<Vec<CommonPrefix>>,
293}
294
295#[derive(Deserialize, Debug, Clone)]
297pub struct CommonPrefix {
298 #[serde(rename = "Prefix")]
299 pub prefix: String,
301}
302
303#[derive(Deserialize, Debug, Default, Clone)]
305pub struct HeadObjectResult {
306 #[serde(rename = "AcceptRanges")]
307 pub accept_ranges: Option<String>,
309 #[serde(rename = "CacheControl")]
310 pub cache_control: Option<String>,
312 #[serde(rename = "ContentDisposition")]
313 pub content_disposition: Option<String>,
315 #[serde(rename = "ContentEncoding")]
316 pub content_encoding: Option<String>,
318 #[serde(rename = "ContentLanguage")]
319 pub content_language: Option<String>,
321 #[serde(rename = "ContentLength")]
322 pub content_length: Option<i64>,
324 #[serde(rename = "ContentType")]
325 pub content_type: Option<String>,
327 #[serde(rename = "DeleteMarker")]
328 pub delete_marker: Option<bool>,
330 #[serde(rename = "ETag")]
331 pub e_tag: Option<String>,
333 #[serde(rename = "Expiration")]
334 pub expiration: Option<String>,
337 #[serde(rename = "Expires")]
338 pub expires: Option<String>,
340 #[serde(rename = "LastModified")]
341 pub last_modified: Option<String>,
343 #[serde(rename = "Metadata", default)]
344 pub metadata: Option<::std::collections::HashMap<String, String>>,
346 #[serde(rename = "MissingMeta")]
347 pub missing_meta: Option<i64>,
350 #[serde(rename = "ObjectLockLegalHoldStatus")]
351 pub object_lock_legal_hold_status: Option<String>,
354 #[serde(rename = "ObjectLockMode")]
355 pub object_lock_mode: Option<String>,
357 #[serde(rename = "ObjectLockRetainUntilDate")]
358 pub object_lock_retain_until_date: Option<String>,
361 #[serde(rename = "PartsCount")]
362 pub parts_count: Option<i64>,
364 #[serde(rename = "ReplicationStatus")]
365 pub replication_status: Option<String>,
367 #[serde(rename = "RequestCharged")]
368 pub request_charged: Option<String>,
369 #[serde(rename = "Restore")]
370 pub restore: Option<String>,
373 #[serde(rename = "SseCustomerAlgorithm")]
374 pub sse_customer_algorithm: Option<String>,
376 #[serde(rename = "SseCustomerKeyMd5")]
377 pub sse_customer_key_md5: Option<String>,
379 #[serde(rename = "SsekmsKeyId")]
380 pub ssekms_key_id: Option<String>,
382 #[serde(rename = "ServerSideEncryption")]
383 pub server_side_encryption: Option<String>,
386 #[serde(rename = "StorageClass")]
387 pub storage_class: Option<String>,
389 #[serde(rename = "VersionId")]
390 pub version_id: Option<String>,
392 #[serde(rename = "WebsiteRedirectLocation")]
393 pub website_redirect_location: Option<String>,
395}
396
397#[derive(Deserialize, Debug)]
398pub struct AwsError {
399 #[serde(rename = "Code")]
400 pub code: String,
401 #[serde(rename = "Message")]
402 pub message: String,
403 #[serde(rename = "RequestId")]
404 pub request_id: String,
405}
406
407#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
408#[serde(rename = "CORSConfiguration")]
409pub struct CorsConfiguration {
410 #[serde(rename = "CORSRule")]
411 rules: Vec<CorsRule>,
412}
413
414impl CorsConfiguration {
415 pub fn new(rules: Vec<CorsRule>) -> Self {
416 CorsConfiguration { rules }
417 }
418}
419
420impl fmt::Display for CorsConfiguration {
421 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
422 let cors = quick_xml::se::to_string(&self).map_err(|_| fmt::Error)?;
423 let preamble = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
424 let cors = format!("{}{}", preamble, cors);
425 let cors = cors.replace(
426 "<CORSConfiguration>",
427 "<CORSConfiguration xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">",
428 );
429
430 write!(f, "{}", cors)
431 }
432}
433
434#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
435pub struct CorsRule {
436 #[serde(rename = "AllowedHeader")]
437 #[serde(skip_serializing_if = "Option::is_none")]
438 allowed_headers: Option<Vec<String>>,
439 #[serde(rename = "AllowedMethod")]
440 allowed_methods: Vec<String>,
441 #[serde(rename = "AllowedOrigin")]
442 allowed_origins: Vec<String>,
443 #[serde(rename = "ExposeHeader")]
444 #[serde(skip_serializing_if = "Option::is_none")]
445 expose_headers: Option<Vec<String>>,
446 #[serde(skip_serializing_if = "Option::is_none")]
447 #[serde(rename = "ID")]
448 id: Option<String>,
449 #[serde(rename = "MaxAgeSeconds")]
450 #[serde(skip_serializing_if = "Option::is_none")]
451 max_age_seconds: Option<u32>,
452}
453
454impl CorsRule {
455 pub fn new(
456 allowed_headers: Option<Vec<String>>,
457 allowed_methods: Vec<String>,
458 allowed_origins: Vec<String>,
459 expose_headers: Option<Vec<String>>,
460 id: Option<String>,
461 max_age_seconds: Option<u32>,
462 ) -> Self {
463 Self {
464 allowed_headers,
465 allowed_methods,
466 allowed_origins,
467 expose_headers,
468 id,
469 max_age_seconds,
470 }
471 }
472}
473
474#[derive(Serialize, Deserialize, Clone, Debug)]
475#[serde(rename = "LifecycleConfiguration")]
476pub struct BucketLifecycleConfiguration {
477 #[serde(rename = "Rule")]
478 pub rules: Vec<LifecycleRule>,
479}
480
481impl BucketLifecycleConfiguration {
482 pub fn new(rules: Vec<LifecycleRule>) -> Self {
483 BucketLifecycleConfiguration { rules }
484 }
485}
486
487#[derive(Serialize, Deserialize, Debug, Clone, Default)]
488pub struct LifecycleRule {
489 #[serde(
490 rename = "AbortIncompleteMultipartUpload",
491 skip_serializing_if = "Option::is_none"
492 )]
493 pub abort_incomplete_multipart_upload: Option<AbortIncompleteMultipartUpload>,
494
495 #[serde(rename = "Expiration", skip_serializing_if = "Option::is_none")]
496 pub expiration: Option<Expiration>,
497
498 #[serde(rename = "Filter", skip_serializing_if = "Option::is_none")]
499 pub filter: Option<LifecycleFilter>,
500
501 #[serde(rename = "ID", skip_serializing_if = "Option::is_none")]
502 pub id: Option<String>,
503
504 #[serde(
505 rename = "NoncurrentVersionExpiration",
506 skip_serializing_if = "Option::is_none"
507 )]
508 pub noncurrent_version_expiration: Option<NoncurrentVersionExpiration>,
509
510 #[serde(
511 rename = "NoncurrentVersionTransition",
512 skip_serializing_if = "Option::is_none"
513 )]
514 pub noncurrent_version_transition: Option<Vec<NoncurrentVersionTransition>>,
515
516 #[serde(rename = "Status")]
517 pub status: String,
519
520 #[serde(rename = "Transition", skip_serializing_if = "Option::is_none")]
521 pub transition: Option<Vec<Transition>>,
522}
523
524pub struct LifecycleRuleBuilder {
525 lifecycle_rule: LifecycleRule,
526}
527
528impl LifecycleRule {
529 pub fn builder(status: &str) -> LifecycleRuleBuilder {
530 LifecycleRuleBuilder::new(status)
531 }
532}
533
534impl LifecycleRuleBuilder {
535 pub fn new(status: &str) -> LifecycleRuleBuilder {
536 LifecycleRuleBuilder {
537 lifecycle_rule: LifecycleRule {
538 status: status.to_string(),
539 ..Default::default()
540 },
541 }
542 }
543
544 pub fn abort_incomplete_multipart_upload(
545 mut self,
546 abort_incomplete_multipart_upload: AbortIncompleteMultipartUpload,
547 ) -> LifecycleRuleBuilder {
548 self.lifecycle_rule.abort_incomplete_multipart_upload =
549 Some(abort_incomplete_multipart_upload);
550 self
551 }
552
553 pub fn expiration(mut self, expiration: Expiration) -> LifecycleRuleBuilder {
554 self.lifecycle_rule.expiration = Some(expiration);
555 self
556 }
557
558 pub fn filter(mut self, filter: LifecycleFilter) -> LifecycleRuleBuilder {
559 self.lifecycle_rule.filter = Some(filter);
560 self
561 }
562
563 pub fn id(mut self, id: &str) -> LifecycleRuleBuilder {
564 self.lifecycle_rule.id = Some(id.to_string());
565 self
566 }
567
568 pub fn noncurrent_version_expiration(
569 mut self,
570 noncurrent_version_expiration: NoncurrentVersionExpiration,
571 ) -> LifecycleRuleBuilder {
572 self.lifecycle_rule.noncurrent_version_expiration = Some(noncurrent_version_expiration);
573 self
574 }
575
576 pub fn noncurrent_version_transition(
577 mut self,
578 noncurrent_version_transition: Vec<NoncurrentVersionTransition>,
579 ) -> LifecycleRuleBuilder {
580 self.lifecycle_rule.noncurrent_version_transition = Some(noncurrent_version_transition);
581 self
582 }
583
584 pub fn transition(mut self, transition: Vec<Transition>) -> LifecycleRuleBuilder {
585 self.lifecycle_rule.transition = Some(transition);
586 self
587 }
588
589 pub fn build(self) -> LifecycleRule {
590 self.lifecycle_rule
591 }
592}
593#[derive(Serialize, Deserialize, Debug, Clone)]
594pub struct AbortIncompleteMultipartUpload {
595 #[serde(
596 rename = "DaysAfterInitiation",
597 skip_serializing_if = "Option::is_none"
598 )]
599 pub days_after_initiation: Option<i32>,
600}
601
602impl AbortIncompleteMultipartUpload {
603 pub fn new(days_after_initiation: Option<i32>) -> Self {
604 Self {
605 days_after_initiation,
606 }
607 }
608}
609
610#[derive(Serialize, Deserialize, Debug, Clone, Default)]
611pub struct Expiration {
612 #[serde(rename = "Date", skip_serializing_if = "Option::is_none")]
614 pub date: Option<String>,
615
616 #[serde(rename = "Days", skip_serializing_if = "Option::is_none")]
617 pub days: Option<u32>,
618
619 #[serde(
621 rename = "ExpiredObjectDeleteMarker",
622 skip_serializing_if = "Option::is_none"
623 )]
624 pub expired_object_delete_marker: Option<bool>,
625}
626
627impl Expiration {
628 pub fn new(
629 date: Option<String>,
630 days: Option<u32>,
631 expired_object_delete_marker: Option<bool>,
632 ) -> Self {
633 Self {
634 date,
635 days,
636 expired_object_delete_marker,
637 }
638 }
639}
640
641#[derive(Serialize, Deserialize, Debug, Clone, Default)]
642pub struct LifecycleFilter {
643 #[serde(rename = "And", skip_serializing_if = "Option::is_none")]
644 pub and: Option<And>,
645
646 #[serde(
647 rename = "ObjectSizeGreaterThan",
648 skip_serializing_if = "Option::is_none"
649 )]
650 pub object_size_greater_than: Option<i64>,
651
652 #[serde(rename = "ObjectSizeLessThan", skip_serializing_if = "Option::is_none")]
653 pub object_size_less_than: Option<i64>,
654
655 #[serde(rename = "Prefix", skip_serializing_if = "Option::is_none")]
656 pub prefix: Option<String>,
657
658 #[serde(rename = "Tag", skip_serializing_if = "Option::is_none")]
659 pub tag: Option<Tag>,
660}
661impl LifecycleFilter {
662 pub fn new(
663 and: Option<And>,
664 object_size_greater_than: Option<i64>,
665 object_size_less_than: Option<i64>,
666 prefix: Option<String>,
667 tag: Option<Tag>,
668 ) -> Self {
669 Self {
670 and,
671 object_size_greater_than,
672 object_size_less_than,
673 prefix,
674 tag,
675 }
676 }
677}
678
679#[derive(Serialize, Deserialize, Debug, Clone)]
680pub struct And {
681 #[serde(
682 rename = "ObjectSizeGreaterThan",
683 skip_serializing_if = "Option::is_none"
684 )]
685 pub object_size_greater_than: Option<i64>,
686
687 #[serde(rename = "ObjectSizeLessThan", skip_serializing_if = "Option::is_none")]
688 pub object_size_less_than: Option<i64>,
689
690 #[serde(rename = "Prefix", skip_serializing_if = "Option::is_none")]
691 pub prefix: Option<String>,
692
693 #[serde(rename = "Tag", skip_serializing_if = "Option::is_none")]
694 pub tags: Option<Vec<Tag>>,
695}
696
697impl And {
698 pub fn new(
699 object_size_greater_than: Option<i64>,
700 object_size_less_than: Option<i64>,
701 prefix: Option<String>,
702 tags: Option<Vec<Tag>>,
703 ) -> Self {
704 Self {
705 object_size_greater_than,
706 object_size_less_than,
707 prefix,
708 tags,
709 }
710 }
711}
712
713#[derive(Serialize, Deserialize, Debug, Clone)]
714pub struct Tag {
715 #[serde(rename = "Key")]
716 pub key: String,
717
718 #[serde(rename = "Value")]
719 pub value: String,
720}
721
722impl Tag {
723 pub fn new(key: &str, value: &str) -> Self {
724 Self {
725 key: key.to_string(),
726 value: value.to_string(),
727 }
728 }
729}
730
731#[derive(Serialize, Deserialize, Debug, Clone)]
732pub struct NoncurrentVersionExpiration {
733 #[serde(
734 rename = "NewerNoncurrentVersions",
735 skip_serializing_if = "Option::is_none"
736 )]
737 pub newer_noncurrent_versions: Option<i32>,
738
739 #[serde(rename = "NoncurrentDays", skip_serializing_if = "Option::is_none")]
740 pub noncurrent_days: Option<i32>,
741}
742
743impl NoncurrentVersionExpiration {
744 pub fn new(newer_noncurrent_versions: Option<i32>, noncurrent_days: Option<i32>) -> Self {
745 NoncurrentVersionExpiration {
746 newer_noncurrent_versions,
747 noncurrent_days,
748 }
749 }
750}
751
752#[derive(Serialize, Deserialize, Debug, Clone)]
753pub struct NoncurrentVersionTransition {
754 #[serde(
755 rename = "NewerNoncurrentVersions",
756 skip_serializing_if = "Option::is_none"
757 )]
758 pub newer_noncurrent_versions: Option<i32>,
759
760 #[serde(rename = "NoncurrentDays", skip_serializing_if = "Option::is_none")]
761 pub noncurrent_days: Option<i32>,
762
763 #[serde(rename = "StorageClass", skip_serializing_if = "Option::is_none")]
764 pub storage_class: Option<String>,
766}
767
768impl NoncurrentVersionTransition {
769 pub fn new(
770 newer_noncurrent_versions: Option<i32>,
771 noncurrent_days: Option<i32>,
772 storage_class: Option<String>,
773 ) -> Self {
774 NoncurrentVersionTransition {
775 newer_noncurrent_versions,
776 noncurrent_days,
777 storage_class,
778 }
779 }
780}
781
782#[derive(Serialize, Deserialize, Debug, Clone)]
783pub struct Transition {
784 #[serde(rename = "Date", skip_serializing_if = "Option::is_none")]
785 pub date: Option<String>,
786
787 #[serde(rename = "Days", skip_serializing_if = "Option::is_none")]
788 pub days: Option<u32>,
789 #[serde(rename = "StorageClass")]
791 pub storage_class: Option<String>,
792}
793
794impl Transition {
795 pub fn new(date: Option<String>, days: Option<u32>, storage_class: Option<String>) -> Self {
796 Transition {
797 date,
798 days,
799 storage_class,
800 }
801 }
802}
803
804#[cfg(test)]
805mod test {
806 use crate::serde_types::{
807 AbortIncompleteMultipartUpload, BucketLifecycleConfiguration, Expiration, LifecycleFilter,
808 LifecycleRule, NoncurrentVersionExpiration, NoncurrentVersionTransition, Transition,
809 };
810
811 use super::{CorsConfiguration, CorsRule};
812
813 #[test]
814 fn cors_config_serde() {
815 let rule = CorsRule {
816 allowed_headers: Some(vec!["Authorization".to_string(), "Header2".to_string()]),
817 allowed_methods: vec!["GET".to_string(), "DELETE".to_string()],
818 allowed_origins: vec!["*".to_string()],
819 expose_headers: None,
820 id: Some("lala".to_string()),
821 max_age_seconds: None,
822 };
823
824 let config = CorsConfiguration {
825 rules: vec![rule.clone(), rule],
826 };
827
828 let se = quick_xml::se::to_string(&config).unwrap();
829 assert_eq!(
830 se,
831 r#"<CORSConfiguration><CORSRule><AllowedHeader>Authorization</AllowedHeader><AllowedHeader>Header2</AllowedHeader><AllowedMethod>GET</AllowedMethod><AllowedMethod>DELETE</AllowedMethod><AllowedOrigin>*</AllowedOrigin><ID>lala</ID></CORSRule><CORSRule><AllowedHeader>Authorization</AllowedHeader><AllowedHeader>Header2</AllowedHeader><AllowedMethod>GET</AllowedMethod><AllowedMethod>DELETE</AllowedMethod><AllowedOrigin>*</AllowedOrigin><ID>lala</ID></CORSRule></CORSConfiguration>"#
832 )
833 }
834
835 #[test]
836 fn lifecycle_config_serde() {
837 let rule = LifecycleRule {
838 abort_incomplete_multipart_upload: Some(AbortIncompleteMultipartUpload {
839 days_after_initiation: Some(30),
840 }),
841 expiration: Some(Expiration {
842 date: Some("2024-06-017".to_string()),
843 days: Some(30),
844 expired_object_delete_marker: Some(true),
845 }),
846 filter: Some(LifecycleFilter {
847 and: None,
848 object_size_greater_than: Some(10),
849 object_size_less_than: Some(50),
850 prefix: None,
851 tag: None,
852 }),
853 id: Some("lala".to_string()),
854 noncurrent_version_expiration: Some(NoncurrentVersionExpiration {
855 newer_noncurrent_versions: Some(30),
856 noncurrent_days: Some(30),
857 }),
858 noncurrent_version_transition: Some(vec![NoncurrentVersionTransition {
859 newer_noncurrent_versions: Some(30),
860 noncurrent_days: Some(30),
861 storage_class: Some("GLACIER".to_string()),
862 }]),
863 status: "Enabled".to_string(),
864 transition: Some(vec![Transition {
865 date: Some("2024-06-017".to_string()),
866 days: Some(30),
867 storage_class: Some("GLACIER".to_string()),
868 }]),
869 };
870
871 let config = BucketLifecycleConfiguration { rules: vec![rule] };
872
873 let se = quick_xml::se::to_string(&config).unwrap();
874 assert_eq!(
875 se,
876 r#"<LifecycleConfiguration><Rule><AbortIncompleteMultipartUpload><DaysAfterInitiation>30</DaysAfterInitiation></AbortIncompleteMultipartUpload><Expiration><Date>2024-06-017</Date><Days>30</Days><ExpiredObjectDeleteMarker>true</ExpiredObjectDeleteMarker></Expiration><Filter><ObjectSizeGreaterThan>10</ObjectSizeGreaterThan><ObjectSizeLessThan>50</ObjectSizeLessThan></Filter><ID>lala</ID><NoncurrentVersionExpiration><NewerNoncurrentVersions>30</NewerNoncurrentVersions><NoncurrentDays>30</NoncurrentDays></NoncurrentVersionExpiration><NoncurrentVersionTransition><NewerNoncurrentVersions>30</NewerNoncurrentVersions><NoncurrentDays>30</NoncurrentDays><StorageClass>GLACIER</StorageClass></NoncurrentVersionTransition><Status>Enabled</Status><Transition><Date>2024-06-017</Date><Days>30</Days><StorageClass>GLACIER</StorageClass></Transition></Rule></LifecycleConfiguration>"#
877 )
878 }
879}