//! The explicit importer must preserve source paths and never start on help/error. use std::{fs, path::PathBuf, process::Command}; struct Fixture { _temporary: tempfile::TempDir, root: PathBuf, launcher: PathBuf, arguments: PathBuf, environment: PathBuf, } impl Fixture { fn new() -> Self { let temporary = tempfile::tempdir().unwrap(); let root = temporary.path().to_path_buf(); let project = root.join("new application"); fs::create_dir(&project).unwrap(); let launcher = project.join("import-python.sh"); fs::write(&launcher, include_str!("../import-python.sh")).unwrap(); fs::write( project.join("start.sh"), "#!/usr/bin/env bash\nset -euo pipefail\nprintf '%s\\0' \"$@\" > \"$IMPORT_TEST_ARGS\"\nprintf '%s\\0' \"${DATA_DIR-}\" \"${DATABASE_PATH-}\" > \"$IMPORT_TEST_ENV\"\nexit \"${IMPORT_TEST_STATUS:-0}\"\n", ) .unwrap(); Self { _temporary: temporary, launcher, arguments: root.join("arguments"), environment: root.join("environment"), root, } } fn command(&self) -> Command { let mut command = Command::new("bash"); command .arg(&self.launcher) .current_dir(&self.root) .env("IMPORT_TEST_ARGS", &self.arguments) .env("IMPORT_TEST_ENV", &self.environment) .env_remove("IMPORT_TEST_STATUS"); command } fn arguments(&self) -> Vec { let mut bytes = fs::read(&self.arguments).unwrap(); assert_eq!(bytes.pop(), Some(0)); bytes .split(|byte| *byte == 0) .map(|part| String::from_utf8(part.to_vec()).unwrap()) .collect() } } #[test] fn help_and_invalid_sources_do_not_build_or_import() { let fixture = Fixture::new(); let help = fixture.command().arg("--help").output().unwrap(); assert!(help.status.success()); assert!( String::from_utf8(help.stdout) .unwrap() .contains("SOURCE_DIRECTORY") ); assert!(!fixture.arguments.exists()); for arguments in [vec![], vec![""], vec!["missing source"]] { let result = fixture.command().args(arguments).output().unwrap(); assert_eq!(result.status.code(), Some(2)); assert!(!fixture.arguments.exists()); } } #[test] fn resolves_source_and_preserves_arguments_and_destination_settings() { let fixture = Fixture::new(); let source_name = "old app; literal $(no-command)"; let source = fixture.root.join(source_name); fs::create_dir(&source).unwrap(); let result = fixture .command() .args([ source_name, "--database", "docker-data/db/original data.db", "--backup-root", "/srv/original backups", ]) .env("DATA_DIR", "./new storage") .env("DATABASE_PATH", "./new storage/custom.db") .env("CDPATH", &fixture.root) .output() .unwrap(); assert!(result.status.success(), "{:?}", result); assert_eq!( fixture.arguments(), [ "import-python", "--source", source.canonicalize().unwrap().to_str().unwrap(), "--database", "docker-data/db/original data.db", "--backup-root", "/srv/original backups", ] ); assert_eq!( fs::read(&fixture.environment).unwrap(), b"./new storage\0./new storage/custom.db\0" ); } #[test] fn forwards_import_failure_without_falling_back_to_serve() { let fixture = Fixture::new(); fs::create_dir(fixture.root.join("source")).unwrap(); let result = fixture .command() .arg("source") .env("IMPORT_TEST_STATUS", "23") .output() .unwrap(); assert_eq!(result.status.code(), Some(23)); assert_eq!(fixture.arguments().len(), 3); assert_eq!(fixture.arguments()[0], "import-python"); }