K2V #293
14 changed files with 111 additions and 31 deletions
|
@ -10,7 +10,7 @@ pub fn build_client(instance: &Instance) -> Client {
|
||||||
None,
|
None,
|
||||||
"garage-integ-test",
|
"garage-integ-test",
|
||||||
);
|
);
|
||||||
let endpoint = Endpoint::immutable(instance.uri());
|
let endpoint = Endpoint::immutable(instance.s3_uri());
|
||||||
|
|
||||||
let config = Config::builder()
|
let config = Config::builder()
|
||||||
.region(super::REGION)
|
.region(super::REGION)
|
||||||
|
|
|
@ -17,14 +17,25 @@ use garage_api::signature;
|
||||||
pub struct CustomRequester {
|
pub struct CustomRequester {
|
||||||
key: Key,
|
key: Key,
|
||||||
uri: Uri,
|
uri: Uri,
|
||||||
|
service: &'static str,
|
||||||
client: Client<HttpConnector>,
|
client: Client<HttpConnector>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CustomRequester {
|
impl CustomRequester {
|
||||||
pub fn new(instance: &Instance) -> Self {
|
pub fn new_s3(instance: &Instance) -> Self {
|
||||||
CustomRequester {
|
CustomRequester {
|
||||||
key: instance.key.clone(),
|
key: instance.key.clone(),
|
||||||
uri: instance.uri(),
|
uri: instance.s3_uri(),
|
||||||
|
service: "s3",
|
||||||
|
client: Client::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_k2v(instance: &Instance) -> Self {
|
||||||
|
CustomRequester {
|
||||||
|
key: instance.key.clone(),
|
||||||
|
uri: instance.k2v_uri(),
|
||||||
|
service: "k2v",
|
||||||
client: Client::new(),
|
client: Client::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +43,7 @@ impl CustomRequester {
|
||||||
pub fn builder(&self, bucket: String) -> RequestBuilder<'_> {
|
pub fn builder(&self, bucket: String) -> RequestBuilder<'_> {
|
||||||
RequestBuilder {
|
RequestBuilder {
|
||||||
requester: self,
|
requester: self,
|
||||||
service: "s3",
|
service: self.service,
|
||||||
bucket,
|
bucket,
|
||||||
method: Method::GET,
|
method: Method::GET,
|
||||||
path: String::new(),
|
path: String::new(),
|
||||||
|
@ -112,12 +123,12 @@ impl<'a> RequestBuilder<'a> {
|
||||||
let query = query_param_to_string(&self.query_params);
|
let query = query_param_to_string(&self.query_params);
|
||||||
let (host, path) = if self.vhost_style {
|
let (host, path) = if self.vhost_style {
|
||||||
(
|
(
|
||||||
format!("{}.s3.garage", self.bucket),
|
format!("{}.{}.garage", self.bucket, self.service),
|
||||||
format!("{}{}", self.path, query),
|
format!("{}{}", self.path, query),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
"s3.garage".to_owned(),
|
format!("{}.garage", self.service),
|
||||||
format!("{}/{}{}", self.bucket, self.path, query),
|
format!("{}/{}{}", self.bucket, self.path, query),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
@ -129,7 +140,7 @@ impl<'a> RequestBuilder<'a> {
|
||||||
&now,
|
&now,
|
||||||
&self.requester.key.secret,
|
&self.requester.key.secret,
|
||||||
super::REGION.as_ref(),
|
super::REGION.as_ref(),
|
||||||
"s3",
|
self.service,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let streaming_signer = signer.clone();
|
let streaming_signer = signer.clone();
|
||||||
|
|
|
@ -22,7 +22,9 @@ pub struct Instance {
|
||||||
process: process::Child,
|
process: process::Child,
|
||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
pub key: Key,
|
pub key: Key,
|
||||||
pub api_port: u16,
|
pub s3_port: u16,
|
||||||
|
pub k2v_port: u16,
|
||||||
|
pub web_port: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Instance {
|
impl Instance {
|
||||||
|
@ -58,9 +60,12 @@ rpc_secret = "{secret}"
|
||||||
|
|
||||||
[s3_api]
|
[s3_api]
|
||||||
s3_region = "{region}"
|
s3_region = "{region}"
|
||||||
api_bind_addr = "127.0.0.1:{api_port}"
|
api_bind_addr = "127.0.0.1:{s3_port}"
|
||||||
root_domain = ".s3.garage"
|
root_domain = ".s3.garage"
|
||||||
|
|
||||||
|
[k2v_api]
|
||||||
|
api_bind_addr = "127.0.0.1:{k2v_port}"
|
||||||
|
|
||||||
[s3_web]
|
[s3_web]
|
||||||
bind_addr = "127.0.0.1:{web_port}"
|
bind_addr = "127.0.0.1:{web_port}"
|
||||||
root_domain = ".web.garage"
|
root_domain = ".web.garage"
|
||||||
|
@ -72,10 +77,11 @@ api_bind_addr = "127.0.0.1:{admin_port}"
|
||||||
path = path.display(),
|
path = path.display(),
|
||||||
secret = GARAGE_TEST_SECRET,
|
secret = GARAGE_TEST_SECRET,
|
||||||
region = super::REGION,
|
region = super::REGION,
|
||||||
api_port = port,
|
s3_port = port,
|
||||||
rpc_port = port + 1,
|
k2v_port = port + 1,
|
||||||
web_port = port + 2,
|
rpc_port = port + 2,
|
||||||
admin_port = port + 3,
|
web_port = port + 3,
|
||||||
|
admin_port = port + 4,
|
||||||
);
|
);
|
||||||
fs::write(path.join("config.toml"), config).expect("Could not write garage config file");
|
fs::write(path.join("config.toml"), config).expect("Could not write garage config file");
|
||||||
|
|
||||||
|
@ -88,7 +94,7 @@ api_bind_addr = "127.0.0.1:{admin_port}"
|
||||||
.arg("server")
|
.arg("server")
|
||||||
.stdout(stdout)
|
.stdout(stdout)
|
||||||
.stderr(stderr)
|
.stderr(stderr)
|
||||||
.env("RUST_LOG", "garage=info,garage_api=debug")
|
.env("RUST_LOG", "garage=info,garage_api=trace")
|
||||||
.spawn()
|
.spawn()
|
||||||
.expect("Could not start garage");
|
.expect("Could not start garage");
|
||||||
|
|
||||||
|
@ -96,7 +102,9 @@ api_bind_addr = "127.0.0.1:{admin_port}"
|
||||||
process: child,
|
process: child,
|
||||||
path,
|
path,
|
||||||
key: Key::default(),
|
key: Key::default(),
|
||||||
api_port: port,
|
s3_port: port,
|
||||||
|
k2v_port: port + 1,
|
||||||
|
web_port: port + 3,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,8 +155,14 @@ api_bind_addr = "127.0.0.1:{admin_port}"
|
||||||
String::from_utf8(output.stdout).unwrap()
|
String::from_utf8(output.stdout).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uri(&self) -> http::Uri {
|
pub fn s3_uri(&self) -> http::Uri {
|
||||||
format!("http://127.0.0.1:{api_port}", api_port = self.api_port)
|
format!("http://127.0.0.1:{s3_port}", s3_port = self.s3_port)
|
||||||
|
.parse()
|
||||||
|
.expect("Could not build garage endpoint URI")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn k2v_uri(&self) -> http::Uri {
|
||||||
|
format!("http://127.0.0.1:{k2v_port}", k2v_port = self.k2v_port)
|
||||||
.parse()
|
.parse()
|
||||||
.expect("Could not build garage endpoint URI")
|
.expect("Could not build garage endpoint URI")
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,18 +17,27 @@ pub struct Context {
|
||||||
pub garage: &'static garage::Instance,
|
pub garage: &'static garage::Instance,
|
||||||
pub client: Client,
|
pub client: Client,
|
||||||
pub custom_request: CustomRequester,
|
pub custom_request: CustomRequester,
|
||||||
|
pub k2v: K2VContext,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct K2VContext {
|
||||||
|
pub request: CustomRequester,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
let garage = garage::instance();
|
let garage = garage::instance();
|
||||||
let client = client::build_client(garage);
|
let client = client::build_client(garage);
|
||||||
let custom_request = CustomRequester::new(garage);
|
let custom_request = CustomRequester::new_s3(garage);
|
||||||
|
let k2v_request = CustomRequester::new_k2v(garage);
|
||||||
|
|
||||||
Context {
|
Context {
|
||||||
garage,
|
garage,
|
||||||
client,
|
client,
|
||||||
custom_request,
|
custom_request,
|
||||||
|
k2v: K2VContext {
|
||||||
|
request: k2v_request,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1
src/garage/tests/k2v/mod.rs
Normal file
1
src/garage/tests/k2v/mod.rs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
pub mod simple;
|
43
src/garage/tests/k2v/simple.rs
Normal file
43
src/garage/tests/k2v/simple.rs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use crate::common;
|
||||||
|
use common::custom_requester::BodySignature;
|
||||||
|
|
||||||
|
use hyper::Method;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_simple() {
|
||||||
|
let ctx = common::context();
|
||||||
|
let bucket = ctx.create_bucket("test-k2v-simple");
|
||||||
|
|
||||||
|
let mut query_params = HashMap::new();
|
||||||
|
query_params.insert("sort_key".to_string(), Some("test1".to_string()));
|
||||||
|
|
||||||
|
let res = ctx.k2v.request
|
||||||
|
.builder(bucket.clone())
|
||||||
|
.method(Method::PUT)
|
||||||
|
.path("root".into())
|
||||||
|
.query_params(query_params.clone())
|
||||||
|
.body(b"Hello, world!".to_vec())
|
||||||
|
.body_signature(BodySignature::Classic)
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(res.status(), 200);
|
||||||
|
|
||||||
|
let mut h = HashMap::new();
|
||||||
|
h.insert("accept".to_string(), "application/octet-stream".to_string());
|
||||||
|
|
||||||
|
let res2 = ctx.k2v.request
|
||||||
|
.builder(bucket.clone())
|
||||||
|
.path("root".into())
|
||||||
|
.query_params(query_params.clone())
|
||||||
|
.signed_headers(h)
|
||||||
|
.body_signature(BodySignature::Classic)
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(res2.status(), 200);
|
||||||
|
|
||||||
|
let res2_body = hyper::body::to_bytes(res2.into_body()).await.unwrap().to_vec();
|
||||||
|
assert_eq!(res2_body, b"Hello, world!");
|
||||||
|
}
|
|
@ -3,9 +3,5 @@ mod common;
|
||||||
|
|
||||||
mod admin;
|
mod admin;
|
||||||
mod bucket;
|
mod bucket;
|
||||||
mod list;
|
mod s3;
|
||||||
mod multipart;
|
mod k2v;
|
||||||
mod objects;
|
|
||||||
mod simple;
|
|
||||||
mod streaming_signature;
|
|
||||||
mod website;
|
|
||||||
|
|
6
src/garage/tests/s3/mod.rs
Normal file
6
src/garage/tests/s3/mod.rs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
mod list;
|
||||||
|
mod multipart;
|
||||||
|
mod objects;
|
||||||
|
mod simple;
|
||||||
|
mod streaming_signature;
|
||||||
|
mod website;
|
|
@ -37,7 +37,7 @@ async fn test_website() {
|
||||||
.method("GET")
|
.method("GET")
|
||||||
.uri(format!(
|
.uri(format!(
|
||||||
"http://127.0.0.1:{}/",
|
"http://127.0.0.1:{}/",
|
||||||
common::garage::DEFAULT_PORT + 2
|
ctx.garage.web_port
|
||||||
))
|
))
|
||||||
.header("Host", format!("{}.web.garage", BCKT_NAME))
|
.header("Host", format!("{}.web.garage", BCKT_NAME))
|
||||||
.body(Body::empty())
|
.body(Body::empty())
|
||||||
|
@ -172,7 +172,7 @@ async fn test_website_s3_api() {
|
||||||
.method("GET")
|
.method("GET")
|
||||||
.uri(format!(
|
.uri(format!(
|
||||||
"http://127.0.0.1:{}/site/",
|
"http://127.0.0.1:{}/site/",
|
||||||
common::garage::DEFAULT_PORT + 2
|
ctx.garage.web_port
|
||||||
))
|
))
|
||||||
.header("Host", format!("{}.web.garage", BCKT_NAME))
|
.header("Host", format!("{}.web.garage", BCKT_NAME))
|
||||||
.header("Origin", "https://example.com")
|
.header("Origin", "https://example.com")
|
||||||
|
@ -198,7 +198,7 @@ async fn test_website_s3_api() {
|
||||||
.method("GET")
|
.method("GET")
|
||||||
.uri(format!(
|
.uri(format!(
|
||||||
"http://127.0.0.1:{}/wrong.html",
|
"http://127.0.0.1:{}/wrong.html",
|
||||||
common::garage::DEFAULT_PORT + 2
|
ctx.garage.web_port
|
||||||
))
|
))
|
||||||
.header("Host", format!("{}.web.garage", BCKT_NAME))
|
.header("Host", format!("{}.web.garage", BCKT_NAME))
|
||||||
.body(Body::empty())
|
.body(Body::empty())
|
||||||
|
@ -219,7 +219,7 @@ async fn test_website_s3_api() {
|
||||||
.method("OPTIONS")
|
.method("OPTIONS")
|
||||||
.uri(format!(
|
.uri(format!(
|
||||||
"http://127.0.0.1:{}/site/",
|
"http://127.0.0.1:{}/site/",
|
||||||
common::garage::DEFAULT_PORT + 2
|
ctx.garage.web_port
|
||||||
))
|
))
|
||||||
.header("Host", format!("{}.web.garage", BCKT_NAME))
|
.header("Host", format!("{}.web.garage", BCKT_NAME))
|
||||||
.header("Origin", "https://example.com")
|
.header("Origin", "https://example.com")
|
||||||
|
@ -246,7 +246,7 @@ async fn test_website_s3_api() {
|
||||||
.method("OPTIONS")
|
.method("OPTIONS")
|
||||||
.uri(format!(
|
.uri(format!(
|
||||||
"http://127.0.0.1:{}/site/",
|
"http://127.0.0.1:{}/site/",
|
||||||
common::garage::DEFAULT_PORT + 2
|
ctx.garage.web_port
|
||||||
))
|
))
|
||||||
.header("Host", format!("{}.web.garage", BCKT_NAME))
|
.header("Host", format!("{}.web.garage", BCKT_NAME))
|
||||||
.header("Origin", "https://example.com")
|
.header("Origin", "https://example.com")
|
||||||
|
@ -290,7 +290,7 @@ async fn test_website_s3_api() {
|
||||||
.method("OPTIONS")
|
.method("OPTIONS")
|
||||||
.uri(format!(
|
.uri(format!(
|
||||||
"http://127.0.0.1:{}/site/",
|
"http://127.0.0.1:{}/site/",
|
||||||
common::garage::DEFAULT_PORT + 2
|
ctx.garage.web_port
|
||||||
))
|
))
|
||||||
.header("Host", format!("{}.web.garage", BCKT_NAME))
|
.header("Host", format!("{}.web.garage", BCKT_NAME))
|
||||||
.header("Origin", "https://example.com")
|
.header("Origin", "https://example.com")
|
||||||
|
@ -321,7 +321,7 @@ async fn test_website_s3_api() {
|
||||||
.method("GET")
|
.method("GET")
|
||||||
.uri(format!(
|
.uri(format!(
|
||||||
"http://127.0.0.1:{}/site/",
|
"http://127.0.0.1:{}/site/",
|
||||||
common::garage::DEFAULT_PORT + 2
|
ctx.garage.web_port
|
||||||
))
|
))
|
||||||
.header("Host", format!("{}.web.garage", BCKT_NAME))
|
.header("Host", format!("{}.web.garage", BCKT_NAME))
|
||||||
.body(Body::empty())
|
.body(Body::empty())
|
Loading…
Reference in a new issue