Add tests for http functions ()

This commit is contained in:
Mees Delzenne 2023-07-20 14:46:11 +02:00 committed by GitHub
parent cbbde1fae1
commit cacd9a1de9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 491 additions and 34 deletions

135
Cargo.lock generated
View file

@ -70,12 +70,12 @@ dependencies = [
[[package]]
name = "actix-macros"
version = "0.2.3"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "465a6172cf69b960917811022d8f29bc0b7fa1398bc4f78b3c466673db1213b6"
checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb"
dependencies = [
"quote",
"syn 1.0.109",
"syn 2.0.26",
]
[[package]]
@ -379,6 +379,16 @@ version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
[[package]]
name = "assert-json-diff"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12"
dependencies = [
"serde",
"serde_json",
]
[[package]]
name = "assert_fs"
version = "1.0.13"
@ -1110,9 +1120,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.3.16"
version = "4.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74bb1b4028935821b2d6b439bba2e970bdcf740832732437ead910c632e30d7d"
checksum = "5b0827b011f6f8ab38590295339817b0d26f344aa4932c3ced71b45b0c54b4a9"
dependencies = [
"clap_builder",
"clap_derive",
@ -1121,9 +1131,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.3.16"
version = "4.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ae467cbb0111869b765e13882a1dbbd6cb52f58203d8b80c44f667d4dd19843"
checksum = "9441b403be87be858db6a23edb493e7f694761acdc3343d5a0fcaafd304cbc9e"
dependencies = [
"anstream",
"anstyle",
@ -1416,6 +1426,25 @@ version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
[[package]]
name = "deadpool"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "421fe0f90f2ab22016f32a9881be5134fdd71c65298917084b0c7477cbc3856e"
dependencies = [
"async-trait",
"deadpool-runtime",
"num_cpus",
"retain_mut",
"tokio",
]
[[package]]
name = "deadpool-runtime"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eaa37046cc0f6c3cc6090fbdbf73ef0b8ef4cfcc37f6befc0020f63e8cf121e1"
[[package]]
name = "debugid"
version = "0.8.0"
@ -2253,6 +2282,27 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29"
[[package]]
name = "http-types"
version = "2.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e9b187a72d63adbfba487f48095306ac823049cb504ee195541e91c7775f5ad"
dependencies = [
"anyhow",
"async-channel",
"base64 0.13.1",
"futures-lite",
"http",
"infer",
"pin-project-lite",
"rand 0.7.3",
"serde",
"serde_json",
"serde_qs",
"serde_urlencoded",
"url",
]
[[package]]
name = "httparse"
version = "1.8.0"
@ -2446,6 +2496,12 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "infer"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64e9829a50b42bb782c1df523f78d332fe371b10c661e78b7a3c34b0198e9fac"
[[package]]
name = "inferno"
version = "0.11.15"
@ -4313,9 +4369,9 @@ dependencies = [
[[package]]
name = "scopeguard"
version = "1.1.0"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "scrypt"
@ -4385,9 +4441,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73"
[[package]]
name = "serde"
version = "1.0.171"
version = "1.0.173"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9"
checksum = "e91f70896d6720bc714a4a57d22fc91f1db634680e65c8efe13323f1fa38d53f"
dependencies = [
"serde_derive",
]
@ -4413,9 +4469,9 @@ dependencies = [
[[package]]
name = "serde_derive"
version = "1.0.171"
version = "1.0.173"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682"
checksum = "a6250dde8342e0232232be9ca3db7aa40aceb5a3e5dd9bddbc00d99a007cde49"
dependencies = [
"proc-macro2",
"quote",
@ -4424,9 +4480,9 @@ dependencies = [
[[package]]
name = "serde_html_form"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7d9b8af723e4199801a643c622daa7aae8cf4a772dc2b3efcb3a95add6cb91a"
checksum = "cde65b75f2603066b78d6fa239b2c07b43e06ead09435f60554d3912962b4a3c"
dependencies = [
"form_urlencoded",
"indexmap 2.0.0",
@ -4456,6 +4512,17 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_qs"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7715380eec75f029a4ef7de39a9200e0a63823176b759d055b613f5a87df6a6"
dependencies = [
"percent-encoding",
"serde",
"thiserror",
]
[[package]]
name = "serde_urlencoded"
version = "0.7.1"
@ -4690,7 +4757,7 @@ dependencies = [
"axum-server",
"base64 0.21.2",
"bytes",
"clap 4.3.16",
"clap 4.3.17",
"futures 0.3.28",
"futures-util",
"glob",
@ -4810,6 +4877,7 @@ dependencies = [
"uuid",
"wasm-bindgen-futures",
"wasmtimer",
"wiremock",
"ws_stream_wasm",
]
@ -5595,6 +5663,7 @@ dependencies = [
"form_urlencoded",
"idna",
"percent-encoding",
"serde",
]
[[package]]
@ -5946,6 +6015,28 @@ dependencies = [
"winapi",
]
[[package]]
name = "wiremock"
version = "0.5.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6f71803d3a1c80377a06221e0530be02035d5b3e854af56c6ece7ac20ac441d"
dependencies = [
"assert-json-diff",
"async-trait",
"base64 0.21.2",
"deadpool",
"futures 0.3.28",
"futures-timer",
"http-types",
"hyper",
"log",
"once_cell",
"regex",
"serde",
"serde_json",
"tokio",
]
[[package]]
name = "ws_stream_wasm"
version = "0.7.4"
@ -5976,9 +6067,9 @@ dependencies = [
[[package]]
name = "xml-rs"
version = "0.8.15"
version = "0.8.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a56c84a8ccd4258aed21c92f70c0f6dea75356b6892ae27c24139da456f9336"
checksum = "47430998a7b5d499ccee752b41567bc3afc57e1327dc855b1a2aa44ce29b5fa1"
[[package]]
name = "yasna"
@ -5997,18 +6088,18 @@ checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
[[package]]
name = "zstd"
version = "0.12.3+zstd.1.5.2"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76eea132fb024e0e13fd9c2f5d5d595d8a967aa72382ac2f9d39fcc95afd0806"
checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c"
dependencies = [
"zstd-safe",
]
[[package]]
name = "zstd-safe"
version = "6.0.5+zstd.1.5.4"
version = "6.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d56d9e60b4b1758206c238a10165fbcae3ca37b01744e394c463463f6529d23b"
checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581"
dependencies = [
"libc",
"zstd-sys",

View file

@ -124,6 +124,7 @@ temp-dir = "0.1.11"
time = { version = "0.3.23", features = ["serde"] }
tokio = { version = "1.29.1", features = ["macros", "sync", "rt-multi-thread"] }
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
wiremock = "0.5.19"
[target.'cfg(target_arch = "wasm32")'.dependencies]
pharos = "0.5.3"

View file

@ -118,3 +118,146 @@ pub async fn fetch<'js>(
};
Ok(response)
}
#[cfg(test)]
mod test {
use crate::fnc::script::fetch::test::create_test_context;
#[tokio::test]
async fn test_fetch_get() {
use js::{promise::Promise, CatchResultExt};
use wiremock::{
matchers::{header, method, path},
Mock, MockServer, ResponseTemplate,
};
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 server_ref = &server;
create_test_context!(ctx => {
ctx.globals().set("SERVER_URL",server_ref.uri()).unwrap();
ctx.eval::<Promise<()>,_>(r#"
(async () => {
let res = await fetch(SERVER_URL + '/hello',{
headers: {
"some-header": "some-value",
}
});
assert.seq(res.status,200);
let body = await res.text();
assert.seq(body,'some body once told me');
})()
"#).catch(&ctx).unwrap().await.catch(&ctx).unwrap()
})
.await;
server.verify().await;
}
#[tokio::test]
async fn test_fetch_put() {
use js::{promise::Promise, CatchResultExt};
use wiremock::{
matchers::{body_string, header, method, path},
Mock, MockServer, ResponseTemplate,
};
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 server_ref = &server;
create_test_context!(ctx => {
ctx.globals().set("SERVER_URL",server_ref.uri()).unwrap();
ctx.eval::<Promise<()>,_>(r#"
(async () => {
let res = await fetch(SERVER_URL + '/hello',{
method: "PuT",
headers: {
"some-header": "some-value",
},
body: "some text",
});
assert.seq(res.status,201);
assert(res.ok);
let body = await res.text();
assert.seq(body,'some body once told me');
})()
"#).catch(&ctx).unwrap().await.catch(&ctx).unwrap()
})
.await;
server.verify().await;
}
#[tokio::test]
async fn test_fetch_error() {
use js::{promise::Promise, CatchResultExt};
use wiremock::{
matchers::{body_string, header, method, path},
Mock, MockServer, ResponseTemplate,
};
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 server_ref = &server;
create_test_context!(ctx => {
ctx.globals().set("SERVER_URL",server_ref.uri()).unwrap();
ctx.eval::<Promise<()>,_>(r#"
(async () => {
let req = new Request(SERVER_URL + '/hello',{
method: "PROPPATCH",
headers: {
"some-header": "some-value",
},
body: "some text",
})
let res = await fetch(req);
assert.seq(res.status,500);
assert(!res.ok);
let body = await res.json();
assert(body.foo !== undefined, "body.foo not defined");
assert(body.baz !== undefined, "body.foo not defined");
assert.seq(body.foo, "bar");
assert.seq(body.baz, 2);
})()
"#).catch(&ctx).unwrap().await.catch(&ctx).unwrap()
})
.await;
server.verify().await;
}
}

View file

@ -57,21 +57,19 @@ mod test {
crate::fnc::script::fetch::register(&$ctx).unwrap();
$ctx.eval::<(),_>(r"
globalThis.assert = (...arg) => {
arg.forEach(x => {
if (!x) {
throw new Error('assertion failed')
}
})
};
assert.eq = (a,b) => {
if(a != b){
throw new Error(`assertion failed, '${a}' != '${b}'`)
globalThis.assert = (arg, text) => {
if (!arg) {
throw new Error('assertion failed ' + (text ? text : ''))
}
};
assert.seq = (a,b) => {
assert.eq = (a,b, text) => {
if(a != b){
throw new Error(`assertion failed, '${a}' != '${b}'` + (text ? text : ''))
}
};
assert.seq = (a,b, text) => {
if(!(a === b)){
throw new Error(`assertion failed, '${a}' !== '${b}'`)
throw new Error(`assertion failed, '${a}' !== '${b}'` +( text ? text : ''))
}
};
assert.mustThrow = (cb) => {

View file

@ -12,6 +12,7 @@ async fn test_queries(sql: &str, desired_responses: &[&str]) -> Result<(), Error
for (i, r) in response.into_iter().map(|r| r.result).enumerate() {
let v = r?;
if let Some(desired_response) = desired_responses.get(i) {
dbg!(desired_response);
let desired_value = Value::parse(*desired_response);
// If both values are NaN, they are equal from a test PoV
if !desired_value.is_nan() || !v.is_nan() {
@ -5178,3 +5179,226 @@ async fn function_vector_distance_chebyshev() -> Result<(), Error> {
]).await?;
Ok(())
}
#[cfg(feature = "http")]
#[tokio::test]
pub async fn function_http_head() -> Result<(), Error> {
use wiremock::{
matchers::{header, method, path},
Mock, ResponseTemplate,
};
let server = wiremock::MockServer::start().await;
Mock::given(method("HEAD"))
.and(path("/some/path"))
.and(header("user-agent", "SurrealDB"))
.respond_with(ResponseTemplate::new(200))
.expect(1)
.mount(&server)
.await;
test_queries(&format!("RETURN http::head('{}/some/path')", server.uri()), &["NONE"]).await?;
server.verify().await;
Ok(())
}
#[cfg(feature = "http")]
#[tokio::test]
pub async fn function_http_get() -> Result<(), Error> {
use wiremock::{
matchers::{header, method, path},
Mock, ResponseTemplate,
};
let server = wiremock::MockServer::start().await;
Mock::given(method("GET"))
.and(path("/some/path"))
.and(header("user-agent", "SurrealDB"))
.and(header("a-test-header", "with-a-test-value"))
.respond_with(ResponseTemplate::new(200).set_body_string("some text result"))
.expect(1)
.mount(&server)
.await;
let query = format!(
r#"RETURN http::get("{}/some/path",{{ 'a-test-header': 'with-a-test-value'}})"#,
server.uri()
);
test_queries(&query, &["'some text result'"]).await?;
server.verify().await;
Ok(())
}
#[cfg(feature = "http")]
#[tokio::test]
pub async fn function_http_put() -> Result<(), Error> {
use wiremock::{
matchers::{header, method, path},
Mock, ResponseTemplate,
};
let server = wiremock::MockServer::start().await;
Mock::given(method("PUT"))
.and(path("/some/path"))
.and(header("user-agent", "SurrealDB"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"some-response": "some-value"
})))
.expect(1)
.mount(&server)
.await;
let query =
format!(r#"RETURN http::put("{}/some/path",{{ 'some-key': 'some-value' }})"#, server.uri());
test_queries(&query, &[r#"{ "some-response": 'some-value' }"#]).await?;
server.verify().await;
Ok(())
}
#[cfg(feature = "http")]
#[tokio::test]
pub async fn function_http_post() -> Result<(), Error> {
use wiremock::{
matchers::{header, method, path},
Mock, ResponseTemplate,
};
let server = wiremock::MockServer::start().await;
Mock::given(method("POST"))
.and(path("/some/path"))
.and(header("user-agent", "SurrealDB"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"some-response": "some-value"
})))
.expect(1)
.mount(&server)
.await;
let query = format!(
r#"RETURN http::post("{}/some/path",{{ 'some-key': 'some-value' }})"#,
server.uri()
);
test_queries(&query, &[r#"{ "some-response": 'some-value' }"#]).await?;
server.verify().await;
Ok(())
}
#[cfg(feature = "http")]
#[tokio::test]
pub async fn function_http_patch() -> Result<(), Error> {
use wiremock::{
matchers::{header, method, path},
Mock, ResponseTemplate,
};
let server = wiremock::MockServer::start().await;
Mock::given(method("PATCH"))
.and(path("/some/path"))
.and(header("user-agent", "SurrealDB"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"some-response": "some-value"
})))
.expect(1)
.mount(&server)
.await;
let query = format!(
r#"RETURN http::patch("{}/some/path",{{ 'some-key': 'some-value' }})"#,
server.uri()
);
test_queries(&query, &[r#"{ "some-response": 'some-value' }"#]).await?;
server.verify().await;
Ok(())
}
#[cfg(feature = "http")]
#[tokio::test]
pub async fn function_http_delete() -> Result<(), Error> {
use wiremock::{
matchers::{header, method, path},
Mock, ResponseTemplate,
};
let server = wiremock::MockServer::start().await;
Mock::given(method("DELETE"))
.and(path("/some/path"))
.and(header("user-agent", "SurrealDB"))
.and(header("a-test-header", "with-a-test-value"))
.respond_with(ResponseTemplate::new(200).set_body_string("some text result"))
.expect(1)
.mount(&server)
.await;
let query = format!(
r#"RETURN http::delete("{}/some/path",{{ 'a-test-header': 'with-a-test-value'}})"#,
server.uri()
);
test_queries(&query, &["'some text result'"]).await?;
server.verify().await;
Ok(())
}
#[cfg(feature = "http")]
#[tokio::test]
pub async fn function_http_error() -> Result<(), Error> {
use wiremock::{
matchers::{header, method, path},
Mock, ResponseTemplate,
};
let server = wiremock::MockServer::start().await;
Mock::given(method("GET"))
.and(path("/some/path"))
.and(header("user-agent", "SurrealDB"))
.and(header("a-test-header", "with-a-test-value"))
.respond_with(ResponseTemplate::new(500).set_body_string("some text result"))
.expect(1)
.mount(&server)
.await;
let query = format!(
r#"RETURN http::get("{}/some/path",{{ 'a-test-header': 'with-a-test-value'}})"#,
server.uri()
);
let res = test_queries(&query, &["NONE"]).await;
match res {
Err(Error::Http(text)) => {
assert_eq!(text, "Internal Server Error");
}
e => panic!("query didn't return correct response: {:?}", e),
}
server.verify().await;
Ok(())
}
#[cfg(not(feature = "http"))]
#[tokio::test]
pub async fn function_http_disabled() -> Result<(), Error> {
let res = test_queries("RETURN http::head({})", &["NONE"]).await;
assert!(matches!(res, Err(Error::HttpDisabled)));
let res = test_queries("RETURN http::put({})", &["NONE"]).await;
assert!(matches!(res, Err(Error::HttpDisabled)));
let res = test_queries("RETURN http::post({})", &["NONE"]).await;
assert!(matches!(res, Err(Error::HttpDisabled)));
let res = test_queries("RETURN http::patch({})", &["NONE"]).await;
assert!(matches!(res, Err(Error::HttpDisabled)));
let res = test_queries("RETURN http::delete({})", &["NONE"]).await;
assert!(matches!(res, Err(Error::HttpDisabled)));
Ok(())
}