// file: crates/knowledge-git-lib/unit_tests/backend.rs // version: 1 #[derive(Clone)] struct RecordingRunner { calls: std::rc::Rc>>, failure: Option, inspection_stdout: Vec, } impl RecordingRunner { fn successful() -> RecordingRunner { return RecordingRunner { calls: std::rc::Rc::new(std::cell::RefCell::new(Vec::new())), failure: None, inspection_stdout: b"true\n".to_vec(), }; } fn failing(error: crate::GitBackendError) -> RecordingRunner { return RecordingRunner { calls: std::rc::Rc::new(std::cell::RefCell::new(Vec::new())), failure: Some(error), inspection_stdout: b"true\n".to_vec(), }; } fn with_inspection_stdout(value: &[u8]) -> RecordingRunner { return RecordingRunner { calls: std::rc::Rc::new(std::cell::RefCell::new(Vec::new())), failure: None, inspection_stdout: value.to_vec(), }; } } impl super::GitCommandRunner for RecordingRunner { fn run(&self, specification: &super::GitCommandSpec) -> Result { self.calls.borrow_mut().push(specification.clone()); if let Some(error) = self.failure { return Err(error); } if specification.operation == crate::GitOperation::InspectMirror { return Ok(super::GitCommandOutput { stdout: self.inspection_stdout.clone(), }); } return Ok(super::GitCommandOutput { stdout: Vec::new() }); } } fn source_id(value: &str) -> Option { let result = knowledge_domain_lib::SourceId::new(value); match result { Ok(source_id) => return Some(source_id), Err(_) => return None, } } fn test_root(label: &str) -> std::path::PathBuf { let mut path = std::env::temp_dir(); path.push(format!("sasedev-knowledge-git-lib-{label}-{}", std::process::id())); let _ = std::fs::remove_dir_all(&path); return path; } #[test] fn backend_configuration_requires_non_empty_paths() { assert_eq!(crate::GitBackendConfig::new(std::path::PathBuf::new()), Err(crate::GitBackendError::EmptyStateRoot)); assert_eq!( crate::GitBackendConfig::with_git_executable(test_root("empty-executable"), std::path::PathBuf::new()), Err(crate::GitBackendError::EmptyGitExecutable) ); return; } #[test] fn source_key_never_interpolates_raw_source_identifier_as_a_path() { let source_result = source_id("../pgr/credential:value"); assert!(source_result.is_some()); let source_id = match source_result { Some(value) => value, None => return, }; let key = crate::GitSourceKey::from_source_id(&source_id); assert!(key.as_str().starts_with("source-")); assert!(key.as_str().chars().all(|character| character.is_ascii_alphanumeric() || character == '-')); assert!(!key.as_str().contains("pgr")); assert!(!key.as_str().contains("..")); return; } #[test] fn local_source_clone_uses_mirror_no_local_and_argument_separator() { let root = test_root("local-arguments"); let config_result = crate::GitBackendConfig::new(root.clone()); assert!(config_result.is_ok()); let config = match config_result { Ok(value) => value, Err(_) => return, }; let runner = RecordingRunner::successful(); let backend = crate::GitBackend::with_runner(config, Box::new(runner.clone())); let source_id_result = source_id("pgr"); assert!(source_id_result.is_some()); let source_id = match source_id_result { Some(value) => value, None => return, }; let source_result = crate::GitSourceConfig::local(source_id, std::path::PathBuf::from("/controlled/source")); assert!(source_result.is_ok()); let source = match source_result { Ok(value) => value, Err(_) => return, }; let mirror_result = backend.ensure_mirror(&source); assert!(mirror_result.is_ok()); let calls = runner.calls.borrow(); assert_eq!(calls.len(), 2); assert_eq!(calls[0].operation, crate::GitOperation::CloneMirror); assert_eq!( calls[0].arguments, vec![ std::ffi::OsString::from("clone"), std::ffi::OsString::from("--mirror"), std::ffi::OsString::from("--no-local"), std::ffi::OsString::from("--"), std::ffi::OsString::from("/controlled/source"), backend.repository_path(source.source_id()).into_os_string(), ] ); assert_eq!(calls[1].operation, crate::GitOperation::InspectMirror); assert!(backend.config().hooks_path().is_dir()); assert!(backend.config().repositories_path().is_dir()); assert!(backend.config().snapshots_path().is_dir()); let _ = std::fs::remove_dir_all(root); return; } #[test] fn remote_source_clone_does_not_add_no_local() { let root = test_root("remote-arguments"); let config_result = crate::GitBackendConfig::new(root.clone()); assert!(config_result.is_ok()); let config = match config_result { Ok(value) => value, Err(_) => return, }; let runner = RecordingRunner::successful(); let backend = crate::GitBackend::with_runner(config, Box::new(runner.clone())); let source_id_result = source_id("howtos"); assert!(source_id_result.is_some()); let source_id = match source_id_result { Some(value) => value, None => return, }; let source_result = crate::GitSourceConfig::remote(source_id, "ssh://git@example.invalid/howtos.git"); assert!(source_result.is_ok()); let source = match source_result { Ok(value) => value, Err(_) => return, }; assert!(backend.ensure_mirror(&source).is_ok()); let calls = runner.calls.borrow(); assert_eq!(calls[0].operation, crate::GitOperation::CloneMirror); assert_eq!(calls[0].arguments[0], std::ffi::OsString::from("clone")); assert_eq!(calls[0].arguments[1], std::ffi::OsString::from("--mirror")); assert_eq!(calls[0].arguments[2], std::ffi::OsString::from("--")); assert!(!calls[0].arguments.contains(&std::ffi::OsString::from("--no-local"))); let _ = std::fs::remove_dir_all(root); return; } #[test] fn process_errors_do_not_expose_remote_location_or_credentials() { let root = test_root("redaction"); let config_result = crate::GitBackendConfig::new(root.clone()); assert!(config_result.is_ok()); let config = match config_result { Ok(value) => value, Err(_) => return, }; let runner = RecordingRunner::failing(crate::GitBackendError::GitCommandFailed { operation: crate::GitOperation::CloneMirror, exit_code: Some(128), }); let backend = crate::GitBackend::with_runner(config, Box::new(runner)); let source_id_result = source_id("snippets"); assert!(source_id_result.is_some()); let source_id = match source_id_result { Some(value) => value, None => return, }; let source_result = crate::GitSourceConfig::remote(source_id, "https://user:secret@example.invalid/snippets.git"); assert!(source_result.is_ok()); let source = match source_result { Ok(value) => value, Err(_) => return, }; let result = backend.ensure_mirror(&source); assert!(result.is_err()); let error = match result { Ok(_) => return, Err(value) => value, }; let display = error.to_string(); assert!(!display.contains("secret")); assert!(!display.contains("example.invalid")); assert_eq!( error, crate::GitBackendError::GitCommandFailed { operation: crate::GitOperation::CloneMirror, exit_code: Some(128), } ); let _ = std::fs::remove_dir_all(root); return; } #[test] fn existing_mirror_is_inspected_without_clone() { let root = test_root("existing-mirror"); let config_result = crate::GitBackendConfig::new(root.clone()); assert!(config_result.is_ok()); let config = match config_result { Ok(value) => value, Err(_) => return, }; let runner = RecordingRunner::successful(); let backend = crate::GitBackend::with_runner(config, Box::new(runner.clone())); let source_result = source_id("pgr"); assert!(source_result.is_some()); let source_id = match source_result { Some(value) => value, None => return, }; let repository_path = backend.repository_path(&source_id); assert!(std::fs::create_dir_all(&repository_path).is_ok()); let source_result = crate::GitSourceConfig::remote(source_id, "https://example.invalid/pgr.git"); assert!(source_result.is_ok()); let source = match source_result { Ok(value) => value, Err(_) => return, }; let result = backend.ensure_mirror(&source); assert!(result.is_ok()); let mirror = match result { Ok(value) => value, Err(_) => return, }; assert_eq!(mirror.status(), crate::GitMirrorStatus::Existing); let calls = runner.calls.borrow(); assert_eq!(calls.len(), 1); assert_eq!(calls[0].operation, crate::GitOperation::InspectMirror); let _ = std::fs::remove_dir_all(root); return; } #[test] fn invalid_existing_mirror_is_rejected_without_deleting_it() { let root = test_root("invalid-mirror"); let config_result = crate::GitBackendConfig::new(root.clone()); assert!(config_result.is_ok()); let config = match config_result { Ok(value) => value, Err(_) => return, }; let runner = RecordingRunner::with_inspection_stdout(b"false\n"); let backend = crate::GitBackend::with_runner(config, Box::new(runner)); let source_result = source_id("pgr"); assert!(source_result.is_some()); let source_id = match source_result { Some(value) => value, None => return, }; let repository_path = backend.repository_path(&source_id); assert!(std::fs::create_dir_all(&repository_path).is_ok()); let result = backend.inspect_mirror(&source_id); assert_eq!(result, Err(crate::GitBackendError::InvalidMirror)); assert!(repository_path.is_dir()); let _ = std::fs::remove_dir_all(root); return; }