Skip to content

Commit 87a495a

Browse files
committed
update tests
1 parent 64bb990 commit 87a495a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+555
-232
lines changed

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ async-std = { version = "1.13.1", features = ["attributes", "tokio1"] }
6262
clap = { version = "4.5.35", features = ["derive"] }
6363
quickcheck = "1.0.3"
6464
criterion = "0.5.1"
65-
test-tag = "0.1.4"
6665

6766
[lib]
6867
name = "minio"

common/src/cleanup_guard.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ impl Drop for CleanupGuard {
5858
Ok(_) => {
5959
//println!("Bucket {} removed successfully", bucket_name),
6060
}
61-
Err(e) => println!("Error removing bucket {}: {:?}", bucket_name, e),
61+
Err(_e) => {
62+
//println!("Error removing bucket {}: {:?}", bucket_name, e)
63+
}
6264
},
6365
Err(_) => println!("Timeout after 60s while removing bucket {}", bucket_name),
6466
}

common/src/example.rs

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@
1616
use chrono::{DateTime, Utc};
1717
use minio::s3::builders::PostPolicy;
1818
use minio::s3::types::{
19-
AndOperator, Destination, Filter, LifecycleConfig, LifecycleRule, NotificationConfig,
20-
ObjectLockConfig, PrefixFilterRule, QueueConfig, ReplicationConfig, ReplicationRule,
21-
RetentionMode, SuffixFilterRule,
19+
AndOperator, CsvInputSerialization, CsvOutputSerialization, Destination, FileHeaderInfo,
20+
Filter, LifecycleConfig, LifecycleRule, NotificationConfig, ObjectLockConfig, PrefixFilterRule,
21+
QueueConfig, QuoteFields, ReplicationConfig, ReplicationRule, RetentionMode, SelectRequest,
22+
SuffixFilterRule,
2223
};
2324
use minio::s3::utils::utc_now;
2425
use std::collections::HashMap;
@@ -195,3 +196,38 @@ pub fn create_post_policy_example(bucket_name: &str, object_name: &str) -> PostP
195196
.unwrap();
196197
policy
197198
}
199+
/// return (body, data)
200+
pub fn create_select_content_data() -> (String, String) {
201+
let mut data = String::new();
202+
data.push_str("1997,Ford,E350,\"ac, abs, moon\",3000.00\n");
203+
data.push_str("1999,Chevy,\"Venture \"\"Extended Edition\"\"\",,4900.00\n");
204+
data.push_str("1999,Chevy,\"Venture \"\"Extended Edition, Very Large\"\"\",,5000.00\n");
205+
data.push_str("1996,Jeep,Grand Cherokee,\"MUST SELL!\n");
206+
data.push_str("air, moon roof, loaded\",4799.00\n");
207+
let body = String::from("Year,Make,Model,Description,Price\n") + &data;
208+
(body, data)
209+
}
210+
pub fn create_select_content_request() -> SelectRequest {
211+
let request = SelectRequest::new_csv_input_output(
212+
"select * from S3Object",
213+
CsvInputSerialization {
214+
compression_type: None,
215+
allow_quoted_record_delimiter: false,
216+
comments: None,
217+
field_delimiter: None,
218+
file_header_info: Some(FileHeaderInfo::USE),
219+
quote_character: None,
220+
quote_escape_character: None,
221+
record_delimiter: None,
222+
},
223+
CsvOutputSerialization {
224+
field_delimiter: None,
225+
quote_character: None,
226+
quote_escape_character: None,
227+
quote_fields: Some(QuoteFields::ASNEEDED),
228+
record_delimiter: None,
229+
},
230+
)
231+
.unwrap();
232+
request
233+
}

