201 lines
7.9 KiB
Rust
201 lines
7.9 KiB
Rust
// file: crates/knowledge-git-lib/tests/git_read_path.rs
|
|
// version: 2
|
|
|
|
//! Integration tests for the real generic Git read path using local temporary repositories.
|
|
|
|
fn test_root(label: &str) -> std::path::PathBuf {
|
|
let nanos_result = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH);
|
|
let nanos = match nanos_result {
|
|
Ok(value) => value.as_nanos(),
|
|
Err(_) => 0,
|
|
};
|
|
let mut path = std::env::temp_dir();
|
|
path.push(format!("sasedev-knowledge-git-integration-{label}-{}-{nanos}", std::process::id()));
|
|
let _ = std::fs::remove_dir_all(&path);
|
|
return path;
|
|
}
|
|
|
|
fn run_git(repository: &std::path::Path, arguments: &[&str]) -> bool {
|
|
let mut command = std::process::Command::new("git");
|
|
command.current_dir(repository);
|
|
command.args(arguments);
|
|
command.env("GIT_TERMINAL_PROMPT", "0");
|
|
let status_result = command.status();
|
|
match status_result {
|
|
Ok(status) => return status.success(),
|
|
Err(_) => return false,
|
|
}
|
|
}
|
|
|
|
fn prepare_source(root: &std::path::Path) -> Option<std::path::PathBuf> {
|
|
let source = root.join("source");
|
|
if std::fs::create_dir_all(&source).is_err() {
|
|
return None;
|
|
}
|
|
if !run_git(&source, &["init", "-b", "main"]) {
|
|
return None;
|
|
}
|
|
if !run_git(&source, &["config", "user.name", "Knowledge Test"]) {
|
|
return None;
|
|
}
|
|
if !run_git(&source, &["config", "user.email", "knowledge@example.invalid"]) {
|
|
return None;
|
|
}
|
|
if !run_git(&source, &["config", "commit.gpgsign", "false"]) {
|
|
return None;
|
|
}
|
|
if std::fs::write(source.join("content.txt"), "first\n").is_err() {
|
|
return None;
|
|
}
|
|
if !run_git(&source, &["add", "content.txt"]) {
|
|
return None;
|
|
}
|
|
if !run_git(&source, &["commit", "-m", "first"]) {
|
|
return None;
|
|
}
|
|
return Some(source);
|
|
}
|
|
|
|
fn source_id() -> Option<knowledge_domain_lib::SourceId> {
|
|
let result = knowledge_domain_lib::SourceId::new("integration-source");
|
|
match result {
|
|
Ok(value) => return Some(value),
|
|
Err(_) => return None,
|
|
}
|
|
}
|
|
|
|
fn configured_backend(root: &std::path::Path, source: &std::path::Path) -> Option<(knowledge_git_lib::GitBackend, knowledge_domain_lib::SourceId)> {
|
|
let source_id_result = source_id();
|
|
let source_id = match source_id_result {
|
|
Some(value) => value,
|
|
None => return None,
|
|
};
|
|
let config_result = knowledge_git_lib::GitBackendConfig::new(root.join("state"));
|
|
let config = match config_result {
|
|
Ok(value) => value,
|
|
Err(_) => return None,
|
|
};
|
|
let source_result = knowledge_git_lib::GitSourceConfig::local(source_id.clone(), source.to_path_buf());
|
|
let source_config = match source_result {
|
|
Ok(value) => value,
|
|
Err(_) => return None,
|
|
};
|
|
let mut backend = knowledge_git_lib::GitBackend::new(config);
|
|
if backend.register_source(source_config).is_err() {
|
|
return None;
|
|
}
|
|
return Some((backend, source_id));
|
|
}
|
|
|
|
#[test]
|
|
fn real_local_repository_refreshes_resolves_and_materializes_revision_snapshots() {
|
|
let root = test_root("refresh-resolve-snapshot");
|
|
let source_result = prepare_source(&root);
|
|
assert!(source_result.is_some());
|
|
let source = match source_result {
|
|
Some(value) => value,
|
|
None => return,
|
|
};
|
|
let backend_result = configured_backend(&root, &source);
|
|
assert!(backend_result.is_some());
|
|
let (mut backend, source_id) = match backend_result {
|
|
Some(value) => value,
|
|
None => return,
|
|
};
|
|
let reference = knowledge_git_api::GitReference::new("refs/heads/main");
|
|
assert!(knowledge_git_api::GitRepository::refresh(&mut backend, &source_id).is_ok());
|
|
let first_revision_result = knowledge_git_api::GitRepository::resolve_revision(&backend, &source_id, &reference);
|
|
assert!(first_revision_result.is_ok());
|
|
let first_revision = match first_revision_result {
|
|
Ok(value) => value,
|
|
Err(_) => return,
|
|
};
|
|
let first_snapshot_result = knowledge_git_api::GitRepository::prepare_snapshot(&backend, &source_id, &first_revision);
|
|
assert!(first_snapshot_result.is_ok());
|
|
let first_snapshot = match first_snapshot_result {
|
|
Ok(value) => value,
|
|
Err(_) => return,
|
|
};
|
|
assert!(first_snapshot.path().is_dir());
|
|
let first_content_result = std::fs::read_to_string(first_snapshot.path().join("content.txt"));
|
|
assert!(first_content_result.is_ok());
|
|
let first_content = match first_content_result {
|
|
Ok(value) => value,
|
|
Err(_) => return,
|
|
};
|
|
assert_eq!(first_content, "first\n");
|
|
let repeated_snapshot_result = knowledge_git_api::GitRepository::prepare_snapshot(&backend, &source_id, &first_revision);
|
|
assert!(repeated_snapshot_result.is_ok());
|
|
let repeated_snapshot = match repeated_snapshot_result {
|
|
Ok(value) => value,
|
|
Err(_) => return,
|
|
};
|
|
assert_eq!(first_snapshot.path(), repeated_snapshot.path());
|
|
assert!(std::fs::write(source.join("content.txt"), "second\n").is_ok());
|
|
assert!(run_git(&source, &["add", "content.txt"]));
|
|
assert!(run_git(&source, &["commit", "-m", "second"]));
|
|
assert!(knowledge_git_api::GitRepository::refresh(&mut backend, &source_id).is_ok());
|
|
let second_revision_result = knowledge_git_api::GitRepository::resolve_revision(&backend, &source_id, &reference);
|
|
assert!(second_revision_result.is_ok());
|
|
let second_revision = match second_revision_result {
|
|
Ok(value) => value,
|
|
Err(_) => return,
|
|
};
|
|
assert_ne!(first_revision, second_revision);
|
|
let second_snapshot_result = knowledge_git_api::GitRepository::prepare_snapshot(&backend, &source_id, &second_revision);
|
|
assert!(second_snapshot_result.is_ok());
|
|
let second_snapshot = match second_snapshot_result {
|
|
Ok(value) => value,
|
|
Err(_) => return,
|
|
};
|
|
assert_ne!(first_snapshot.path(), second_snapshot.path());
|
|
let second_content_result = std::fs::read_to_string(second_snapshot.path().join("content.txt"));
|
|
assert!(second_content_result.is_ok());
|
|
let second_content = match second_content_result {
|
|
Ok(value) => value,
|
|
Err(_) => return,
|
|
};
|
|
assert_eq!(second_content, "second\n");
|
|
let _ = std::fs::remove_dir_all(&root);
|
|
return;
|
|
}
|
|
|
|
#[test]
|
|
fn invalid_reference_and_dirty_existing_snapshot_are_rejected() {
|
|
let root = test_root("invalid-and-dirty");
|
|
let source_result = prepare_source(&root);
|
|
assert!(source_result.is_some());
|
|
let source = match source_result {
|
|
Some(value) => value,
|
|
None => return,
|
|
};
|
|
let backend_result = configured_backend(&root, &source);
|
|
assert!(backend_result.is_some());
|
|
let (mut backend, source_id) = match backend_result {
|
|
Some(value) => value,
|
|
None => return,
|
|
};
|
|
assert!(knowledge_git_api::GitRepository::refresh(&mut backend, &source_id).is_ok());
|
|
let missing_reference = knowledge_git_api::GitReference::new("refs/heads/does-not-exist");
|
|
let missing_result = knowledge_git_api::GitRepository::resolve_revision(&backend, &source_id, &missing_reference);
|
|
assert!(missing_result.is_err());
|
|
let reference = knowledge_git_api::GitReference::new("refs/heads/main");
|
|
let revision_result = knowledge_git_api::GitRepository::resolve_revision(&backend, &source_id, &reference);
|
|
assert!(revision_result.is_ok());
|
|
let revision = match revision_result {
|
|
Ok(value) => value,
|
|
Err(_) => return,
|
|
};
|
|
let snapshot_result = knowledge_git_api::GitRepository::prepare_snapshot(&backend, &source_id, &revision);
|
|
assert!(snapshot_result.is_ok());
|
|
let snapshot = match snapshot_result {
|
|
Ok(value) => value,
|
|
Err(_) => return,
|
|
};
|
|
assert!(std::fs::write(snapshot.path().join("content.txt"), "dirty\n").is_ok());
|
|
let repeated_result = knowledge_git_api::GitRepository::prepare_snapshot(&backend, &source_id, &revision);
|
|
assert_eq!(repeated_result, Err(knowledge_git_lib::GitBackendError::InvalidSnapshot));
|
|
let _ = std::fs::remove_dir_all(&root);
|
|
return;
|
|
}
|