aws_lite_rs/api/
cloudtrail.rs1use crate::{
8 AwsHttpClient, Result,
9 ops::cloudtrail::CloudtrailOps,
10 types::cloudtrail::{
11 DeleteTrailRequest, DeleteTrailResponse, DescribeTrailsRequest, DescribeTrailsResponse,
12 GetEventSelectorsRequest, GetEventSelectorsResponse, GetTrailStatusRequest,
13 GetTrailStatusResponse, UpdateTrailRequest, UpdateTrailResponse,
14 },
15};
16
17pub struct CloudtrailClient<'a> {
19 ops: CloudtrailOps<'a>,
20}
21
22impl<'a> CloudtrailClient<'a> {
23 pub(crate) fn new(client: &'a AwsHttpClient) -> Self {
25 Self {
26 ops: CloudtrailOps::new(client),
27 }
28 }
29
30 pub async fn describe_trails(
32 &self,
33 body: &DescribeTrailsRequest,
34 ) -> Result<DescribeTrailsResponse> {
35 self.ops.describe_trails(body).await
36 }
37
38 pub async fn get_trail_status(
40 &self,
41 body: &GetTrailStatusRequest,
42 ) -> Result<GetTrailStatusResponse> {
43 self.ops.get_trail_status(body).await
44 }
45
46 pub async fn get_event_selectors(
48 &self,
49 body: &GetEventSelectorsRequest,
50 ) -> Result<GetEventSelectorsResponse> {
51 self.ops.get_event_selectors(body).await
52 }
53
54 pub async fn delete_trail(&self, body: &DeleteTrailRequest) -> Result<DeleteTrailResponse> {
56 self.ops.delete_trail(body).await
57 }
58
59 pub async fn update_trail(&self, body: &UpdateTrailRequest) -> Result<UpdateTrailResponse> {
61 self.ops.update_trail(body).await
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68
69 #[tokio::test]
70 async fn describe_trails_returns_trail_list() {
71 let mut mock = crate::MockClient::new();
72 mock.expect_post("/").returning_json(serde_json::json!({
73 "trailList": [
74 {
75 "Name": "my-trail",
76 "TrailARN": "arn:aws:cloudtrail:us-east-1:123456789012:trail/my-trail",
77 "HomeRegion": "us-east-1",
78 "S3BucketName": "my-trail-logs",
79 "IsMultiRegionTrail": true,
80 "IsOrganizationTrail": false,
81 "HasCustomEventSelectors": false,
82 "HasInsightSelectors": false
83 }
84 ]
85 }));
86 let client = crate::AwsHttpClient::from_mock(mock);
87 let result = client
88 .cloudtrail()
89 .describe_trails(&DescribeTrailsRequest::default())
90 .await
91 .unwrap();
92 assert_eq!(result.trail_list.len(), 1);
93 let trail = &result.trail_list[0];
94 assert_eq!(trail.name.as_deref(), Some("my-trail"));
95 assert_eq!(
96 trail.trail_arn.as_deref(),
97 Some("arn:aws:cloudtrail:us-east-1:123456789012:trail/my-trail")
98 );
99 assert_eq!(trail.home_region.as_deref(), Some("us-east-1"));
100 assert_eq!(trail.s3_bucket_name.as_deref(), Some("my-trail-logs"));
101 assert_eq!(trail.is_multi_region_trail, Some(true));
102 }
103
104 #[tokio::test]
105 async fn get_trail_status_returns_logging_state() {
106 let mut mock = crate::MockClient::new();
107 mock.expect_post("/").returning_json(serde_json::json!({
108 "IsLogging": true,
109 "StartLoggingTime": 1700000000.0,
110 "LatestDeliveryTime": 1700001000.0
111 }));
112 let client = crate::AwsHttpClient::from_mock(mock);
113 let result = client
114 .cloudtrail()
115 .get_trail_status(&GetTrailStatusRequest {
116 name: "my-trail".to_string(),
117 })
118 .await
119 .unwrap();
120 assert_eq!(result.is_logging, Some(true));
121 assert_eq!(result.start_logging_time, Some(1700000000.0));
122 assert_eq!(result.latest_delivery_time, Some(1700001000.0));
123 }
124
125 #[tokio::test]
126 async fn update_trail_returns_updated_config() {
127 let mut mock = crate::MockClient::new();
128 mock.expect_post("/").returning_json(serde_json::json!({
129 "Name": "my-trail",
130 "TrailARN": "arn:aws:cloudtrail:us-east-1:123456789012:trail/my-trail",
131 "S3BucketName": "my-trail-logs",
132 "IncludeGlobalServiceEvents": false,
133 "IsMultiRegionTrail": false,
134 "LogFileValidationEnabled": true
135 }));
136 let client = crate::AwsHttpClient::from_mock(mock);
137 let result = client
138 .cloudtrail()
139 .update_trail(&UpdateTrailRequest {
140 name: "my-trail".to_string(),
141 include_global_service_events: Some(false),
142 ..Default::default()
143 })
144 .await
145 .unwrap();
146 assert_eq!(result.name.as_deref(), Some("my-trail"));
147 assert_eq!(
148 result.trail_arn.as_deref(),
149 Some("arn:aws:cloudtrail:us-east-1:123456789012:trail/my-trail")
150 );
151 assert_eq!(result.include_global_service_events, Some(false));
152 assert_eq!(result.log_file_validation_enabled, Some(true));
153 }
154
155 #[tokio::test]
156 async fn delete_trail_returns_empty_response() {
157 let mut mock = crate::MockClient::new();
158 mock.expect_post("/").returning_json(serde_json::json!({}));
159 let client = crate::AwsHttpClient::from_mock(mock);
160 let result = client
161 .cloudtrail()
162 .delete_trail(&DeleteTrailRequest {
163 name: "my-trail".to_string(),
164 })
165 .await;
166 assert!(result.is_ok(), "DeleteTrail should succeed with empty body");
167 }
168
169 #[tokio::test]
170 async fn get_event_selectors_returns_selectors() {
171 let mut mock = crate::MockClient::new();
172 mock.expect_post("/").returning_json(serde_json::json!({
173 "TrailARN": "arn:aws:cloudtrail:us-east-1:123456789012:trail/my-trail",
174 "EventSelectors": [
175 {
176 "ReadWriteType": "All",
177 "IncludeManagementEvents": true,
178 "DataResources": []
179 }
180 ],
181 "AdvancedEventSelectors": []
182 }));
183 let client = crate::AwsHttpClient::from_mock(mock);
184 let result = client
185 .cloudtrail()
186 .get_event_selectors(&GetEventSelectorsRequest {
187 trail_name: "my-trail".to_string(),
188 })
189 .await
190 .unwrap();
191 assert_eq!(
192 result.trail_arn.as_deref(),
193 Some("arn:aws:cloudtrail:us-east-1:123456789012:trail/my-trail")
194 );
195 assert_eq!(result.event_selectors.len(), 1);
196 assert_eq!(
197 result.event_selectors[0].read_write_type.as_deref(),
198 Some("All")
199 );
200 assert_eq!(
201 result.event_selectors[0].include_management_events,
202 Some(true)
203 );
204 assert!(result.advanced_event_selectors.is_empty());
205 }
206}