src/s3/builders/append_object.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ impl AppendObjectContent {
227227
.stat_object(&self.bucket, &self.object)
228228
.send()
229229
.await?;
230-
println!("statObjectResponse={:#?}", resp);
230+
//println!("statObjectResponse={:#?}", resp);
231231

232232
let current_file_size = resp.size;
233233

src/s3/client.rs

Lines changed: 84 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use std::fs::File;
1919
use std::io::prelude::*;
2020
use std::mem;
2121
use std::path::{Path, PathBuf};
22-
use std::sync::Arc;
22+
use std::sync::{Arc, OnceLock};
2323

2424
use crate::s3::creds::Provider;
2525
use crate::s3::error::{Error, ErrorResponse};
@@ -28,12 +28,15 @@ use crate::s3::response::*;
2828
use crate::s3::signer::sign_v4_s3;
2929
use crate::s3::utils::{EMPTY_SHA256, Multimap, sha256_hash_sb, to_amz_date, utc_now};
3030

31-
use crate::s3::builders::ComposeSource;
31+
use crate::s3::builders::{BucketExists, ComposeSource};
3232
use crate::s3::segmented_bytes::SegmentedBytes;
3333
use bytes::Bytes;
3434
use dashmap::DashMap;
3535
use hyper::http::Method;
36+
use rand::Rng;
37+
use rand::distributions::Alphanumeric;
3638
use reqwest::Body;
39+
use tokio::task;
3740

3841
mod append_object;
3942
mod bucket_exists;
@@ -186,7 +189,7 @@ impl ClientBuilder {
186189
client: builder.build()?,
187190
base_url: self.base_url,
188191
provider: self.provider,
189-
region_map: Arc::default(),
192+
..Default::default()
190193
})
191194
}
192195
}
@@ -200,7 +203,8 @@ pub struct Client {
200203
client: reqwest::Client,
201204
pub(crate) base_url: BaseUrl,
202205
pub(crate) provider: Option<Arc<Box<(dyn Provider + Send + Sync + 'static)>>>,
203-
pub(crate) region_map: Arc<DashMap<String, String>>,
206+
pub(crate) region_map: DashMap<String, String>,
207+
express: OnceLock<bool>,
204208
}
205209

206210
impl Client {
@@ -234,14 +238,53 @@ impl Client {
234238
.build()
235239
}
236240

241+
/// Returns whether is client uses an AWS host.
237242
pub fn is_aws_host(&self) -> bool {
238243
self.base_url.is_aws_host()
239244
}
240245

246+
/// Returns whether this client is configured to use HTTPS.
241247
pub fn is_secure(&self) -> bool {
242248
self.base_url.https
243249
}
244250

251+
/// Returns whether this client is configured to use the express endpoint and is minio enterprise.
252+
pub fn is_minio_express(self: &Arc<Self>) -> bool {
253+
if self.express.get().is_some() {
254+
self.express.get().unwrap().clone()
255+
} else {
256+
task::block_in_place(|| match tokio::runtime::Runtime::new() {
257+
Ok(rt) => {
258+
let bucket_name: String = rand::thread_rng()
259+
.sample_iter(&Alphanumeric)
260+
.take(20)
261+
.map(char::from)
262+
.collect::<String>()
263+
.to_lowercase();
264+
265+
let express = rt.block_on(async {
266+
match BucketExists::new(self, bucket_name).send().await {
267+
Ok(v) => {
268+
if let Some(server) = v.headers.get("server") {
269+
if let Ok(s) = server.to_str() {
270+
return s == "MinIO Enterprise/S3express";
271+
}
272+
}
273+
}
274+
Err(e) => {
275+
println!("is_express_internal: error: {e}\nassume false");
276+
}
277+
}
278+
false
279+
});
280+
self.express.set(express).unwrap_or_default();
281+
express
282+
}
283+
Err(_) => false,
284+
})
285+
}
286+
}
287+
245288
fn handle_redirect_response(
246289
&self,
247290
status_code: u16,
@@ -297,7 +340,7 @@ impl Client {
297340
return match headers.get("Content-Type") {
298341
Some(v) => match v.to_str() {
299342
Ok(s) => match s.to_lowercase().contains("application/xml") {
300-
true => match ErrorResponse::parse(body) {
343+
true => match ErrorResponse::parse(body, headers) {
301344
Ok(v) => Error::S3Error(v),
302345
Err(e) => e,
303346
},
@@ -349,15 +392,15 @@ impl Client {
349392
_ => return Error::ServerError(status_code),
350393
};
351394

352-
let request_id = match headers.get("x-amz-request-id") {
395+
let request_id: String = match headers.get("x-amz-request-id") {
353396
Some(v) => match v.to_str() {
354397
Ok(s) => s.to_string(),
355398
Err(e) => return Error::StrError(e),
356399
},
357400
_ => String::new(),
358401
};
359402

360-
let host_id = match headers.get("x-amz-id-2") {
403+
let host_id: String = match headers.get("x-amz-id-2") {
361404
Some(v) => match v.to_str() {
362405
Ok(s) => s.to_string(),
363406
Err(e) => return Error::StrError(e),
@@ -366,6 +409,7 @@ impl Client {
366409
};
367410

368411
Error::S3Error(ErrorResponse {
412+
headers,
369413
code,
370414
message,
371415
resource: resource.to_string(),
@@ -376,7 +420,7 @@ impl Client {
376420
})
377421
}
378422

379-
pub async fn do_execute(
423+
async fn execute_internal(
380424
&self,
381425
method: &Method,
382426
region: &str,
@@ -447,6 +491,31 @@ impl Client {
447491
}
448492
}
449493

494+
if false {
495+
let mut header_strings: Vec<String> = headers
496+
.iter_all()
497+
.map(|(k, v)| format!("{}: {}", k, v.join(",")))
498+
.collect();
499+
500+
// Sort headers alphabetically by name
501+
header_strings.sort();
502+
503+
let body_str: String = String::from_utf8(
504+
body.clone()
505+
.unwrap_or(&SegmentedBytes::new())
506+
.to_bytes()
507+
.to_vec(),
508+
)?;
509+
510+
println!(
511+
"S3 request: {} url={:?}; headers={:?}; body={}\n",
512+
method,
513+
url.path,
514+
header_strings.join("; "),
515+
body_str
516+
);
517+
}
518+
450519
if *method == Method::PUT || *method == Method::POST {
451520
let mut bytes_vec = vec![];
452521
if let Some(body) = body {
@@ -461,15 +530,17 @@ impl Client {
461530
}
462531

463532
let resp = req.send().await?;
533+
464534
if resp.status().is_success() {
465535
return Ok(resp);
466536
}
467537

468538
let mut resp = resp;
469539
let status_code = resp.status().as_u16();
470540
let headers: reqwest::header::HeaderMap = mem::take(resp.headers_mut());
541+
471542
let body: Bytes = resp.bytes().await?;
472-
let e = self.get_error_response(
543+
let e: Error = self.get_error_response(
473544
body,
474545
status_code,
475546
headers,
@@ -504,8 +575,8 @@ impl Client {
504575
object_name: &Option<&str>,
505576
data: Option<&SegmentedBytes>,
506577
) -> Result<reqwest::Response, Error> {
507-
let res = self
508-
.do_execute(
578+
let resp: Result<reqwest::Response, Error> = self
579+
.execute_internal(
509580
&method,
510581
region,
511582
headers,
@@ -516,7 +587,7 @@ impl Client {
516587
true,
517588
)
518589
.await;
519-
match res {
590+
match resp {
520591
Ok(r) => return Ok(r),
521592
Err(e) => match e {
522593
Error::S3Error(ref er) => {
@@ -529,7 +600,7 @@ impl Client {
529600
};
530601

531602
// Retry only once on RetryHead error.
532-
self.do_execute(
603+
self.execute_internal(
533604
&method,
534605
region,
535606
headers,

0 commit comments

Comments
 (0)