diff --git a/sqlx-core/src/postgres/connection/mod.rs b/sqlx-core/src/postgres/connection/mod.rs index e0238f5911..fd0cbee7d2 100644 --- a/sqlx-core/src/postgres/connection/mod.rs +++ b/sqlx-core/src/postgres/connection/mod.rs @@ -100,6 +100,21 @@ impl PgConnection { Ok(()) } + + pub async fn server_version(&mut self) -> Result { + let result = self.fetch_one("SHOW server_version;",).await?; + let server_version: String = result.get("server_version"); + + Ok(server_version) + } + + pub async fn server_major_version(&mut self) -> Result { + let server_version = self.server_version().await?; + let first = server_version.split(".").next().unwrap(); + let major_version = first.parse::().unwrap(); + + Ok(major_version) + } } impl Debug for PgConnection { diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000000..bc2dc2327c --- /dev/null +++ b/tests/README.md @@ -0,0 +1,18 @@ + + +### Running Tests +SQLx uses docker to run many compatible database systems for integration testing. You'll need to [install docker](https://docs.docker.com/engine/) to run the full suite. You can validate your docker installation with: + + $ docker run hello-world + +Start the databases with `docker-compose` before running tests: + + $ docker-compose up + +Run all tests against all supported databases using: + + $ ./x.py + +If you see test failures, or want to run a more specific set of tests against a specific database, you can specify both the features to be tests and the DATABASE_URL. e.g. + + $ DATABASE_URL=mysql://root:password@127.0.0.1:49183/sqlx cargo test --no-default-features --features macros,offline,any,all-types,mysql,runtime-async-std-native-tls diff --git a/tests/docker.py b/tests/docker.py index b4cdadd650..e664c38c6e 100644 --- a/tests/docker.py +++ b/tests/docker.py @@ -1,4 +1,5 @@ import subprocess +import sys import time from os import path diff --git a/tests/mysql/macros.rs b/tests/mysql/macros.rs index 9b9b436c98..e6fc618cff 100644 --- a/tests/mysql/macros.rs +++ b/tests/mysql/macros.rs @@ -190,12 +190,19 @@ async fn with_test_row<'a>( conn: &'a mut MySqlConnection, ) -> anyhow::Result> { let mut transaction = conn.begin().await?; - sqlx::query!("INSERT INTO tweet(id, text, owner_id) VALUES (1, '#sqlx is pretty cool!', 1)") + sqlx::query!("INSERT INTO tweet(text, owner_id) VALUES ('#sqlx is pretty cool!', 1)") .execute(&mut transaction) .await?; Ok(transaction) } +async fn last_insert_id(conn: &mut MySqlConnection) -> anyhow::Result { + let result = sqlx::query!("SELECT last_insert_id() AS last_insert_id") + .fetch_one(conn) + .await?; + Ok(MyInt(result.last_insert_id as i64)) +} + #[derive(PartialEq, Eq, Debug, sqlx::Type)] #[sqlx(transparent)] struct MyInt(i64); @@ -212,12 +219,13 @@ struct OptionalRecord { async fn test_column_override_wildcard() -> anyhow::Result<()> { let mut conn = new::().await?; let mut conn = with_test_row(&mut conn).await?; + let id = last_insert_id(&mut conn).await?; let record = sqlx::query_as!(Record, "select id as `id: _` from tweet") .fetch_one(&mut conn) .await?; - assert_eq!(record.id, MyInt(1)); + assert_eq!(record.id, id); // this syntax is also useful for expressions let record = sqlx::query_as!(Record, "select * from (select 1 as `id: _`) records") @@ -253,12 +261,13 @@ async fn test_column_override_wildcard_not_null() -> anyhow::Result<()> { async fn test_column_override_wildcard_nullable() -> anyhow::Result<()> { let mut conn = new::().await?; let mut conn = with_test_row(&mut conn).await?; + let id = last_insert_id(&mut conn).await?; let record = sqlx::query_as!(OptionalRecord, "select id as `id?: _` from tweet") .fetch_one(&mut conn) .await?; - assert_eq!(record.id, Some(MyInt(1))); + assert_eq!(record.id, Some(id)); Ok(()) } @@ -267,12 +276,13 @@ async fn test_column_override_wildcard_nullable() -> anyhow::Result<()> { async fn test_column_override_exact() -> anyhow::Result<()> { let mut conn = new::().await?; let mut conn = with_test_row(&mut conn).await?; + let id = last_insert_id(&mut conn).await?; let record = sqlx::query!("select id as `id: MyInt` from tweet") .fetch_one(&mut conn) .await?; - assert_eq!(record.id, MyInt(1)); + assert_eq!(record.id, id); // we can also support this syntax for expressions let record = sqlx::query!("select * from (select 1 as `id: MyInt`) records") @@ -308,12 +318,13 @@ async fn test_column_override_exact_not_null() -> anyhow::Result<()> { async fn test_column_override_exact_nullable() -> anyhow::Result<()> { let mut conn = new::().await?; let mut conn = with_test_row(&mut conn).await?; + let id = last_insert_id(&mut conn).await?; let record = sqlx::query!("select id as `id?: MyInt` from tweet") .fetch_one(&mut conn) .await?; - assert_eq!(record.id, Some(MyInt(1))); + assert_eq!(record.id, Some(id)); Ok(()) } diff --git a/tests/postgres/postgres.rs b/tests/postgres/postgres.rs index 5688aded5f..dbe212a716 100644 --- a/tests/postgres/postgres.rs +++ b/tests/postgres/postgres.rs @@ -968,6 +968,12 @@ async fn test_listener_cleanup() -> anyhow::Result<()> { #[sqlx_macros::test] async fn it_supports_domain_types_in_composite_domain_types() -> anyhow::Result<()> { + // Only supported in Postgres 11+ + let mut conn = new::().await?; + if !(conn.server_major_version().await? >= 11) { + return Ok(()); + } + #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] struct MonthId(i16); @@ -1040,21 +1046,14 @@ async fn it_supports_domain_types_in_composite_domain_types() -> anyhow::Result< } } - let mut conn = new::().await?; - - { - let result = sqlx::query("DELETE FROM heating_bills;") - .execute(&mut conn) - .await; - - let result = result.unwrap(); - assert_eq!(result.rows_affected(), 1); - } + // Ensure the table is empty to begin to avoid CPK violations from repeat runs + sqlx::query("DELETE FROM heating_bills;") + .execute(&mut conn) + .await; - { - let result = sqlx::query( - "INSERT INTO heating_bills(month, cost) VALUES($1::winter_year_month, 100);", - ) + let result = sqlx::query( + "INSERT INTO heating_bills(month, cost) VALUES($1::winter_year_month, 100);", + ) .bind(WinterYearMonth { year: 2021, month: MonthId(1), @@ -1062,18 +1061,8 @@ async fn it_supports_domain_types_in_composite_domain_types() -> anyhow::Result< .execute(&mut conn) .await; - let result = result.unwrap(); - assert_eq!(result.rows_affected(), 1); - } - - { - let result = sqlx::query("DELETE FROM heating_bills;") - .execute(&mut conn) - .await; - - let result = result.unwrap(); - assert_eq!(result.rows_affected(), 1); - } + let result = result.unwrap(); + assert_eq!(result.rows_affected(), 1); Ok(()) } diff --git a/tests/postgres/types.rs b/tests/postgres/types.rs index 5ae5bd217e..932f6b81f3 100644 --- a/tests/postgres/types.rs +++ b/tests/postgres/types.rs @@ -211,7 +211,7 @@ test_type!(ipnetwork_vec>(Postgres, #[cfg(feature = "mac_address")] test_type!(mac_address_vec>(Postgres, - "'{01:02:03:04:05:06,FF:FF:FF:FF:FF:FF}'::inet[]" + "'{01:02:03:04:05:06,FF:FF:FF:FF:FF:FF}'::macaddr[]" == vec![ "01:02:03:04:05:06".parse::().unwrap(), "FF:FF:FF:FF:FF:FF".parse::().unwrap() diff --git a/tests/sqlite/sqlite.db b/tests/sqlite/sqlite.db index 49913441df..d693511079 100644 Binary files a/tests/sqlite/sqlite.db and b/tests/sqlite/sqlite.db differ diff --git a/tests/x.py b/tests/x.py index 2133beefe4..832b914ebb 100755 --- a/tests/x.py +++ b/tests/x.py @@ -88,8 +88,6 @@ def run(command, comment=None, env=None, service=None, tag=None, args=None, data # check # -run("cargo c", comment="check with a default set of features", tag="check") - run( "cargo c --no-default-features --features runtime-async-std-native-tls,all-databases,all-types,offline,macros", comment="check with async-std", @@ -113,9 +111,9 @@ def run(command, comment=None, env=None, service=None, tag=None, args=None, data # run( - "cargo test --manifest-path sqlx-core/Cargo.toml --features all-databases,all-types", + "cargo test --no-default-features --manifest-path sqlx-core/Cargo.toml --features all-databases,all-types,runtime-async-std-native-tls", comment="unit test core", - tag="unit" + tag="unit_async_std" ) run( @@ -124,6 +122,12 @@ def run(command, comment=None, env=None, service=None, tag=None, args=None, data tag="unit_tokio" ) +run( + "cargo test --no-default-features --manifest-path sqlx-core/Cargo.toml --features all-databases,all-types,runtime-actix-native-tls", + comment="unit test core", + tag="unit_actix" +) + # # integration tests #