From 6be3d620b1f507012c86a50a3dfb06908ef8d591 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Thu, 7 Dec 2023 17:46:23 +0100 Subject: [PATCH 1/3] Add runtime test for outbound postgres Signed-off-by: Ryan Levick --- test-components/Cargo.lock | 7 + test-components/Cargo.toml | 2 +- test-components/outbound-postgres/Cargo.toml | 10 ++ test-components/outbound-postgres/README.md | 9 ++ .../outbound-postgres/component.wasm | Bin 0 -> 194518 bytes test-components/outbound-postgres/src/lib.rs | 121 ++++++++++++++++++ .../outbound-postgres-no-permission/error.txt | 1 + .../outbound-postgres-no-permission/spin.toml | 14 ++ .../tests/outbound-postgres/spin.toml | 15 +++ tests/runtime.rs | 5 + 10 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 test-components/outbound-postgres/Cargo.toml create mode 100644 test-components/outbound-postgres/README.md create mode 100755 test-components/outbound-postgres/component.wasm create mode 100644 test-components/outbound-postgres/src/lib.rs create mode 100644 tests/runtime-tests/tests/outbound-postgres-no-permission/error.txt create mode 100644 tests/runtime-tests/tests/outbound-postgres-no-permission/spin.toml create mode 100644 tests/runtime-tests/tests/outbound-postgres/spin.toml diff --git a/test-components/Cargo.lock b/test-components/Cargo.lock index e7f84c0ddc..43232478bc 100644 --- a/test-components/Cargo.lock +++ b/test-components/Cargo.lock @@ -91,6 +91,13 @@ dependencies = [ "helper", ] +[[package]] +name = "outbound-postgres" +version = "0.1.0" +dependencies = [ + "helper", +] + [[package]] name = "outbound-redis" version = "0.1.0" diff --git a/test-components/Cargo.toml b/test-components/Cargo.toml index a091d09184..98f3f96ea6 100644 --- a/test-components/Cargo.toml +++ b/test-components/Cargo.toml @@ -1,3 +1,3 @@ [workspace] -members = ["sqlite", "helper", "outbound-mysql", "outbound-redis", "key-value"] +members = ["*"] resolver = "2" diff --git a/test-components/outbound-postgres/Cargo.toml b/test-components/outbound-postgres/Cargo.toml new file mode 100644 index 0000000000..77fc2aae30 --- /dev/null +++ b/test-components/outbound-postgres/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "outbound-postgres" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +helper = { path = "../helper" } diff --git a/test-components/outbound-postgres/README.md b/test-components/outbound-postgres/README.md new file mode 100644 index 0000000000..713cc7bef4 --- /dev/null +++ b/test-components/outbound-postgres/README.md @@ -0,0 +1,9 @@ +# Outbound PostgreSQL + +Tests the outbound PostgreSQL interface. + +## Expectations + +This test component expects the following to be true: +* It can connect to a PostgreSQL database using the connection string stored in the environment variable `DB_URL` +* It does not have access to a PostgreSQL database at localhost:10000 diff --git a/test-components/outbound-postgres/component.wasm b/test-components/outbound-postgres/component.wasm new file mode 100755 index 0000000000000000000000000000000000000000..042f0f10d2299b4f5d401a6b6f5f0da043fb737e GIT binary patch literal 194518 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

