use super::*;
use crate::config::merge::Merge;
use crate::config::types::*;
#[test]
fn test_config_input_merge() {
let file_config = ConfigInput {
databases: Some(DatabasesInput {
dev_url: Some("postgres://localhost/dev".to_string()),
shadow_url: None,
target_url: None,
shadow: Some(ShadowDatabaseInput {
auto: Some(true),
url: None,
docker: None,
}),
}),
directories: Some(DirectoriesInput {
schema_dir: Some("schema".to_string()),
migrations_dir: None,
baselines_dir: None,
roles_file: None,
}),
objects: None,
migration: None,
schema: None,
docker: None,
};
let cli_config = ConfigInput {
databases: Some(DatabasesInput {
dev_url: None, shadow_url: Some("postgres://localhost/shadow_override".to_string()),
target_url: Some("postgres://localhost/target".to_string()),
shadow: None,
}),
directories: Some(DirectoriesInput {
schema_dir: None,
migrations_dir: Some("migrations_override".to_string()),
baselines_dir: Some("baselines".to_string()),
roles_file: Some("roles.sql".to_string()),
}),
objects: Some(ObjectsInput {
include: None,
exclude: Some(ObjectExcludeInput {
exclude_schemas: Some(vec!["temp_*".to_string()]),
exclude_tables: None,
}),
}),
migration: None,
schema: None,
docker: None,
};
let merged = file_config.merge(cli_config);
assert_eq!(
merged.databases.as_ref().unwrap().dev_url,
Some("postgres://localhost/dev".to_string())
);
assert_eq!(
merged.databases.as_ref().unwrap().shadow_url,
Some("postgres://localhost/shadow_override".to_string())
);
assert_eq!(
merged.databases.as_ref().unwrap().target_url,
Some("postgres://localhost/target".to_string())
);
assert_eq!(
merged.directories.as_ref().unwrap().schema_dir,
Some("schema".to_string())
);
assert_eq!(
merged.directories.as_ref().unwrap().migrations_dir,
Some("migrations_override".to_string())
);
assert_eq!(
merged.directories.as_ref().unwrap().baselines_dir,
Some("baselines".to_string())
);
assert!(merged.objects.is_some());
assert_eq!(
merged
.objects
.as_ref()
.unwrap()
.exclude
.as_ref()
.unwrap()
.exclude_schemas,
Some(vec!["temp_*".to_string()])
);
}
#[test]
fn test_config_builder_resolve() {
let config_input = ConfigInput {
databases: Some(DatabasesInput {
dev_url: Some("postgres://localhost/dev".to_string()),
shadow_url: None,
target_url: None,
shadow: None, }),
directories: None, objects: Some(ObjectsInput {
include: None,
exclude: Some(ObjectExcludeInput {
exclude_schemas: Some(vec!["pg_*".to_string()]),
exclude_tables: Some(vec!["temp_*".to_string()]),
}),
}),
migration: None, schema: None, docker: None, };
let config = ConfigBuilder::new()
.with_file(config_input)
.resolve()
.unwrap();
assert_eq!(config.databases.dev, "postgres://localhost/dev");
match config.databases.shadow {
ShadowDatabase::Auto => {} _ => panic!("Expected auto shadow database"),
}
assert_eq!(config.databases.target, None);
assert_eq!(config.directories.schema, "schema");
assert_eq!(config.directories.migrations, "migrations");
assert_eq!(config.directories.baselines, "schema_baselines");
assert_eq!(config.directories.roles, "roles.sql");
assert_eq!(config.objects.exclude.schemas, vec!["pg_*".to_string()]);
assert_eq!(config.objects.exclude.tables, vec!["temp_*".to_string()]);
assert_eq!(config.migration.default_mode, "safe_only");
assert!(config.migration.validate_baseline_consistency);
assert!(config.docker.auto_cleanup);
assert!(config.docker.check_system_identifier);
}
#[tokio::test]
async fn test_shadow_database_url_mode() {
let shadow_db = ShadowDatabase::Url("postgres://localhost/explicit_shadow".to_string());
let url = shadow_db.get_connection_string().await.unwrap();
assert_eq!(url, "postgres://localhost/explicit_shadow");
}
#[test]
fn test_object_filter_schema_filtering() {
let objects = Objects {
include: ObjectInclude {
schemas: vec!["public".to_string(), "app".to_string()],
tables: vec![],
},
exclude: ObjectExclude {
schemas: vec!["pg_*".to_string(), "information_schema".to_string()],
tables: vec![],
},
};
let tracking_table = TrackingTable::default();
let filter = ObjectFilter::new(&objects, &tracking_table);
assert!(filter.should_include_schema("public"));
assert!(filter.should_include_schema("app"));
assert!(!filter.should_include_schema("pg_catalog"));
assert!(!filter.should_include_schema("information_schema"));
assert!(!filter.should_include_schema("other"));
}
#[test]
fn test_object_filter_table_filtering() {
let objects = Objects {
include: ObjectInclude {
schemas: vec!["public".to_string()],
tables: vec!["users".to_string(), "posts".to_string()],
},
exclude: ObjectExclude {
schemas: vec!["pg_*".to_string()],
tables: vec!["temp_*".to_string()],
},
};
let tracking_table = TrackingTable::default();
let filter = ObjectFilter::new(&objects, &tracking_table);
assert!(filter.should_include_table("public", "users"));
assert!(filter.should_include_table("public", "posts"));
assert!(!filter.should_include_table("public", "temp_data"));
assert!(!filter.should_include_table("public", "other_table"));
assert!(!filter.should_include_table("pg_catalog", "pg_tables"));
}
#[test]
fn test_empty_include_patterns_means_include_all() {
let objects = Objects {
include: ObjectInclude {
schemas: vec![], tables: vec![],
},
exclude: ObjectExclude {
schemas: vec!["pg_*".to_string()],
tables: vec![],
},
};
let tracking_table = TrackingTable::default();
let filter = ObjectFilter::new(&objects, &tracking_table);
assert!(filter.should_include_schema("public"));
assert!(filter.should_include_schema("app"));
assert!(filter.should_include_schema("custom"));
assert!(!filter.should_include_schema("pg_catalog"));
assert!(!filter.should_include_schema("pg_stat"));
}
#[test]
fn test_shadow_docker_version_resolution() {
let config = ShadowDockerConfig {
version: Some("16".to_string()),
image: ShadowDockerConfig::default().image.clone(),
environment: Default::default(),
container_name: None,
auto_cleanup: true,
volumes: None,
network: None,
};
assert_eq!(config.resolved_image(), "postgres:16-alpine");
let config_with_both = ShadowDockerConfig {
version: Some("16".to_string()),
image: "postgres:14-bullseye".to_string(),
environment: Default::default(),
container_name: None,
auto_cleanup: true,
volumes: None,
network: None,
};
assert_eq!(config_with_both.resolved_image(), "postgres:14-bullseye");
let default_config = ShadowDockerConfig::default();
assert_eq!(default_config.resolved_image(), "postgres:18-alpine");
}
#[test]
fn test_config_builder_shadow_docker_version() {
let config_input = ConfigInput {
databases: Some(DatabasesInput {
dev_url: Some("postgres://localhost/dev".to_string()),
shadow_url: None,
target_url: None,
shadow: Some(ShadowDatabaseInput {
auto: None,
url: None,
docker: Some(ShadowDockerInput {
version: Some("16".to_string()),
image: None,
environment: None,
container_name: None,
auto_cleanup: None,
volumes: None,
network: None,
}),
}),
}),
directories: None,
objects: None,
migration: None,
schema: None,
docker: None,
};
let config = ConfigBuilder::new()
.with_file(config_input)
.resolve()
.unwrap();
match config.databases.shadow {
ShadowDatabase::Docker(docker_config) => {
assert_eq!(docker_config.version, Some("16".to_string()));
assert_eq!(docker_config.resolved_image(), "postgres:16-alpine");
}
_ => panic!("Expected Docker shadow database"),
}
}
#[test]
fn test_config_builder_shadow_docker_explicit_image() {
let config_input = ConfigInput {
databases: Some(DatabasesInput {
dev_url: Some("postgres://localhost/dev".to_string()),
shadow_url: None,
target_url: None,
shadow: Some(ShadowDatabaseInput {
auto: None,
url: None,
docker: Some(ShadowDockerInput {
version: Some("16".to_string()), image: Some("postgres:14-bullseye".to_string()),
environment: None,
container_name: None,
auto_cleanup: None,
volumes: None,
network: None,
}),
}),
}),
directories: None,
objects: None,
migration: None,
schema: None,
docker: None,
};
let config = ConfigBuilder::new()
.with_file(config_input)
.resolve()
.unwrap();
match config.databases.shadow {
ShadowDatabase::Docker(docker_config) => {
assert_eq!(docker_config.resolved_image(), "postgres:14-bullseye");
}
_ => panic!("Expected Docker shadow database"),
}
}
#[test]
fn test_default_shadow_docker_version() {
let default_config = ShadowDockerConfig::default();
assert_eq!(default_config.image, "postgres:18-alpine");
assert_eq!(default_config.resolved_image(), "postgres:18-alpine");
}