Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a --test-db global parameter to use TEST_DATABAE_URL env instead #4201

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions diesel_cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ path = "../diesel_migrations/"

[dev-dependencies]
tempfile = "3.1.0"
temp-env = "0.3"
regex = "1.3.9"
insta = "1.21"

Expand Down
3 changes: 3 additions & 0 deletions diesel_cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ ways that you can set it:
* Set it as an environment variable using [dotenv](https://github.com/dotenv-rs/dotenv#examples)
* Pass it directly by adding the `--database-url` flag

To support a test database during development, passing --test-db to have
diesel load the database url from TEST_DATABASE_URL instead.

As an alternative to running migrations with the CLI, you can call
[`diesel::migrations::run_pending_migrations`][pending-migrations] from
`build.rs`.
Expand Down
11 changes: 11 additions & 0 deletions diesel_cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,16 @@ pub fn build_cli() -> Command {
.global(true)
.num_args(1);

let test_db_arg = Arg::new("TEST_DB")
.long("test-db")
.short('t')
.help(
"Enable using a test db. This switches the database-url fall back to load from the \
TEST_DATABASE_URL environment variable before DATABASE_URL.",
)
.global(true)
.action(ArgAction::SetTrue);

let locked_schema_arg = Arg::new("LOCKED_SCHEMA")
.long("locked-schema")
.help("Require that the schema file is up to date.")
Expand Down Expand Up @@ -384,6 +394,7 @@ pub fn build_cli() -> Command {
)
.arg(database_arg)
.arg(config_arg)
.arg(test_db_arg)
.arg(locked_schema_arg)
.subcommand(migration_subcommand)
.subcommand(setup_subcommand)
Expand Down
218 changes: 182 additions & 36 deletions diesel_cli/src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,14 @@ pub fn database_url(matches: &ArgMatches) -> Result<String, crate::errors::Error
matches
.get_one::<String>("DATABASE_URL")
.cloned()
.or_else(|| env::var("DATABASE_URL").ok())
.or_else(|| {
let is_test_db = matches.get_one::<bool>("TEST_DB").cloned().unwrap_or(false);
if is_test_db {
env::var("TEST_DATABASE_URL").ok()
} else {
env::var("DATABASE_URL").ok()
}
})
.ok_or(crate::errors::Error::DatabaseUrlMissing)
}

Expand Down Expand Up @@ -469,44 +476,183 @@ fn path_from_sqlite_url(database_url: &str) -> Result<std::path::PathBuf, crate:
}
}