^#(?jwlVhP~||Q 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 literal 0 HcmV?d00001 diff --git a/test-components/outbound-postgres/src/lib.rs b/test-components/outbound-postgres/src/lib.rs new file mode 100644 index 0000000000..f33815f15d --- /dev/null +++ b/test-components/outbound-postgres/src/lib.rs @@ -0,0 +1,121 @@ +use helper::{ensure, ensure_eq, ensure_matches, ensure_ok}; + +use bindings::fermyon::spin2_0_0::{postgres, rdbms_types}; + +helper::define_component!(Component); +const DB_URL_ENV: &str = "DB_URL"; + +impl Component { + fn main() -> Result<(), String> { + ensure_matches!( + postgres::Connection::open("hello"), + Err(postgres::Error::ConnectionFailed(_)) + ); + ensure_matches!( + postgres::Connection::open("localhost:10000"), + Err(postgres::Error::ConnectionFailed(_)) + ); + + let address = ensure_ok!(std::env::var(DB_URL_ENV)); + let conn = ensure_ok!(postgres::Connection::open(&address)); + let rowset = ensure_ok!(test_numeric_types(&conn)); + ensure!(rowset.rows.iter().all(|r| r.len() == 12)); + ensure_matches!(rowset.rows[0][11], rdbms_types::DbValue::Floating64(f) if f == 1.0); + + let rowset = ensure_ok!(test_character_types(&conn)); + ensure!(rowset.rows.iter().all(|r| r.len() == 3)); + ensure!(matches!(rowset.rows[0][0], rdbms_types::DbValue::Str(ref s) if s == "rvarchar")); + + let pid1 = format!("{:?}", ensure_ok!(pg_backend_pid(&conn))); + let pid2 = format!("{:?}", ensure_ok!(pg_backend_pid(&conn))); + ensure_eq!(pid1, pid2); + + Ok(()) + } +} + +fn test_numeric_types(conn: &postgres::Connection) -> Result { + let create_table_sql = r#" + CREATE TEMPORARY TABLE test_numeric_types ( + intid integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + rsmallserial smallserial NOT NULL, + rsmallint smallint NOT NULL, + rint2 int2 NOT NULL, + rserial serial NOT NULL, + rint int NOT NULL, + rint4 int4 NOT NULL, + rbigserial bigserial NOT NULL, + rbigint bigint NOT NULL, + rint8 int8 NOT NULL, + rreal real NOT NULL, + rdouble double precision NOT NULL + ); + "#; + + conn.execute(create_table_sql, &[])?; + + let insert_sql = r#" + INSERT INTO test_numeric_types + (rsmallint, rint2, rint, rint4, rbigint, rint8, rreal, rdouble) + VALUES + (0, 0, 0, 0, 0, 0, 0, 1); + "#; + + conn.execute(insert_sql, &[])?; + + let sql = r#" + SELECT + intid, + rsmallserial, + rsmallint, + rint2, + rserial, + rint, + rint4, + rbigserial, + rbigint, + rint8, + rreal, + rdouble + FROM test_numeric_types; + "#; + + conn.query(sql, &[]) +} + +fn test_character_types(conn: &postgres::Connection) -> Result { + let create_table_sql = r#" + CREATE TEMPORARY TABLE test_character_types ( + rvarchar varchar(40) NOT NULL, + rtext text NOT NULL, + rchar char(10) NOT NULL + ); + "#; + + conn.execute(create_table_sql, &[])?; + + let insert_sql = r#" + INSERT INTO test_character_types + (rvarchar, rtext, rchar) + VALUES + ('rvarchar', 'rtext', 'rchar'); + "#; + + conn.execute(insert_sql, &[])?; + + let sql = r#" + SELECT + rvarchar, rtext, rchar + FROM test_character_types; + "#; + + conn.query(sql, &[]) +} + +fn pg_backend_pid(conn: &postgres::Connection) -> Result { + let sql = "SELECT pg_backend_pid()"; + + let rowset = conn.query(sql, &[])?; + + Ok(rowset.rows[0][0].clone()) +} diff --git a/tests/runtime-tests/tests/outbound-postgres-no-permission/error.txt b/tests/runtime-tests/tests/outbound-postgres-no-permission/error.txt new file mode 100644 index 0000000000..ce02e5aa90 --- /dev/null +++ b/tests/runtime-tests/tests/outbound-postgres-no-permission/error.txt @@ -0,0 +1 @@ +Error::ConnectionFailed("address postgres://spin:spin@postgres:5432/spin_dev is not permitted") \ No newline at end of file diff --git a/tests/runtime-tests/tests/outbound-postgres-no-permission/spin.toml b/tests/runtime-tests/tests/outbound-postgres-no-permission/spin.toml new file mode 100644 index 0000000000..b117c4aff8 --- /dev/null +++ b/tests/runtime-tests/tests/outbound-postgres-no-permission/spin.toml @@ -0,0 +1,14 @@ +spin_manifest_version = 2 + +[application] +name = "outbound-postgres" +authors = ["Fermyon Engineering "] +version = "0.1.0" + +[[trigger.http]] +route = "/" +component = "test" + +[component.test] +source = "{{outbound-postgres}}" +environment = { DB_URL = "postgres://spin:spin@postgres:5432/spin_dev" } diff --git a/tests/runtime-tests/tests/outbound-postgres/spin.toml b/tests/runtime-tests/tests/outbound-postgres/spin.toml new file mode 100644 index 0000000000..109ea22df8 --- /dev/null +++ b/tests/runtime-tests/tests/outbound-postgres/spin.toml @@ -0,0 +1,15 @@ +spin_manifest_version = 2 + +[application] +name = "outbound-postgres" +authors = ["Fermyon Engineering "] +version = "0.1.0" + +[[trigger.http]] +route = "/" +component = "test" + +[component.test] +source = "{{outbound-postgres}}" +allowed_outbound_hosts = ["postgres://postgres:5432"] +environment = { DB_URL = "postgres://spin:spin@postgres:5432/spin_dev" } diff --git a/tests/runtime.rs b/tests/runtime.rs index 1d95133829..8d6ab051f5 100644 --- a/tests/runtime.rs +++ b/tests/runtime.rs @@ -16,6 +16,11 @@ mod runtime_tests { test!(outbound_mysql, "outbound-mysql"); test!(outbound_mysql_no_permission, "outbound-mysql-no-permission"); + test!(outbound_postgres, "outbound-postgres"); + test!( + outbound_postgres_no_permission, + "outbound-postgres-no-permission" + ); test!(outbound_redis, "outbound-redis"); test!(outbound_redis_no_permission, "outbound-redis-no-permission"); test!(sqlite, "sqlite"); From 068a133389b6a7c91ebcd0abc2a8a3933d494609 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Thu, 7 Dec 2023 17:58:01 +0100 Subject: [PATCH 2/3] Remove the outbound postgres and mysql e2e tests These have been replaced by new runtime tests. Signed-off-by: Ryan Levick --- .../tests/outbound-postgres/spin.toml | 2 +- tests/spinup_tests.rs | 10 - .../.cargo/config.toml | 2 - .../http-rust-outbound-mysql/Cargo.lock | 587 ------------------ .../http-rust-outbound-mysql/Cargo.toml | 20 - .../http-rust-outbound-mysql/spin.toml | 15 - .../http-rust-outbound-mysql/src/lib.rs | 237 ------- .../http-rust-outbound-pg/.cargo/config.toml | 2 - .../http-rust-outbound-pg/Cargo.lock | 587 ------------------ .../http-rust-outbound-pg/Cargo.toml | 20 - .../testcases/http-rust-outbound-pg/spin.toml | 15 - .../http-rust-outbound-pg/src/lib.rs | 306 --------- tests/testcases/mod.rs | 111 ---- 13 files changed, 1 insertion(+), 1913 deletions(-) delete mode 100644 tests/testcases/http-rust-outbound-mysql/.cargo/config.toml delete mode 100644 tests/testcases/http-rust-outbound-mysql/Cargo.lock delete mode 100644 tests/testcases/http-rust-outbound-mysql/Cargo.toml delete mode 100644 tests/testcases/http-rust-outbound-mysql/spin.toml delete mode 100644 tests/testcases/http-rust-outbound-mysql/src/lib.rs delete mode 100644 tests/testcases/http-rust-outbound-pg/.cargo/config.toml delete mode 100644 tests/testcases/http-rust-outbound-pg/Cargo.lock delete mode 100644 tests/testcases/http-rust-outbound-pg/Cargo.toml delete mode 100644 tests/testcases/http-rust-outbound-pg/spin.toml delete mode 100644 tests/testcases/http-rust-outbound-pg/src/lib.rs diff --git a/tests/runtime-tests/tests/outbound-postgres/spin.toml b/tests/runtime-tests/tests/outbound-postgres/spin.toml index 109ea22df8..e1976e87e2 100644 --- a/tests/runtime-tests/tests/outbound-postgres/spin.toml +++ b/tests/runtime-tests/tests/outbound-postgres/spin.toml @@ -12,4 +12,4 @@ component = "test" [component.test] source = "{{outbound-postgres}}" allowed_outbound_hosts = ["postgres://postgres:5432"] -environment = { DB_URL = "postgres://spin:spin@postgres:5432/spin_dev" } +environment = { DB_URL = "postgres://postgres:postgres@postgres:5432/spin_dev" } diff --git a/tests/spinup_tests.rs b/tests/spinup_tests.rs index 0bbcee6b99..1211437d9f 100644 --- a/tests/spinup_tests.rs +++ b/tests/spinup_tests.rs @@ -103,16 +103,6 @@ mod spinup_tests { testcases::header_dynamic_env_works(CONTROLLER).await } - #[tokio::test] - async fn http_rust_outbound_mysql_works() { - testcases::http_rust_outbound_mysql_works(CONTROLLER).await - } - - #[tokio::test] - async fn http_rust_outbound_pg_works() { - testcases::http_rust_outbound_pg_works(CONTROLLER).await - } - #[tokio::test] async fn redis_go_works() { testcases::redis_go_works(CONTROLLER).await diff --git a/tests/testcases/http-rust-outbound-mysql/.cargo/config.toml b/tests/testcases/http-rust-outbound-mysql/.cargo/config.toml deleted file mode 100644 index 6b77899cb3..0000000000 --- a/tests/testcases/http-rust-outbound-mysql/.cargo/config.toml +++ /dev/null @@ -1,2 +0,0 @@ -[build] -target = "wasm32-wasi" diff --git a/tests/testcases/http-rust-outbound-mysql/Cargo.lock b/tests/testcases/http-rust-outbound-mysql/Cargo.lock deleted file mode 100644 index 3b45ce0f18..0000000000 --- a/tests/testcases/http-rust-outbound-mysql/Cargo.lock +++ /dev/null @@ -1,587 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "anyhow" -version = "1.0.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" - -[[package]] -name = "async-trait" -version = "0.1.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bitflags" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" - -[[package]] -name = "bytes" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "form_urlencoded" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" - -[[package]] -name = "futures-executor" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" - -[[package]] -name = "futures-macro" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "futures-sink" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" - -[[package]] -name = "futures-task" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" - -[[package]] -name = "futures-util" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "hashbrown" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "http" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-rust-outbound-mysql-test" -version = "0.1.0" -dependencies = [ - "anyhow", - "bytes", - "http", - "spin-sdk", -] - -[[package]] -name = "id-arena" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" - -[[package]] -name = "indexmap" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" -dependencies = [ - "equivalent", - "hashbrown", - "serde", -] - -[[package]] -name = "itoa" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" - -[[package]] -name = "leb128" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" - -[[package]] -name = "log" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" - -[[package]] -name = "memchr" -version = "2.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" - -[[package]] -name = "once_cell" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" - -[[package]] -name = "percent-encoding" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" - -[[package]] -name = "pin-project-lite" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "proc-macro2" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "routefinder" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94f8f99b10dedd317514253dda1fa7c14e344aac96e1f78149a64879ce282aca" -dependencies = [ - "smartcow", - "smartstring", -] - -[[package]] -name = "ryu" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" - -[[package]] -name = "semver" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" - -[[package]] -name = "serde" -version = "1.0.189" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.189" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "serde_json" -version = "1.0.107" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" - -[[package]] -name = "smartcow" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "656fcb1c1fca8c4655372134ce87d8afdf5ec5949ebabe8d314be0141d8b5da2" -dependencies = [ - "smartstring", -] - -[[package]] -name = "smartstring" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" -dependencies = [ - "autocfg", - "static_assertions", - "version_check", -] - -[[package]] -name = "spdx" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b19b32ed6d899ab23174302ff105c1577e45a06b08d4fe0a9dd13ce804bbbf71" -dependencies = [ - "smallvec", -] - -[[package]] -name = "spin-macro" -version = "0.1.0" -dependencies = [ - "anyhow", - "bytes", - "http", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "spin-sdk" -version = "2.1.0-pre0" -dependencies = [ - "anyhow", - "async-trait", - "bytes", - "form_urlencoded", - "futures", - "http", - "once_cell", - "routefinder", - "serde", - "serde_json", - "spin-macro", - "thiserror", - "wit-bindgen", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thiserror" -version = "1.0.49" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.49" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-segmentation" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasm-encoder" -version = "0.35.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca90ba1b5b0a70d3d49473c5579951f3bddc78d47b59256d2f9d4922b150aca" -dependencies = [ - "leb128", -] - -[[package]] -name = "wasm-metadata" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14abc161bfda5b519aa229758b68f2a52b45a12b993808665c857d1a9a00223c" -dependencies = [ - "anyhow", - "indexmap", - "serde", - "serde_derive", - "serde_json", - "spdx", - "wasm-encoder", - "wasmparser", -] - -[[package]] -name = "wasmparser" -version = "0.115.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e06c0641a4add879ba71ccb3a1e4278fd546f76f1eafb21d8f7b07733b547cd5" -dependencies = [ - "indexmap", - "semver", -] - -[[package]] -name = "wit-bindgen" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d92ce0ca6b6074059413a9581a637550c3a740581c854f9847ec293c8aed71" -dependencies = [ - "bitflags", - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen-core" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "565b945ae074886071eccf9cdaf8ccd7b959c2b0d624095bea5fe62003e8b3e0" -dependencies = [ - "anyhow", - "wit-component", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5695ff4e41873ed9ce56d2787e6b5772bdad9e70e2c1d2d160621d1762257f4f" -dependencies = [ - "anyhow", - "heck", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a91835ea4231da1fe7971679d505ba14be7826e192b6357f08465866ef482e08" -dependencies = [ - "anyhow", - "proc-macro2", - "quote", - "syn 2.0.38", - "wit-bindgen-core", - "wit-bindgen-rust", - "wit-component", -] - -[[package]] -name = "wit-component" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e87488b57a08e2cbbd076b325acbe7f8666965af174d69d5929cd373bd54547f" -dependencies = [ - "anyhow", - "bitflags", - "indexmap", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ace9943d89bbf3dbbc71b966da0e7302057b311f36a4ac3d65ddfef17b52cf" -dependencies = [ - "anyhow", - "id-arena", - "indexmap", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", -] diff --git a/tests/testcases/http-rust-outbound-mysql/Cargo.toml b/tests/testcases/http-rust-outbound-mysql/Cargo.toml deleted file mode 100644 index a30ded99a8..0000000000 --- a/tests/testcases/http-rust-outbound-mysql/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "http-rust-outbound-mysql-test" -version = "0.1.0" -edition = "2021" - -[lib] -crate-type = [ "cdylib" ] - -[dependencies] -# Useful crate to handle errors. -anyhow = "1" -# Crate to simplify working with bytes. -bytes = "1" -# General-purpose crate with common HTTP types. -http = "0.2" -# The Spin SDK. -spin-sdk = { path = "../../../sdk/rust" } - - -[workspace] diff --git a/tests/testcases/http-rust-outbound-mysql/spin.toml b/tests/testcases/http-rust-outbound-mysql/spin.toml deleted file mode 100644 index 69ee2de047..0000000000 --- a/tests/testcases/http-rust-outbound-mysql/spin.toml +++ /dev/null @@ -1,15 +0,0 @@ -spin_version = "1" -authors = ["Fermyon Engineering "] -name = "http-rust-outbound-mysql" -trigger = { type = "http" } -version = "0.1.0" - -[[component]] -environment = { DB_URL = "mysql://spin:spin@mysql/spin_dev" } -id = "outbound-mysql" -source = "target/wasm32-wasi/release/http_rust_outbound_mysql_test.wasm" -allowed_outbound_hosts = ["mysql://mysql"] -[component.trigger] -route = "/..." -[component.build] -command = "cargo build --target wasm32-wasi --release" diff --git a/tests/testcases/http-rust-outbound-mysql/src/lib.rs b/tests/testcases/http-rust-outbound-mysql/src/lib.rs deleted file mode 100644 index c203146ef1..0000000000 --- a/tests/testcases/http-rust-outbound-mysql/src/lib.rs +++ /dev/null @@ -1,237 +0,0 @@ -#![allow(dead_code)] -use anyhow::{anyhow, Result}; -use spin_sdk::{ - http_component, - mysql::{self, Decode}, -}; - -// The environment variable set in `spin.toml` that points to the -// address of the Pg server that the component will write to -const DB_URL_ENV: &str = "DB_URL"; - -#[derive(Debug, Clone)] -struct NumericRow { - rtiny: i8, - rsmall: i16, - rmedium: i32, - rint: i32, - rbig: i64, - rfloat: f32, - rdouble: f64, - rutiny: u8, - rusmall: u16, - rumedium: u32, - ruint: u32, - rubig: u64, - rtinyint1: bool, - rbool: bool, -} - -#[derive(Debug, Clone)] -struct CharacterRow { - rvarchar: String, - rtext: String, - rchar: String, - rbinary: Vec, - rvarbinary: Vec, - rblob: Vec, -} - -#[http_component] -fn process(req: http::Request<()>) -> Result> { - match req.uri().path() { - "/test_character_types" => test_character_types(req), - "/test_numeric_types" => test_numeric_types(req), - _ => Ok(http::Response::builder() - .status(404) - .body("Not found".into())?), - } -} - -fn test_numeric_types(_req: http::Request<()>) -> Result> { - let address = std::env::var(DB_URL_ENV)?; - let conn = mysql::Connection::open(&address)?; - - let create_table_sql = r#" - CREATE TEMPORARY TABLE test_numeric_types ( - rtiny TINYINT NOT NULL, - rsmall SMALLINT NOT NULL, - rmedium MEDIUMINT NOT NULL, - rint INT NOT NULL, - rbig BIGINT NOT NULL, - rfloat FLOAT NOT NULL, - rdouble DOUBLE NOT NULL, - rutiny TINYINT UNSIGNED NOT NULL, - rusmall SMALLINT UNSIGNED NOT NULL, - rumedium MEDIUMINT UNSIGNED NOT NULL, - ruint INT UNSIGNED NOT NULL, - rubig BIGINT UNSIGNED NOT NULL, - rtinyint1 TINYINT(1) NOT NULL, - rbool BOOLEAN NOT NULL - ); - "#; - - conn.execute(create_table_sql, &[])?; - - let insert_sql = r#" - INSERT INTO test_numeric_types - (rtiny, rsmall, rmedium, rint, rbig, rfloat, rdouble, rutiny, rusmall, rumedium, ruint, rubig, rtinyint1, rbool) - VALUES - (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1); - "#; - - conn.execute(insert_sql, &[])?; - - let sql = r#" - SELECT - rtiny, - rsmall, - rmedium, - rint, - rbig, - rfloat, - rdouble, - rutiny, - rusmall, - rumedium, - ruint, - rubig, - rtinyint1, - rbool - FROM test_numeric_types; - "#; - - let rowset = conn.query(sql, &[])?; - - let column_summary = rowset - .columns - .iter() - .map(format_col) - .collect::>() - .join(", "); - - let mut response_lines = vec![]; - - for row in rowset.rows { - let rtiny = i8::decode(&row[0])?; - let rsmall = i16::decode(&row[1])?; - let rmedium = i32::decode(&row[2])?; - let rint = i32::decode(&row[3])?; - let rbig = i64::decode(&row[4])?; - let rfloat = f32::decode(&row[5])?; - let rdouble = f64::decode(&row[6])?; - let rutiny = u8::decode(&row[7])?; - let rusmall = u16::decode(&row[8])?; - let rumedium = u32::decode(&row[9])?; - let ruint = u32::decode(&row[10])?; - let rubig = u64::decode(&row[11])?; - let rtinyint1 = bool::decode(&row[12])?; - let rbool = bool::decode(&row[13])?; - - let row = NumericRow { - rtiny, - rsmall, - rmedium, - rint, - rbig, - rfloat, - rdouble, - rutiny, - rusmall, - rumedium, - ruint, - rubig, - rtinyint1, - rbool, - }; - - response_lines.push(format!("row: {:#?}", row)); - } - - let response = format!( - "Found {} rows(s) as follows:\n{}\n\n(Column info: {})\n", - response_lines.len(), - response_lines.join("\n"), - column_summary, - ); - - Ok(http::Response::builder().status(200).body(response)?) -} - -fn test_character_types(_req: http::Request<()>) -> Result> { - let address = std::env::var(DB_URL_ENV)?; - let conn = mysql::Connection::open(&address)?; - - let create_table_sql = r#" - CREATE TEMPORARY TABLE test_character_types ( - rvarchar varchar(40) NOT NULL, - rtext text NOT NULL, - rchar char(10) NOT NULL, - rbinary binary(10) NOT NULL, - rvarbinary varbinary(10) NOT NULL, - rblob BLOB NOT NULL - ); - "#; - - conn.execute(create_table_sql, &[]) - .map_err(|e| anyhow!("Error executing MySQL command: {:?}", e))?; - - let insert_sql = r#" - INSERT INTO test_character_types - (rvarchar, rtext, rchar, rbinary, rvarbinary, rblob) - VALUES - ('rvarchar', 'rtext', 'rchar', 'a', 'a', 'a'); - "#; - - conn.execute(insert_sql, &[])?; - - let sql = r#" - SELECT - rvarchar, rtext, rchar, rbinary, rvarbinary, rblob - FROM test_character_types; - "#; - - let rowset = conn.query(sql, &[])?; - - let column_summary = rowset - .columns - .iter() - .map(format_col) - .collect::>() - .join(", "); - - let mut response_lines = vec![]; - - for row in rowset.rows { - let rvarchar = String::decode(&row[0])?; - let rtext = String::decode(&row[1])?; - let rchar = String::decode(&row[2])?; - let rbinary = Vec::::decode(&row[3])?; - let rvarbinary = Vec::::decode(&row[4])?; - let rblob = Vec::::decode(&row[5])?; - - let row = CharacterRow { - rvarchar, - rtext, - rchar, - rbinary, - rvarbinary, - rblob, - }; - - response_lines.push(format!("row: {:#?}", row)); - } - - let response = format!( - "Found {} rows(s) as follows:\n{}\n\n(Column info: {})\n", - response_lines.len(), - response_lines.join("\n"), - column_summary, - ); - - Ok(http::Response::builder().status(200).body(response)?) -} - -fn format_col(column: &mysql::Column) -> String { - format!("{}: {:?}", column.name, column.data_type) -} diff --git a/tests/testcases/http-rust-outbound-pg/.cargo/config.toml b/tests/testcases/http-rust-outbound-pg/.cargo/config.toml deleted file mode 100644 index 6b77899cb3..0000000000 --- a/tests/testcases/http-rust-outbound-pg/.cargo/config.toml +++ /dev/null @@ -1,2 +0,0 @@ -[build] -target = "wasm32-wasi" diff --git a/tests/testcases/http-rust-outbound-pg/Cargo.lock b/tests/testcases/http-rust-outbound-pg/Cargo.lock deleted file mode 100644 index b05ca3250e..0000000000 --- a/tests/testcases/http-rust-outbound-pg/Cargo.lock +++ /dev/null @@ -1,587 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "anyhow" -version = "1.0.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" - -[[package]] -name = "async-trait" -version = "0.1.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bitflags" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" - -[[package]] -name = "bytes" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "form_urlencoded" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" - -[[package]] -name = "futures-executor" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" - -[[package]] -name = "futures-macro" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "futures-sink" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" - -[[package]] -name = "futures-task" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" - -[[package]] -name = "futures-util" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "hashbrown" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "http" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-rust-outbound-pg" -version = "0.1.0" -dependencies = [ - "anyhow", - "bytes", - "http", - "spin-sdk", -] - -[[package]] -name = "id-arena" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" - -[[package]] -name = "indexmap" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" -dependencies = [ - "equivalent", - "hashbrown", - "serde", -] - -[[package]] -name = "itoa" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" - -[[package]] -name = "leb128" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" - -[[package]] -name = "log" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" - -[[package]] -name = "memchr" -version = "2.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" - -[[package]] -name = "once_cell" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" - -[[package]] -name = "percent-encoding" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" - -[[package]] -name = "pin-project-lite" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "proc-macro2" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "routefinder" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94f8f99b10dedd317514253dda1fa7c14e344aac96e1f78149a64879ce282aca" -dependencies = [ - "smartcow", - "smartstring", -] - -[[package]] -name = "ryu" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" - -[[package]] -name = "semver" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" - -[[package]] -name = "serde" -version = "1.0.189" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.189" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "serde_json" -version = "1.0.107" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" - -[[package]] -name = "smartcow" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "656fcb1c1fca8c4655372134ce87d8afdf5ec5949ebabe8d314be0141d8b5da2" -dependencies = [ - "smartstring", -] - -[[package]] -name = "smartstring" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" -dependencies = [ - "autocfg", - "static_assertions", - "version_check", -] - -[[package]] -name = "spdx" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b19b32ed6d899ab23174302ff105c1577e45a06b08d4fe0a9dd13ce804bbbf71" -dependencies = [ - "smallvec", -] - -[[package]] -name = "spin-macro" -version = "0.1.0" -dependencies = [ - "anyhow", - "bytes", - "http", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "spin-sdk" -version = "2.1.0-pre0" -dependencies = [ - "anyhow", - "async-trait", - "bytes", - "form_urlencoded", - "futures", - "http", - "once_cell", - "routefinder", - "serde", - "serde_json", - "spin-macro", - "thiserror", - "wit-bindgen", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thiserror" -version = "1.0.49" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.49" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-segmentation" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasm-encoder" -version = "0.35.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca90ba1b5b0a70d3d49473c5579951f3bddc78d47b59256d2f9d4922b150aca" -dependencies = [ - "leb128", -] - -[[package]] -name = "wasm-metadata" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14abc161bfda5b519aa229758b68f2a52b45a12b993808665c857d1a9a00223c" -dependencies = [ - "anyhow", - "indexmap", - "serde", - "serde_derive", - "serde_json", - "spdx", - "wasm-encoder", - "wasmparser", -] - -[[package]] -name = "wasmparser" -version = "0.115.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e06c0641a4add879ba71ccb3a1e4278fd546f76f1eafb21d8f7b07733b547cd5" -dependencies = [ - "indexmap", - "semver", -] - -[[package]] -name = "wit-bindgen" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d92ce0ca6b6074059413a9581a637550c3a740581c854f9847ec293c8aed71" -dependencies = [ - "bitflags", - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen-core" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "565b945ae074886071eccf9cdaf8ccd7b959c2b0d624095bea5fe62003e8b3e0" -dependencies = [ - "anyhow", - "wit-component", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5695ff4e41873ed9ce56d2787e6b5772bdad9e70e2c1d2d160621d1762257f4f" -dependencies = [ - "anyhow", - "heck", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a91835ea4231da1fe7971679d505ba14be7826e192b6357f08465866ef482e08" -dependencies = [ - "anyhow", - "proc-macro2", - "quote", - "syn 2.0.38", - "wit-bindgen-core", - "wit-bindgen-rust", - "wit-component", -] - -[[package]] -name = "wit-component" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e87488b57a08e2cbbd076b325acbe7f8666965af174d69d5929cd373bd54547f" -dependencies = [ - "anyhow", - "bitflags", - "indexmap", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ace9943d89bbf3dbbc71b966da0e7302057b311f36a4ac3d65ddfef17b52cf" -dependencies = [ - "anyhow", - "id-arena", - "indexmap", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", -] diff --git a/tests/testcases/http-rust-outbound-pg/Cargo.toml b/tests/testcases/http-rust-outbound-pg/Cargo.toml deleted file mode 100644 index 1032768d31..0000000000 --- a/tests/testcases/http-rust-outbound-pg/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "http-rust-outbound-pg" -version = "0.1.0" -edition = "2021" - -[lib] -crate-type = [ "cdylib" ] - -[dependencies] -# Useful crate to handle errors. -anyhow = "1" -# Crate to simplify working with bytes. -bytes = "1" -# General-purpose crate with common HTTP types. -http = "0.2" -# The Spin SDK. -spin-sdk = { path = "../../../sdk/rust" } - - -[workspace] diff --git a/tests/testcases/http-rust-outbound-pg/spin.toml b/tests/testcases/http-rust-outbound-pg/spin.toml deleted file mode 100644 index 9d98a08d9f..0000000000 --- a/tests/testcases/http-rust-outbound-pg/spin.toml +++ /dev/null @@ -1,15 +0,0 @@ -spin_version = "1" -authors = ["Fermyon Engineering "] -name = "rust-outbound-pg-example" -trigger = { type = "http" } -version = "0.1.0" - -[[component]] -environment = { DB_URL = "host=postgres user=postgres password=postgres dbname=spin_dev" } -id = "outbound-pg" -source = "target/wasm32-wasi/release/http_rust_outbound_pg.wasm" -allowed_outbound_hosts = ["postgres://postgres"] -[component.trigger] -route = "/..." -[component.build] -command = "cargo build --target wasm32-wasi --release" diff --git a/tests/testcases/http-rust-outbound-pg/src/lib.rs b/tests/testcases/http-rust-outbound-pg/src/lib.rs deleted file mode 100644 index dd4fa5d324..0000000000 --- a/tests/testcases/http-rust-outbound-pg/src/lib.rs +++ /dev/null @@ -1,306 +0,0 @@ -#![allow(dead_code)] -use anyhow::Result; -use spin_sdk::{ - http_component, - pg::{self, Decode}, -}; - -// The environment variable set in `spin.toml` that points to the -// address of the Pg server that the component will write to -const DB_URL_ENV: &str = "DB_URL"; - -#[derive(Debug, Clone)] -struct NumericRow { - intid: i32, - rsmallserial: i16, - rsmallint: i16, - rint2: i16, - rserial: i32, - rint: i32, - rint4: i32, - rbigserial: i64, - rbigint: i64, - rint8: i64, - rreal: f32, - rdouble: f64, -} - -#[derive(Debug, Clone)] -struct CharacterRow { - rchar: String, - rvarchar: String, - rtext: String, -} - -#[derive(Debug, Clone)] -struct GeneralRow<'a> { - rbool: bool, - obool: Option, - rbytea: &'a str, -} - -#[http_component] -fn process(req: http::Request<()>) -> Result> { - match req.uri().path() { - "/test_character_types" => test_character_types(req), - "/test_numeric_types" => test_numeric_types(req), - "/test_general_types" => test_general_types(req), - "/pg_backend_pid" => pg_backend_pid(req), - _ => Ok(http::Response::builder() - .status(404) - .body("Not found".into())?), - } -} - -fn test_numeric_types(_req: http::Request<()>) -> Result> { - let address = std::env::var(DB_URL_ENV)?; - let conn = pg::Connection::open(&address)?; - - let create_table_sql = r#" - CREATE TEMPORARY TABLE test_numeric_types ( - intid integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, - rsmallserial smallserial NOT NULL, - rsmallint smallint NOT NULL, - rint2 int2 NOT NULL, - rserial serial NOT NULL, - rint int NOT NULL, - rint4 int4 NOT NULL, - rbigserial bigserial NOT NULL, - rbigint bigint NOT NULL, - rint8 int8 NOT NULL, - rreal real NOT NULL, - rdouble double precision NOT NULL - ); - "#; - - conn.execute(create_table_sql, &[])?; - - let insert_sql = r#" - INSERT INTO test_numeric_types - (rsmallint, rint2, rint, rint4, rbigint, rint8, rreal, rdouble) - VALUES - (0, 0, 0, 0, 0, 0, 0, 0); - "#; - - conn.execute(insert_sql, &[])?; - - let sql = r#" - SELECT - intid, - rsmallserial, - rsmallint, - rint2, - rserial, - rint, - rint4, - rbigserial, - rbigint, - rint8, - rreal, - rdouble - FROM test_numeric_types; - "#; - - let rowset = conn.query(sql, &[])?; - - let column_summary = rowset - .columns - .iter() - .map(format_col) - .collect::>() - .join(", "); - - let mut response_lines = vec![]; - - for row in rowset.rows { - let intid = i32::decode(&row[0])?; - let rsmallserial = i16::decode(&row[1])?; - let rsmallint = i16::decode(&row[2])?; - let rint2 = i16::decode(&row[3])?; - let rserial = i32::decode(&row[4])?; - let rint = i32::decode(&row[5])?; - let rint4 = i32::decode(&row[6])?; - let rbigserial = i64::decode(&row[7])?; - let rbigint = i64::decode(&row[8])?; - let rint8 = i64::decode(&row[9])?; - let rreal = f32::decode(&row[10])?; - let rdouble = f64::decode(&row[11])?; - - let row = NumericRow { - intid, - rsmallserial, - rsmallint, - rint2, - rserial, - rint, - rint4, - rbigserial, - rbigint, - rint8, - rreal, - rdouble, - }; - - response_lines.push(format!("row: {:#?}", row)); - } - - let response = format!( - "Found {} rows(s) as follows:\n{}\n\n(Column info: {})\n", - response_lines.len(), - response_lines.join("\n"), - column_summary, - ); - - Ok(http::Response::builder().status(200).body(response)?) -} - -fn test_character_types(_req: http::Request<()>) -> Result> { - let address = std::env::var(DB_URL_ENV)?; - let conn = pg::Connection::open(&address)?; - - let create_table_sql = r#" - CREATE TEMPORARY TABLE test_character_types ( - rvarchar varchar(40) NOT NULL, - rtext text NOT NULL, - rchar char(10) NOT NULL - ); - "#; - - conn.execute(create_table_sql, &[])?; - - let insert_sql = r#" - INSERT INTO test_character_types - (rvarchar, rtext, rchar) - VALUES - ('rvarchar', 'rtext', 'rchar'); - "#; - - conn.execute(insert_sql, &[])?; - - let sql = r#" - SELECT - rvarchar, rtext, rchar - FROM test_character_types; - "#; - - let rowset = conn.query(sql, &[])?; - - let column_summary = rowset - .columns - .iter() - .map(format_col) - .collect::>() - .join(", "); - - let mut response_lines = vec![]; - - for row in rowset.rows { - let rvarchar = String::decode(&row[0])?; - let rtext = String::decode(&row[1])?; - let rchar = String::decode(&row[2])?; - - let row = CharacterRow { - rvarchar, - rtext, - rchar, - }; - - response_lines.push(format!("row: {:#?}", row)); - } - - let response = format!( - "Found {} rows(s) as follows:\n{}\n\n(Column info: {})\n", - response_lines.len(), - response_lines.join("\n"), - column_summary, - ); - - Ok(http::Response::builder().status(200).body(response)?) -} - -fn test_general_types(_req: http::Request<()>) -> Result> { - let address = std::env::var(DB_URL_ENV)?; - let conn = pg::Connection::open(&address)?; - - let create_table_sql = r#" - CREATE TEMPORARY TABLE test_general_types ( - rbool bool NOT NULL, - obool bool, - rbytea bytea NOT NULL - ); - "#; - - conn.execute(create_table_sql, &[])?; - - let insert_sql = r" - INSERT INTO test_general_types - (rbool, rbytea) - VALUES - (TRUE, '\176'::bytea); - "; - - conn.execute(insert_sql, &[])?; - - let sql = r#" - SELECT - rbool, obool, rbytea - FROM test_general_types; - "#; - - let rowset = conn.query(sql, &[])?; - - let column_summary = rowset - .columns - .iter() - .map(format_col) - .collect::>() - .join(", "); - - let mut response_lines = vec![]; - - for row in rowset.rows { - let rbool = bool::decode(&row[0])?; - let obool = Option::::decode(&row[1])?; - let rbytea = Vec::::decode(&row[2])?; - - let row = GeneralRow { - rbool, - obool, - rbytea: std::str::from_utf8(&rbytea).unwrap(), - }; - - response_lines.push(format!("row: {:#?}", row)); - } - - let response = format!( - "Found {} rows(s) as follows:\n{}\n\n(Column info: {})\n", - response_lines.len(), - response_lines.join("\n"), - column_summary, - ); - - Ok(http::Response::builder().status(200).body(response)?) -} - -fn pg_backend_pid(_req: http::Request<()>) -> Result> { - let address = std::env::var(DB_URL_ENV)?; - let conn = pg::Connection::open(&address)?; - let sql = "SELECT pg_backend_pid()"; - - let get_pid = || { - let rowset = conn.query(sql, &[])?; - - let row = &rowset.rows[0]; - i32::decode(&row[0]) - }; - - assert_eq!(get_pid()?, get_pid()?); - - let response = format!("pg_backend_pid: {}\n", get_pid()?); - - Ok(http::Response::builder().status(200).body(response)?) -} - -fn format_col(column: &pg::Column) -> String { - format!("{}:{:?}", column.name, column.data_type) -} diff --git a/tests/testcases/mod.rs b/tests/testcases/mod.rs index a247d04034..5e40c746b0 100644 --- a/tests/testcases/mod.rs +++ b/tests/testcases/mod.rs @@ -848,52 +848,6 @@ pub async fn header_dynamic_env_works(controller: &dyn Controller) { tc.run(controller).await.unwrap() } -pub async fn http_rust_outbound_mysql_works(controller: &dyn Controller) { - async fn checks( - metadata: AppMetadata, - _: Option>>, - _: Option>>, - ) -> Result<()> { - assert_http_response( - get_url(metadata.base.as_str(), "/test_numeric_types").as_str(), - Method::GET, - "", - 200, - &[], - None, - ) - .await?; - - assert_http_response( - get_url(metadata.base.as_str(), "/test_character_types").as_str(), - Method::GET, - "", - 200, - &[], - None, - ) - .await?; - - Ok(()) - } - - let tc = TestCaseBuilder::default() - .name("http-rust-outbound-mysql".to_string()) - .appname(Some("http-rust-outbound-mysql".to_string())) - .deploy_args(vec!["--env".to_string(), "foo=bar".to_string()]) - .assertions( - |metadata: AppMetadata, - stdout_stream: Option>>, - stderr_stream: Option>>| { - Box::pin(checks(metadata, stdout_stream, stderr_stream)) - }, - ) - .build() - .unwrap(); - - tc.run(controller).await.unwrap() -} - pub async fn redis_go_works(controller: &dyn Controller) { async fn checks( _: AppMetadata, @@ -1011,71 +965,6 @@ pub async fn redis_rust_works(controller: &dyn Controller) { tc.run(controller).await.unwrap() } -pub async fn http_rust_outbound_pg_works(controller: &dyn Controller) { - async fn checks( - metadata: AppMetadata, - _: Option>>, - _: Option>>, - ) -> Result<()> { - assert_http_response( - get_url(metadata.base.as_str(), "/test_numeric_types").as_str(), - Method::GET, - "", - 200, - &[], - None, - ) - .await?; - - assert_http_response( - get_url(metadata.base.as_str(), "/test_character_types").as_str(), - Method::GET, - "", - 200, - &[], - None, - ) - .await?; - - assert_http_response( - get_url(metadata.base.as_str(), "/test_general_types").as_str(), - Method::GET, - "", - 200, - &[], - None, - ) - .await?; - - assert_http_response( - get_url(metadata.base.as_str(), "/pg_backend_pid").as_str(), - Method::GET, - "", - 200, - &[], - None, - ) - .await?; - - Ok(()) - } - - let tc = TestCaseBuilder::default() - .name("http-rust-outbound-pg".to_string()) - .appname(Some("http-rust-outbound-pg".to_string())) - .assertions( - |metadata: AppMetadata, - stdout_stream: Option>>, - stderr_stream: Option>>| { - Box::pin(checks(metadata, stdout_stream, stderr_stream)) - }, - ) - .build() - .unwrap(); - - tc.run(controller).await.unwrap() -} - pub async fn registry_works(controller: &dyn Controller) { async fn checks( metadata: AppMetadata, From dfab4ec353d4d75727f39e8860567613941f60d2 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Mon, 11 Dec 2023 11:56:07 +0100 Subject: [PATCH 3/3] Add nullable test Signed-off-by: Ryan Levick --- .../outbound-postgres/component.wasm | Bin 194518 -> 193873 bytes test-components/outbound-postgres/src/lib.rs | 40 ++++++++++++++++-- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/test-components/outbound-postgres/component.wasm b/test-components/outbound-postgres/component.wasm index 042f0f10d2299b4f5d401a6b6f5f0da043fb737e..a1f1a1df5474479e738e9e1627214597d9489975 100755 GIT binary patch delta 48610 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%0D$IpuS~NU;7nR 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 SHR#i#fZWhmE6wDWg!@lL>hPNY diff --git a/test-components/outbound-postgres/src/lib.rs b/test-components/outbound-postgres/src/lib.rs index f33815f15d..ace6eca6e5 100644 --- a/test-components/outbound-postgres/src/lib.rs +++ b/test-components/outbound-postgres/src/lib.rs @@ -18,14 +18,19 @@ impl Component { let address = ensure_ok!(std::env::var(DB_URL_ENV)); let conn = ensure_ok!(postgres::Connection::open(&address)); - let rowset = ensure_ok!(test_numeric_types(&conn)); + + let rowset = ensure_ok!(numeric_types(&conn)); ensure!(rowset.rows.iter().all(|r| r.len() == 12)); ensure_matches!(rowset.rows[0][11], rdbms_types::DbValue::Floating64(f) if f == 1.0); - let rowset = ensure_ok!(test_character_types(&conn)); + let rowset = ensure_ok!(character_types(&conn)); ensure!(rowset.rows.iter().all(|r| r.len() == 3)); ensure!(matches!(rowset.rows[0][0], rdbms_types::DbValue::Str(ref s) if s == "rvarchar")); + let rowset = ensure_ok!(nullable(&conn)); + ensure!(rowset.rows.iter().all(|r| r.len() == 1)); + ensure!(matches!(rowset.rows[0][0], rdbms_types::DbValue::DbNull)); + let pid1 = format!("{:?}", ensure_ok!(pg_backend_pid(&conn))); let pid2 = format!("{:?}", ensure_ok!(pg_backend_pid(&conn))); ensure_eq!(pid1, pid2); @@ -34,7 +39,7 @@ impl Component { } } -fn test_numeric_types(conn: &postgres::Connection) -> Result { +fn numeric_types(conn: &postgres::Connection) -> Result { let create_table_sql = r#" CREATE TEMPORARY TABLE test_numeric_types ( intid integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, @@ -83,7 +88,7 @@ fn test_numeric_types(conn: &postgres::Connection) -> Result Result { +fn character_types(conn: &postgres::Connection) -> Result { let create_table_sql = r#" CREATE TEMPORARY TABLE test_character_types ( rvarchar varchar(40) NOT NULL, @@ -112,6 +117,33 @@ fn test_character_types(conn: &postgres::Connection) -> Result Result { + let create_table_sql = r#" + CREATE TEMPORARY TABLE test_nullable ( + rvarchar varchar(40) + ); + "#; + + conn.execute(create_table_sql, &[])?; + + let insert_sql = r#" + INSERT INTO test_nullable + (rvarchar) + VALUES + ($1); + "#; + + conn.execute(insert_sql, &[rdbms_types::ParameterValue::DbNull])?; + + let sql = r#" + SELECT + rvarchar + FROM test_nullable; + "#; + + conn.query(sql, &[]) +} + fn pg_backend_pid(conn: &postgres::Connection) -> Result { let sql = "SELECT pg_backend_pid()";