Skip to content

Commit

Permalink
Add configuration test
Browse files Browse the repository at this point in the history
  • Loading branch information
danieljharvey committed Nov 13, 2023
1 parent 4d72910 commit 7020371
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 31 deletions.
40 changes: 9 additions & 31 deletions crates/ndc-sqlserver/src/configuration/version1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,7 @@ async fn select_first_row(
let stream = select.query(&mut connection).await.unwrap();

// Nothing is fetched, the first result set starts.
let row = stream.into_row().await.unwrap().unwrap();

row
stream.into_row().await.unwrap().unwrap()
}

/// Construct the deployment configuration by introspecting the database.
Expand Down Expand Up @@ -171,37 +169,16 @@ async fn get_comparison_operators(
database::ComparisonOperators(comparison_operators)
}

const CHARACTER_STRINGS: [&str; 3] = ["char", "text", "varchar"];
const UNICODE_CHARACTER_STRINGS: [&str; 3] = ["nchar", "ntext", "nvarchar"];
const CANNOT_COMPARE: [&str; 3] = ["text", "ntext", "image"];

// we hard code these, essentially
// we look up available types in `sys.types` but hard code their behaviour by looking them up below
// categories taken from https://learn.microsoft.com/en-us/sql/t-sql/data-types/data-types-transact-sql
fn get_comparison_operators_for_type(
type_name: database::ScalarType,
) -> BTreeMap<String, database::ComparisonOperator> {
let _exact_numerics = vec![
"bigint",
"bit",
"decimal",
"int",
"money",
"numeric",
"smallint",
"smallmoney",
"tinyint",
];
let _approx_numerics = vec!["float", "real"];
let _date_and_time = vec![
"date",
"datetime2",
"datetime",
"datetimeoffset",
"smalldatetime",
"time",
];
let character_strings = vec!["char", "text", "varchar"];
let unicode_character_strings = vec!["nchar", "ntext", "nvarchar"];
let _binary_strings = vec!["binary", "image", "varbinary"];
let cannot_compare = vec!["text", "ntext", "image"]; // https://learn.microsoft.com/en-us/sql/t-sql/language-elements/comparison-operators-transact-sql?view=sql-server-ver16

let mut comparison_operators = BTreeMap::new();

// in ndc-spec, all things can be `==`
Expand All @@ -214,8 +191,8 @@ fn get_comparison_operators_for_type(
);

// include LIKE and NOT LIKE for string-ish types
if character_strings.contains(&type_name.0.as_str())
|| unicode_character_strings.contains(&type_name.0.as_str())
if CHARACTER_STRINGS.contains(&type_name.0.as_str())
|| UNICODE_CHARACTER_STRINGS.contains(&type_name.0.as_str())
{
comparison_operators.insert(
"_like".to_string(),
Expand All @@ -234,7 +211,8 @@ fn get_comparison_operators_for_type(
}

// some things cannot be compared
if !cannot_compare.contains(&type_name.0.as_str()) {
// https://learn.microsoft.com/en-us/sql/t-sql/language-elements/comparison-operators-transact-sql?view=sql-server-ver16
if !CANNOT_COMPARE.contains(&type_name.0.as_str()) {
comparison_operators.insert(
"_neq".to_string(),
database::ComparisonOperator {
Expand Down
71 changes: 71 additions & 0 deletions crates/ndc-sqlserver/tests/configuration_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
use std::fs;
use std::path::{Path, PathBuf};

use ndc_sqlserver::configuration;
use similar_asserts::assert_eq;

const CONNECTION_STRING: &str ="DRIVER={ODBC Driver 18 for SQL Server};SERVER=127.0.0.1,64003;Uid=SA;Database=Chinook;Pwd=Password!";

const CHINOOK_DEPLOYMENT_PATH: &str = "static/chinook-deployment.json";

#[tokio::test]
async fn test_configure_is_idempotent() {
configure_is_idempotent(CONNECTION_STRING, CHINOOK_DEPLOYMENT_PATH).await
}

// Tests that configuration generation has not changed.
//
// This test does not use insta snapshots because it checks the deployment file that is shared with
// other tests.
//
// If you have changed it intentionally, run `just generate-chinook-configuration`.
pub async fn configure_is_idempotent(
connection_string: &str,
chinook_deployment_path: impl AsRef<Path>,
) {
let expected_value = read_configuration(chinook_deployment_path);

let mut args: configuration::RawConfiguration = serde_json::from_value(expected_value.clone())
.expect("Unable to deserialize as RawConfiguration");

args.mssql_connection_string = connection_string.to_string();

let actual = configuration::configure(&args)
.await
.expect("configuration::configure");

let actual_value = serde_json::to_value(actual).expect("serde_json::to_value");

assert_eq!(expected_value, actual_value);
}

pub async fn configure_initial_configuration_is_unchanged(
connection_string: &str,
) -> ndc_sqlserver::configuration::RawConfiguration {
let args = configuration::RawConfiguration {
mssql_connection_string: connection_string.to_string(),

..configuration::RawConfiguration::empty()
};

configuration::configure(&args)
.await
.expect("configuration::configure")
}

fn read_configuration(chinook_deployment_path: impl AsRef<Path>) -> serde_json::Value {
let file = fs::File::open(get_path_from_project_root(chinook_deployment_path))
.expect("fs::File::open");
serde_json::from_reader(file).expect("serde_json::from_reader")
}

/// Find the project root via the crate root provided by `cargo test`,
/// and get our single static configuration file.
/// This depends on the convention that all our crates live in `/crates/<name>`
/// and will break in the unlikely case that we change this
pub fn get_path_from_project_root(deployment_path: impl AsRef<Path>) -> PathBuf {
let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
d.push("../../");
d.push(deployment_path);
d
}

0 comments on commit 7020371

Please sign in to comment.