aliyun_oss/operations/
service.rs1use std::sync::Arc;
4
5use crate::client::OSSClient;
6use crate::error::{ErrorContext, OssError, OssErrorKind, Result};
7use crate::http::client::HttpRequest;
8
9pub struct ListBucketsBuilder {
10 client: Arc<crate::client::OSSClientInner>,
11}
12
13impl ListBucketsBuilder {
14 pub(crate) fn new(client: Arc<crate::client::OSSClientInner>) -> Self {
15 Self { client }
16 }
17
18 pub async fn send(self) -> Result<crate::types::response::ListBucketsOutput> {
19 let endpoint = self.client.endpoint.clone();
20 let uri = format!("https://{}", endpoint);
21
22 let request = HttpRequest::builder()
23 .method(http::Method::GET)
24 .uri(&uri)
25 .build();
26
27 let response = self
28 .client
29 .send_signed(request, None, Vec::new())
30 .await
31 .map_err(|e| OssError {
32 kind: OssErrorKind::TransportError,
33 context: Box::new(ErrorContext {
34 operation: Some("ListBuckets".into()),
35 endpoint: Some(endpoint),
36 ..Default::default()
37 }),
38 source: Some(Box::new(e)),
39 })?;
40
41 if response.is_success() {
42 let body_str = response.body_as_str().unwrap_or("");
43 Ok(crate::util::xml::from_xml(body_str)?)
44 } else {
45 Err(OssError {
46 kind: OssErrorKind::ServiceError(Box::new(crate::error::OssServiceError {
47 status_code: response.status().as_u16(),
48 code: String::new(),
49 message: String::new(),
50 request_id: String::new(),
51 host_id: String::new(),
52 resource: None,
53 string_to_sign: None,
54 })),
55 context: Box::new(ErrorContext {
56 operation: Some("ListBuckets".into()),
57 ..Default::default()
58 }),
59 source: None,
60 })
61 }
62 }
63}
64
65impl OSSClient {
66 pub fn list_buckets(&self) -> ListBucketsBuilder {
67 ListBucketsBuilder::new(self.inner().clone())
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use std::str::FromStr;
74 use std::sync::Mutex;
75
76 use crate::client::OSSClientInner;
77 use crate::config::credentials::Credentials;
78 use crate::http::client::{HttpClient, HttpRequest, HttpResponse};
79 use crate::types::region::Region;
80
81 use super::*;
82
83 struct RecordingHttpClient {
84 requests: Arc<Mutex<Vec<HttpRequest>>>,
85 }
86
87 #[async_trait::async_trait]
88 impl HttpClient for RecordingHttpClient {
89 async fn send(&self, request: HttpRequest) -> crate::error::Result<HttpResponse> {
90 self.requests.lock().unwrap().push(request);
91 let mut headers = http::HeaderMap::new();
92 headers.insert(
93 "x-oss-request-id",
94 http::HeaderValue::from_static("rid-svc"),
95 );
96 Ok(HttpResponse {
97 status: http::StatusCode::OK,
98 headers,
99 body: bytes::Bytes::from(
100 r#"<?xml version="1.0" encoding="UTF-8"?><ListAllMyBucketsResult><Owner><ID>owner-id</ID></Owner><Buckets></Buckets></ListAllMyBucketsResult>"#,
101 ),
102 })
103 }
104 }
105
106 fn create_test_inner() -> (Arc<OSSClientInner>, Arc<Mutex<Vec<HttpRequest>>>) {
107 let requests = Arc::new(Mutex::new(Vec::new()));
108 let http = Arc::new(RecordingHttpClient {
109 requests: requests.clone(),
110 });
111 let credentials = Arc::new(crate::config::credentials::StaticCredentialsProvider::new(
112 Credentials::builder()
113 .access_key_id("test-ak")
114 .access_key_secret("test-sk")
115 .build()
116 .unwrap(),
117 ));
118 let inner = Arc::new(OSSClientInner {
119 http,
120 credentials,
121 signer: Arc::from(crate::signer::create_signer(crate::signer::SignVersion::V4)),
122 region: Region::CnHangzhou,
123 endpoint: "oss-cn-hangzhou.aliyuncs.com".into(),
124 });
125 (inner, requests)
126 }
127
128 #[tokio::test]
129 async fn list_buckets_sends_get_request() {
130 let (inner, requests) = create_test_inner();
131 let builder = ListBucketsBuilder::new(inner);
132
133 builder.send().await.unwrap();
134
135 let captured = requests.lock().unwrap();
136 assert_eq!(captured[0].method, http::Method::GET);
137 }
138
139 #[tokio::test]
140 #[ignore = "requires valid OSS credentials"]
141 async fn e2e_list_buckets() {
142 let ak = std::env::var("OSS_ACCESS_KEY_ID").expect("OSS_ACCESS_KEY_ID not set");
143 let sk = std::env::var("OSS_ACCESS_KEY_SECRET").expect("OSS_ACCESS_KEY_SECRET not set");
144 let region_str = std::env::var("OSS_REGION").unwrap_or_else(|_| "cn-wulanchabu".into());
145
146 let region = Region::from_str(®ion_str).unwrap_or_else(|_| Region::Custom {
147 endpoint: format!("oss-{}.aliyuncs.com", region_str),
148 region_id: region_str.clone(),
149 });
150
151 let client = crate::client::OSSClient::builder()
152 .region(region)
153 .credentials(ak, sk)
154 .build()
155 .unwrap();
156
157 let output = client.list_buckets().send().await.unwrap();
158 assert!(!output.owner.id.is_empty());
159 eprintln!(
160 "ListBuckets: {} buckets, owner={}",
161 output.buckets.bucket.len(),
162 output.owner.id
163 );
164 }
165}