use std::str::FromStr;
use surrealdb_types::{Value, object};
use wiremock::matchers::{body_string, header, method, path};
use wiremock::{Mock, MockServer, ResponseTemplate};
use crate::dbs::capabilities::{NetTarget, Targets};
use crate::dbs::{Capabilities, Session};
use crate::kvs::Datastore;
#[tokio::test]
async fn test_fetch_get() {
let server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/hello"))
.and(header("some-header", "some-value"))
.respond_with(ResponseTemplate::new(200).set_body_string("some body once told me"))
.expect(1)
.mount(&server)
.await;
let ds = Datastore::builder()
.with_capabilities(Capabilities::all())
.build_with_path("memory")
.await
.unwrap();
let sess = Session::owner();
let sql = format!(
r#"
RETURN function() {{
let res = await fetch('{}/hello',{{
headers: {{
"some-header": "some-value",
}}
}});
let body = await res.text();
return {{ status: res.status, body: body }};
}}
"#,
server.uri()
);
let res = ds.execute(&sql, &sess, None).await;
let res = res.unwrap().remove(0).output().unwrap();
server.verify().await;
assert_eq!(
res,
Value::Object(object! {
body: "some body once told me".to_string(),
status: 200,
}),
"Unexpected result: {:?}",
res
);
}
#[tokio::test]
async fn test_fetch_put() {
let server = MockServer::start().await;
Mock::given(method("PUT"))
.and(path("/hello"))
.and(header("some-header", "some-value"))
.and(body_string("some text"))
.respond_with(ResponseTemplate::new(201).set_body_string("some body once told me"))
.expect(1)
.mount(&server)
.await;
let ds = Datastore::builder()
.with_capabilities(Capabilities::all())
.build_with_path("memory")
.await
.unwrap();
let sess = Session::owner();
let sql = format!(
r#"
RETURN function() {{
let res = await fetch('{}/hello',{{
method: "PuT",
headers: {{
"some-header": "some-value",
}},
body: "some text",
}});
let body = await res.text();
return {{ status: res.status, body: body }};
}}
"#,
server.uri()
);
let res = ds.execute(&sql, &sess, None).await;
let res = res.unwrap().remove(0).output().unwrap();
server.verify().await;
assert_eq!(
res,
Value::Object(object! {
body: "some body once told me".to_string(),
status: 201,
}),
"Unexpected result: {res:?}"
);
}
#[tokio::test]
async fn test_fetch_error() {
let server = MockServer::start().await;
Mock::given(method("PROPPATCH"))
.and(path("/hello"))
.and(header("some-header", "some-value"))
.and(body_string("some text"))
.respond_with(ResponseTemplate::new(500).set_body_json(serde_json::json!({
"foo": "bar",
"baz": 2,
})))
.expect(1)
.mount(&server)
.await;
let ds = Datastore::builder()
.with_capabilities(Capabilities::all())
.build_with_path("memory")
.await
.unwrap();
let sess = Session::owner();
let sql = format!(
r#"
RETURN function() {{
let res = await fetch('{}/hello',{{
method: "PROPPATCH",
headers: {{
"some-header": "some-value",
}},
body: "some text",
}});
let body = await res.json();
return {{ status: res.status, body: body }};
}}
"#,
server.uri()
);
let res = ds.execute(&sql, &sess, None).await;
let res = res.unwrap().remove(0).output().unwrap();
server.verify().await;
assert_eq!(
res,
Value::Object(object! {
body: Value::Object(object! {
baz: 2,
foo: "bar".to_string(),
}),
status: 500,
}),
"Unexpected result: {res:?}",
);
}
#[tokio::test]
async fn test_fetch_denied() {
let server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/hello"))
.and(header("some-header", "some-value"))
.respond_with(ResponseTemplate::new(200).set_body_string("some body once told me"))
.expect(0)
.mount(&server)
.await;
let ds = Datastore::builder()
.with_capabilities(Capabilities::all().without_network_targets(Targets::Some(
[NetTarget::from_str(&server.address().to_string()).unwrap()].into(),
)))
.build_with_path("memory")
.await
.unwrap();
let sess = Session::owner();
let sql = format!(
r#"
RETURN function() {{
let res = await fetch('{}/hello',{{
headers: {{
"some-header": "some-value",
}}
}});
let body = await res.text();
return {{ status: res.status, body: body }};
}}
"#,
server.uri()
);
let res = ds.execute(&sql, &sess, None).await;
let res = res.unwrap().remove(0).output().unwrap_err();
server.verify().await;
assert!(
res.to_string()
.contains(&format!("Access to network target '{}' is not allowed", server.address())),
"Unexpected result: {:?}",
res
);
}