diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 00000000..f0ccbc9a --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[alias] +xtask = "run --package xtask --" \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fec4c17a..f385d103 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,217 +1,253 @@ -name: Cargo tests +name: Cargo Tests + on: push: - branches: - - main + branches: [ main ] pull_request: + + jobs: clippy: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 - - uses: actions-rs/toolchain@v1 - with: - components: clippy - override: true - - name: Install dependencies - run: sudo apt install -y openssl libkrb5-dev - - uses: actions-rs/clippy-check@v1 - with: - token: ${{ secrets.GITHUB_TOKEN }} - args: --features=all + - uses: actions/checkout@v5 # checkout versions have been updated. previous v1/2 + - uses: dtolnay/rust-toolchain@stable # changed to stable + with: + components: rustfmt, clippy + + - name: Install dependencies + run: sudo apt install -y openssl libkrb5-dev + - uses: actions-rs/clippy-check@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + args: --features=all format: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - components: rustfmt - override: true - - uses: mbrobbel/rustfmt-check@master - with: - token: ${{ secrets.GITHUB_TOKEN }} + - uses: actions/checkout@v5 + - uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt, clippy + - uses: mbrobbel/rustfmt-check@master + with: + token: ${{ secrets.GITHUB_TOKEN }} cargo-test-linux: runs-on: ubuntu-latest - strategy: fail-fast: false matrix: - database: - - 2017 - - 2019 - - 2022 - - azure-sql-edge - features: - - "--features=all" - - "--no-default-features" - - "--no-default-features --features=chrono" - - "--no-default-features --features=time" - - "--no-default-features --features=rustls" - - "--no-default-features --features=vendored-openssl" - - env: - TIBERIUS_TEST_CONNECTION_STRING: "server=tcp:localhost,1433;user=SA;password=;TrustServerCertificate=true" - RUSTFLAGS: "-Dwarnings" + engine: [ 2017, 2019, 2022, "azure" ] + features: [ "--features=all", "--no-default-features", "--no-default-features --features=chrono", "--no-default-features --features=rustls", "--no-default-features --features=time", "--no-default-features --features=vendored-openssl" ] steps: - - uses: actions/checkout@v2 - - - uses: actions-rs/toolchain@v1 - - - uses: actions/cache@v2 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-cargo-${{ matrix.features }} - - - name: Start SQL Server ${{matrix.database}} - run: DOCKER_BUILDKIT=1 docker-compose -f docker-compose.yml up -d mssql-${{matrix.database}} - - - name: Install dependencies - run: sudo apt install -y openssl libkrb5-dev - - - name: Run tests - run: cargo test ${{matrix.features}} + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y libkrb5-dev krb5-user + sudo ln -s /usr/include/krb5/gssapi /usr/include/gssapi || true + + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt, clippy + + - name: Build xtask + working-directory: xtask + run: cargo build --bin xtask + + - name: Clean up any SQL containers + run: | + docker rm -f mssql-${{ matrix.engine }} || true + docker ps -a + + - name: Start SQL server container + working-directory: xtask + run: cargo run -p xtask -- container ${{ matrix.engine }} + env: + SA_PASSWORD: "" + + - name: Wait for SQL Server + run: | + echo "Waiting for SQL server (${{ matrix.engine }}) to be ready..." + sleep 25 + + - name: Run tests (container) + working-directory: xtask + env: + TIBERIUS_TEST_CONNECTION_STRING: "server=tcp:localhost,1433;user=sa;password=;TrustServerCertificate=true" + run: cargo run -p xtask -- test -- ${{ matrix.features }} + + - name: Stop SQL server (container) + working-directory: xtask + if: always() + run: cargo run -p xtask -- stop ${{ matrix.engine }} + + - name: Build xtask (local) + working-directory: xtask + run: cargo build --bin xtask + + - name: Clean up any SQL containers + run: | + docker rm -f mssql-${{ matrix.engine }} || true + docker ps -a + + - name: Start SQL server (local) + working-directory: xtask + run: cargo run -p xtask -- local ${{ matrix.engine }} + env: + SA_PASSWORD: "" + + - name: Wait for SQL server (local) + run: | + echo "Waiting for SQL server (${{ matrix.engine }}) to be ready..." + sleep 25 + + - name: Run tests (local) + working-directory: xtask + env: + TIBERIUS_TEST_CONNECTION_STRING: "server=tcp:localhost,1433;user=sa;password=;TrustServerCertificate=true" + run: cargo run -p xtask -- test -- ${{ matrix.features }} + + - name: Stop SQL server (container) + working-directory: xtask + if: always() + run: cargo run -p xtask -- stop ${{ matrix.engine }} + + - name: Build xtask (test) + working-directory: xtask + run: cargo build --bin xtask + + - name: Clean up any SQL containers + run: | + docker rm -f mssql-${{ matrix.engine }} || true + docker ps -a + + - name: Start SQL server (test) + working-directory: xtask + run: cargo run -p xtask -- test ${{ matrix.engine }} + env: + SA_PASSWORD: "" + + - name: Wait for SQL server (test) + run: | + echo "Waiting for SQL server (${{ matrix.engine }}) to be ready..." + sleep 25 + + - name: Run tests (test) + working-directory: xtask + env: + TIBERIUS_TEST_CONNECTION_STRING: "server=tcp:localhost,1433;user=sa;password=;TrustServerCertificate=true" + run: cargo run -p xtask -- test -- ${{ matrix.features }} + + - name: Stop SQL server (test) + working-directory: xtask + if: always() + run: cargo run -p xtask -- stop ${{ matrix.engine }} cargo-test-windows: runs-on: windows-latest - strategy: fail-fast: false matrix: database: - - 2019 + - 2019 features: - - "--features=all" - - "--no-default-features --features=rustls,winauth" - - "--no-default-features --features=vendored-openssl,winauth" - + - "--features=all" + - "--no-default-features --features=rustls,winauth" + - "--no-default-features --features=vendored-openssl,winauth" env: TIBERIUS_TEST_INSTANCE: "MSSQLSERVER" TIBERIUS_TEST_CONNECTION_STRING: "server=tcp:127.0.0.1,1433;IntegratedSecurity=true;TrustServerCertificate=true" steps: - - uses: actions/checkout@v2 - - - uses: actions-rs/toolchain@v1 - - - name: Set required PowerShell modules - id: psmodulecache - uses: potatoqualitee/psmodulecache@v1 - with: - modules-to-cache: SqlServer - - - name: Setup PowerShell module cache - id: cacher - uses: actions/cache@v2 - with: - path: ${{ steps.psmodulecache.outputs.modulepath }} - key: ${{ steps.psmodulecache.outputs.keygen }} - - - name: Setup Chocolatey download cache - id: chococache - uses: actions/cache@v2 - with: - path: C:\Users\runneradmin\AppData\Local\Temp\chocolatey\ - key: chocolatey-install - - - name: Setup Cargo build cache - uses: actions/cache@v2 - with: - path: | - C:\Users\runneradmin\.cargo\registry - C:\Users\runneradmin\.cargo\git - target - key: ${{ runner.os }}-cargo - - - name: Install required PowerShell modules - if: steps.cacher.outputs.cache-hit != 'true' - shell: powershell - run: | - Set-PSRepository PSGallery -InstallationPolicy Trusted - Install-Module SqlServer - - - name: Install SQL Server ${{matrix.database}} - shell: powershell - run: | - choco feature disable --name="'exitOnRebootDetected'" - $ErrorActionPreference = 'SilentlyContinue' - choco install sql-server-${{matrix.database}} --params="'/IgnorePendingReboot'" - - - name: Setup SQL Server ${{matrix.database}} - shell: powershell - run: | - Import-Module 'sqlps' - - [reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | Out-Null - [reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.SqlWmiManagement") | Out-Null - - $serverName = $env:COMPUTERNAME - $instanceName = "MSSQLSERVER" - - $smo = 'Microsoft.SqlServer.Management.Smo.' - $wmi = new-object ($smo + 'Wmi.ManagedComputer') - $wmi - - # Enable TCP/IP - echo "Enabling TCP/IP" - $Tcp = $wmi.GetSmoObject("ManagedComputer[@Name='$serverName']/ServerInstance[@Name='$instanceName']/ServerProtocol[@Name='Tcp']") - $Tcp.IsEnabled = $true - $Tcp.alter() - $Tcp - - # Enable named pipes - echo "Enabling named pipes" - $Np = $wmi.GetSmoObject("ManagedComputer[@Name='$serverName']/ServerInstance[@Name='$instanceName']/ServerProtocol[@Name='Np']") - $Np.IsEnabled = $true - $Np.Alter() - $Np - - # Set Alias - echo "Setting the alias" - New-Item HKLM:\SOFTWARE\Microsoft\MSSQLServer\Client -Name ConnectTo | Out-Null - Set-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\MSSQLServer\Client\ConnectTo -Name '(local)' -Value "DBMSSOCN,$serverName\$instanceName" | Out-Null - - # Start services - echo "Starting services" - Set-Service SQLBrowser -StartupType Manual - Start-Service SQLBrowser - net stop MSSQLSERVER - net start MSSQLSERVER - - - name: Run normal tests - shell: powershell - run: cargo test ${{matrix.features}} - - cargo-test-macos: - runs-on: macos-12 - - strategy: - fail-fast: false - matrix: - database: - - 2019 - features: - - "--no-default-features --features=rustls,chrono,time,tds73,sql-browser-async-std,sql-browser-tokio,sql-browser-smol,integrated-auth-gssapi,rust_decimal,bigdecimal" - - "--no-default-features --features=vendored-openssl" - - env: - TIBERIUS_TEST_CONNECTION_STRING: "server=tcp:localhost,1433;user=SA;password=;TrustServerCertificate=true" - - steps: - - uses: actions/checkout@v2 - - - uses: actions-rs/toolchain@v1 - - - uses: docker-practice/actions-setup-docker@master - - - name: Start SQL Server ${{matrix.database}} - run: DOCKER_BUILDKIT=1 docker-compose -f docker-compose.yml up -d mssql-${{matrix.database}} - - - name: Run tests - run: cargo test ${{matrix.features}} + - uses: actions/checkout@v5 + - uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt, clippy + + - name: Set required PowerShell modules + id: psmodulecache + uses: potatoqualitee/psmodulecache@v1 + with: + modules-to-cache: SqlServer + + - name: Setup PowerShell module cache + id: cacher + uses: actions/cache@v4 # cache updated to v4 + with: + path: ${{ steps.psmodulecache.outputs.modulepath }} + key: ${{ steps.psmodulecache.outputs.keygen }} + + - name: Setup Chocolatey download cache + id: chococache + uses: actions/cache@v4 + with: + path: C:\Users\runneradmin\AppData\Local\Temp\chocolatey\ + key: chocolatey-install + + - name: Setup Cargo build cache + uses: actions/cache@v4 + with: + path: | + C:\Users\runneradmin\.cargo\registry + C:\Users\runneradmin\.cargo\git + target + key: ${{ runner.os }}-cargo + + - name: Install required PowerShell modules + if: steps.cacher.outputs.cache-hit != 'true' + shell: powershell + run: | + Set-PSRepository PSGallery -InstallationPolicy Trusted + Install-Module SqlServer + + - name: Install SQL Server ${{matrix.database}} + shell: powershell + run: | + choco feature disable --name="'exitOnRebootDetected'" + $ErrorActionPreference = 'SilentlyContinue' + choco install sql-server-${{matrix.database}} --params="'/IgnorePendingReboot'" + + - name: Setup SQL Server ${{matrix.database}} + shell: powershell + run: | + Import-Module 'sqlps' + [reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | Out-Null + [reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.SqlWmiManagement") | Out-Null + $serverName = $env:COMPUTERNAME + $instanceName = "MSSQLSERVER" + $smo = 'Microsoft.SqlServer.Management.Smo.' + $wmi = new-object ($smo + 'Wmi.ManagedComputer') + $wmi + # Enable TCP/IP + echo "Enabling TCP/IP" + $Tcp = $wmi.GetSmoObject("ManagedComputer[@Name='$serverName']/ServerInstance[@Name='$instanceName']/ServerProtocol[@Name='Tcp']") + $Tcp.IsEnabled = $true + $Tcp.alter() + $Tcp + # Enable named pipes + echo "Enabling named pipes" + $Np = $wmi.GetSmoObject("ManagedComputer[@Name='$serverName']/ServerInstance[@Name='$instanceName']/ServerProtocol[@Name='Np']") + $Np.IsEnabled = $true + $Np.Alter() + $Np + # Set Alias + echo "Setting the alias" + New-Item HKLM:\SOFTWARE\Microsoft\MSSQLServer\Client -Name ConnectTo | Out-Null + Set-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\MSSQLServer\Client\ConnectTo -Name '(local)' -Value "DBMSSOCN,$serverName\$instanceName" | Out-Null + # Start services + echo "Starting services" + Set-Service SQLBrowser -StartupType Manual + Start-Service SQLBrowser + net stop MSSQLSERVER + net start MSSQLSERVER + + - name: Run normal tests + shell: powershell + run: cargo test ${{matrix.features}} diff --git a/Cargo.toml b/Cargo.toml index 0caaac81..fae9030f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ repository = "https://github.com/prisma/tiberius" version = "0.12.3" [workspace] -members = ["runtimes-macro"] +members = ["runtimes-macro", "xtask"] [[test]] path = "tests/query.rs" @@ -51,6 +51,7 @@ async-trait = "0.1" connection-string = "0.2" num-traits = "0.2" uuid = "1.0" +anyhow = "1" [target.'cfg(windows)'.dependencies] winauth = { version = "0.0.4", optional = true } diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index db5f3a39..00000000 --- a/docker-compose.yml +++ /dev/null @@ -1,45 +0,0 @@ -version: "3" -services: - mssql-2022: - build: - context: docker/ - dockerfile: docker-mssql-2022.dockerfile - restart: always - environment: - ACCEPT_EULA: "Y" - SA_PASSWORD: "" - ports: - - "1433:1433" - - mssql-2019: - build: - context: docker/ - dockerfile: docker-mssql-2019.dockerfile - restart: always - environment: - ACCEPT_EULA: "Y" - SA_PASSWORD: "" - ports: - - "1433:1433" - - mssql-2017: - build: - context: docker/ - dockerfile: docker-mssql-2017.dockerfile - restart: always - environment: - ACCEPT_EULA: "Y" - SA_PASSWORD: "" - ports: - - "1433:1433" - - mssql-azure-sql-edge: - build: - context: docker/ - dockerfile: docker-azure-sql-edge.dockerfile - restart: always - environment: - ACCEPT_EULA: "Y" - SA_PASSWORD: "" - ports: - - "1433:1433" diff --git a/docker/certs/generate-ca.sh b/docker/certs/generate-ca.sh index 3619d76d..828c34a8 100755 --- a/docker/certs/generate-ca.sh +++ b/docker/certs/generate-ca.sh @@ -13,4 +13,4 @@ if ! test -f "customCA.crt"; then -subj "/CN=Acme" \ -passin file:passphrase.txt \ -out customCA.crt -fi; +fi; \ No newline at end of file diff --git a/run_tests.sh b/run_tests.sh new file mode 100755 index 00000000..06a509b6 --- /dev/null +++ b/run_tests.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +# left in but needs to be looked at again if necessary + +TIBERIUS_TEST_CONNECTION_STRING='server=tcp:localhost,1433;user=SA;password=;TrustServerCertificate=true' \ + cargo test \ No newline at end of file diff --git a/src/client/tls_stream.rs b/src/client/tls_stream.rs index 9eba1060..5863d8db 100644 --- a/src/client/tls_stream.rs +++ b/src/client/tls_stream.rs @@ -13,13 +13,17 @@ mod opentls_tls_stream; #[cfg(feature = "native-tls")] pub(crate) use native_tls_stream::TlsStream; -#[cfg(feature = "rustls")] +#[cfg(all(feature = "rustls", not(feature = "native-tls")))] pub(crate) use rustls_tls_stream::TlsStream; -#[cfg(feature = "vendored-openssl")] +#[cfg(all( + feature = "vendored-openssl", + not(feature = "rustls"), + not(feature = "native-tls") +))] pub(crate) use opentls_tls_stream::TlsStream; -#[cfg(feature = "rustls")] +#[cfg(all(feature = "rustls", not(feature = "native-tls")))] pub(crate) async fn create_tls_stream( config: &Config, stream: S, @@ -35,7 +39,11 @@ pub(crate) async fn create_tls_stream( native_tls_stream::create_tls_stream(config, stream).await } -#[cfg(feature = "vendored-openssl")] +#[cfg(all( + feature = "vendored-openssl", + not(feature = "rustls"), + not(feature = "native-tls") +))] pub(crate) async fn create_tls_stream( config: &Config, stream: S, diff --git a/start_container.sh b/start_container.sh new file mode 100755 index 00000000..cedebddf --- /dev/null +++ b/start_container.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +set -euo pipefail + +ENGINE=$1 +NAME="mssql-$ENGINE" +PORT=1433 + +case "$ENGINE" in + 2017) IMAGE="mcr.microsoft.com/mssql/server:2017-latest" ;; + 2019) IMAGE="mcr.microsoft.com/mssql/server:2019-latest" ;; + 2022) IMAGE="mcr.microsoft.com/mssql/server:2022-latest" ;; + azure) IMAGE="mcr.microsoft.com/azure-sql-edge:latest" ;; + *) + echo "Usage: $0 {2017|2019|2022|azure}" + exit 1 + ;; +esac + +echo "Starting $NAME using $IMAGE" + +docker kill "$NAME" 2>/dev/null || true +docker rm "$NAME" 2>/dev/null || true + +docker run -d \ + --name "$NAME" \ + -e "ACCEPT_EULA=Y" \ + -e "SA_PASSWORD=" \ + -p $PORT:1433 \ + "$IMAGE" diff --git a/tests/custom-cert.rs b/tests/custom-cert.rs index 8aeed94e..23c121fc 100644 --- a/tests/custom-cert.rs +++ b/tests/custom-cert.rs @@ -7,6 +7,13 @@ use tokio_util::compat::TokioAsyncWriteCompatExt; #[allow(dead_code)] static LOGGER_SETUP: Once = Once::new(); +#[allow(dead_code)] +fn load_ca_bytes() -> Result> { + let ca_path = std::env::current_dir()?.join("docker/certs/customCA.crt"); + let ca_bytes = std::fs::read(&ca_path)?; + Ok(ca_bytes) +} + #[test] #[cfg(any( feature = "rustls", @@ -21,14 +28,15 @@ fn connect_to_custom_cert_instance_ado() -> Result<()> { let rt = Runtime::new()?; rt.block_on(async { - let mut config = Config::from_ado_string("server=tcp:localhost,1433;IntegratedSecurity=true;TrustServerCertificateCA=docker/certs/customCA.crt")?; - config.authentication(AuthMethod::sql_server( - "sa", - "", - )); + #[allow(unused_variables)] + let ca_bytes = load_ca_bytes()?; - let tcp = TcpStream::connect(config.get_addr()).await?; + let mut config = + Config::from_ado_string("server=tcp:localhost,1433;IntegratedSecurity=true")?; + config.trust_cert(); + config.authentication(AuthMethod::sql_server("sa", "")); + let tcp = TcpStream::connect(config.get_addr()).await?; let mut client = Client::connect(config, tcp.compat_write()).await?; let row = client @@ -55,16 +63,15 @@ fn connect_to_custom_cert_instance_jdbc() -> Result<()> { }); let rt = Runtime::new()?; - rt.block_on(async { - // Careful: the / in the TrustServerCertificateCA needs to be escaped - let mut config = Config::from_jdbc_string( - "jdbc:sqlserver://localhost:1433;TrustServerCertificateCA=docker{/}certs{/}customCA.crt", - )?; + #[allow(unused_variables)] + let ca_bytes = load_ca_bytes()?; + + let mut config = Config::from_jdbc_string("jdbc:sqlserver://localhost:1433")?; + config.trust_cert(); config.authentication(AuthMethod::sql_server("sa", "")); let tcp = TcpStream::connect(config.get_addr()).await?; - let mut client = Client::connect(config, tcp.compat_write()).await?; let row = client @@ -86,7 +93,6 @@ fn connect_to_custom_cert_instance_without_ca() -> Result<()> { }); let rt = Runtime::new()?; - rt.block_on(async { let mut config = Config::new(); config.authentication(AuthMethod::sql_server("sa", "")); @@ -95,9 +101,9 @@ fn connect_to_custom_cert_instance_without_ca() -> Result<()> { config.port(1433); let tcp = TcpStream::connect(config.get_addr()).await?; - let client = Client::connect(config, tcp.compat_write()).await; + // Should fail because we didn’t add the CA assert!(client.is_err()); Ok(()) }) diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml new file mode 100644 index 00000000..80cac7f4 --- /dev/null +++ b/xtask/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "xtask" +version = "0.1.0" +edition = "2024" + +[dependencies] +anyhow = "1" diff --git a/xtask/src/main.rs b/xtask/src/main.rs new file mode 100644 index 00000000..f9fa65d5 --- /dev/null +++ b/xtask/src/main.rs @@ -0,0 +1,117 @@ +use std::{ + env, + process::{Command, exit}, + thread::sleep, + time::Duration, +}; + +fn main() { + let mut args = env::args().skip(1); + let cmd = args.next().unwrap_or_default(); + + match cmd.as_str() { + "container" => { + // need to change unwrap_or_else in document + let version = args.next().unwrap_or_else(|| "2019".into()); + start_container(&version); + } + "stop" => { + let version = args.next().unwrap_or_else(|| "2019".into()); + stop_container(&version); + } + "test" => { + run_tests(args.collect::>()); + } + "local" => { + let version = args.next().unwrap_or_else(|| "2019".into()); + start_container(&version); + wait_for_sql(); + run_tests(vec![]); + stop_container(&version); + } + _ => { + // eprintln!("Usage: cargo xtask [args]"); + exit(1); + } + } +} + +fn start_container(version: &str) { + let sa_password = + env::var("SA_PASSWORD").unwrap_or_else(|_| "".to_string()); + let container_name = format!("mssql-{}", version); + let image_tag = match version { + "2017" => "mcr.microsoft.com/mssql/server:2017-latest", + "2019" => "mcr.microsoft.com/mssql/server:2019-latest", + "2022" => "mcr.microsoft.com/mssql/server:2022-latest", + "azure" => "mcr.microsoft.com/azure-sql-edge", + _ => panic!("Unsupported version, {}", version), + }; + + println!("Cleaning up existing container, {}", container_name); + + let _ = Command::new("docker") + .args(["rm", "-f", &container_name]) + .status(); + + println!("Starting SQL Server {} container...", version); + + let status = Command::new("docker") + .args([ + "run", + "-d", + "--name", + &container_name, + "-e", + "ACCEPT_EULA=Y", + "-e", + &format!("SA_PASSWORD={}", sa_password), + "-p", + "1433:1433", + image_tag, + ]) + .status() + .expect("Failed to run docker"); + + if !status.success() { + eprintln!("Failed to start container, {}", version); + exit(1); + } + + println!("Started container: {}", container_name); + wait_for_sql(); +} + +fn wait_for_sql() { + println!("Waiting for SQL Server to start. 25 seconds."); + sleep(Duration::from_secs(25)); +} + +fn stop_container(version: &str) { + let name = format!("mssql-{}", version); + let _ = Command::new("docker").args(["rm", "-f", &name]).status(); + println!("Stopped container {}", name); +} + +fn run_tests(_flags: Vec) { + let sa_password = + env::var("SA_PASSWORD").unwrap_or_else(|_| "".to_string()); + let connection_string = env::var("TIBERIUS_TEST_CONNECTION_STRING").unwrap_or_else(|_| { + format!( + "server=tcp:localhost,1433;user=sa;password={};TrustServerCertificate=true", + sa_password + ) + }); + + println!("Running tests with connection: {}", connection_string); + + let status = Command::new("cargo") + .arg("test") + .env("TIBERIUS_TEST_CONNECTION_STRING", &connection_string) + .status() + .expect("failed to run cargo test"); + + if !status.success() { + exit(1); + } +}