#[cfg(all(test, any(feature = "postgres", feature = "mysql")))]
#[cfg(test)]
mod tests {
use super::change_database_of_url;

#[test]
fn split_pg_connection_string_returns_postgres_url_and_database() {
let database = "database".to_owned();
let base_url = "postgresql://localhost:5432".to_owned();
let database_url = format!("{base_url}/{database}");
let postgres_url = format!("{}/{}", base_url, "postgres");
assert_eq!(
(database, postgres_url),
change_database_of_url(&database_url, "postgres").unwrap()
);
}
mod database_url {
use super::super::database_url;
use crate::cli::build_cli;

#[test]
fn when_no_database_url_arg_returns_database_url_env() {
let cli = build_cli();
temp_env::with_vars(
[
("DATABASE_URL", Some("sqlite:///prod.sqlite")),
("TEST_DATABASE_URL", Some("sqlite:///test.sqlite")),
],
|| {
let matches = cli
.clone()
.try_get_matches_from(["diesel", "setup"])
.unwrap();
let ret = database_url(&matches);
assert!(ret.is_ok());
assert_eq!(ret.unwrap(), "sqlite:///prod.sqlite");
},
);
}

#[test]
fn when_no_database_url_arg_nor_env_returns_error() {
let cli = build_cli();
temp_env::with_vars(
[
("DATABASE_URL", None::<&str>),
("TEST_DATABASE_URL", None::<&str>),
],
|| {
let matches = cli
.clone()
.try_get_matches_from(["diesel", "setup"])
.unwrap();
let ret = database_url(&matches);
assert!(ret.is_err());
assert!(matches!(
ret.unwrap_err(),
crate::errors::Error::DatabaseUrlMissing
));
},
);
}

#[test]
fn when_database_url_arg_returns_database_url_arg() {
let cli = build_cli();
temp_env::with_vars(
[
("DATABASE_URL", Some("sqlite:///prod.sqlite")),
("TEST_DATABASE_URL", Some("sqlite:///test.sqlite")),
],
|| {
let matches = cli
.clone()
.try_get_matches_from([
"diesel",
"setup",
"--database-url",
"sqlite:///arg.sqlite",
])
.unwrap();
let ret = database_url(&matches);
assert!(ret.is_ok());
assert_eq!(ret.unwrap(), "sqlite:///arg.sqlite");
},
);
}

#[test]
fn when_test_db_and_no_database_url_arg_returns_test_database_url_env() {
let cli = build_cli();
temp_env::with_vars(
[
("DATABASE_URL", Some("sqlite:///prod.sqlite")),
("TEST_DATABASE_URL", Some("sqlite:///test.sqlite")),
],
|| {
let matches = cli
.clone()
.try_get_matches_from(["diesel", "setup", "--test-db"])
.unwrap();
let ret = database_url(&matches);
assert!(ret.is_ok());
assert_eq!(ret.unwrap(), "sqlite:///test.sqlite");
},
);
}

#[test]
fn split_pg_connection_string_handles_user_and_password() {
let database = "database".to_owned();
let base_url = "postgresql://user:password@localhost:5432".to_owned();
let database_url = format!("{base_url}/{database}");
let postgres_url = format!("{}/{}", base_url, "postgres");
assert_eq!(
(database, postgres_url),
change_database_of_url(&database_url, "postgres").unwrap()
);
#[test]
fn when_test_db_and_no_test_url_env_returns_error() {
let cli = build_cli();
temp_env::with_vars([("DATABASE_URL", Some("sqlite:///prod.sqlite"))], || {
let matches = cli
.clone()
.try_get_matches_from(["diesel", "setup", "--test-db"])
.unwrap();
let ret = database_url(&matches);
assert!(ret.is_err());
assert!(matches!(
ret.unwrap_err(),
crate::errors::Error::DatabaseUrlMissing
));
});
}

#[test]
fn when_test_db_and_database_url_arg_returns_database_url_arg() {
let cli = build_cli();
temp_env::with_vars(
[
("DATABASE_URL", Some("sqlite:///prod.sqlite")),
("TEST_DATABASE_URL", Some("sqlite:///test.sqlite")),
],
|| {
let matches = cli
.clone()
.try_get_matches_from([
"diesel",
"setup",
"--test-db",
"--database-url",
"sqlite:///arg.sqlite",
])
.unwrap();
let ret = database_url(&matches);
assert!(ret.is_ok());
assert_eq!(ret.unwrap(), "sqlite:///arg.sqlite");
},
);
}
}

#[test]
fn split_pg_connection_string_handles_query_string() {
let database = "database".to_owned();
let query = "?sslmode=true".to_owned();
let base_url = "postgresql://user:password@localhost:5432".to_owned();
let database_url = format!("{base_url}/{database}{query}");
let postgres_url = format!("{}/{}{}", base_url, "postgres", query);
assert_eq!(
(database, postgres_url),
change_database_of_url(&database_url, "postgres").unwrap()
);
#[cfg(any(feature = "postgres", feature = "mysql"))]
mod change_of_url_tests {
use super::super::change_database_of_url;

#[test]
fn split_pg_connection_string_returns_postgres_url_and_database() {
let database = "database".to_owned();
let base_url = "postgresql://localhost:5432".to_owned();
let database_url = format!("{base_url}/{database}");
let postgres_url = format!("{}/{}", base_url, "postgres");
assert_eq!(
(database, postgres_url),
change_database_of_url(&database_url, "postgres").unwrap()
);
}

#[test]
fn split_pg_connection_string_handles_user_and_password() {
let database = "database".to_owned();
let base_url = "postgresql://user:password@localhost:5432".to_owned();
let database_url = format!("{base_url}/{database}");
let postgres_url = format!("{}/{}", base_url, "postgres");
assert_eq!(
(database, postgres_url),
change_database_of_url(&database_url, "postgres").unwrap()
);
}

#[test]
fn split_pg_connection_string_handles_query_string() {
let database = "database".to_owned();
let query = "?sslmode=true".to_owned();
let base_url = "postgresql://user:password@localhost:5432".to_owned();
let database_url = format!("{base_url}/{database}{query}");
let postgres_url = format!("{}/{}{}", base_url, "postgres", query);
assert_eq!(
(database, postgres_url),
change_database_of_url(&database_url, "postgres").unwrap()
);
}
}
}
Loading