add more tests

This commit is contained in:
Nikita Galaiko 2023-04-18 10:34:02 +02:00
parent 56ae8a9888
commit be8b3e7560
7 changed files with 219 additions and 83 deletions

View File

@ -238,9 +238,7 @@ impl App {
.ok_or_else(|| anyhow::anyhow!("project {} not found", project_id))?;
let mut sessions = vec![];
let mut iter = gb_repository.get_sessions_iterator()?.skip(1); // skip the first session,
// as it's the initial
// session
let mut iter = gb_repository.get_sessions_iterator()?;
while let Some(session) = iter.next() {
if let Err(e) = session {
return Err(e);

View File

@ -193,7 +193,7 @@ impl Repository {
}
let wd_tree_oid = build_wd_tree(&self, &project_repository)
.context("failed to build workign directory tree")?;
.context("failed to build working directory tree")?;
let session_tree_oid = build_session_tree(&self).context("failed to build session tree")?;
let log_tree_oid =
build_log_tree(&self, &project_repository).context("failed to build logs tree")?;
@ -296,10 +296,6 @@ impl Repository {
pub(crate) fn session_wd_path(&self) -> std::path::PathBuf {
self.session_path().join("wd")
}
pub(crate) fn wd_path(&self) -> std::path::PathBuf {
self.root().join("wd")
}
}
// build wd index from the working directory files new session wd files
@ -363,6 +359,7 @@ fn build_wd_tree(
}
let file_path = std::path::Path::new(&file_path);
if project_repository
.git_repository
.is_path_ignored(&file_path)

View File

@ -57,7 +57,7 @@ fn test_get_current_session_writer_should_use_existing_session() -> Result<()> {
}
#[test]
fn test_must_flush_on_init() -> Result<()> {
fn test_must_not_return_init_session() -> Result<()> {
let repository = test_repository()?;
let project = test_project(&repository)?;
let gb_repo_path = tempdir()?.path().to_str().unwrap().to_string();
@ -72,10 +72,11 @@ fn test_must_flush_on_init() -> Result<()> {
user_store,
)?;
let iter = gb_repo.get_sessions_iterator()?;
assert_eq!(iter.count(), 1);
assert!(gb_repo.get_current_session()?.is_none());
let iter = gb_repo.get_sessions_iterator()?;
assert_eq!(iter.count(), 0);
Ok(())
}
@ -96,10 +97,10 @@ fn test_must_not_flush_without_current_session() -> Result<()> {
)?;
let session = gb_repo.flush()?;
assert!(session.is_none());
let iter = gb_repo.get_sessions_iterator()?;
assert_eq!(iter.count(), 1);
assert!(session.is_none());
assert_eq!(iter.count(), 0);
Ok(())
}
@ -123,10 +124,9 @@ fn test_must_flush_current_session() -> Result<()> {
gb_repo.get_or_create_current_session()?;
let session = gb_repo.flush()?;
let iter = gb_repo.get_sessions_iterator()?;
assert_eq!(iter.count(), 2);
assert!(session.is_some());
let iter = gb_repo.get_sessions_iterator()?;
assert_eq!(iter.count(), 1);
Ok(())
}
@ -209,3 +209,72 @@ fn test_list_deltas_from_flushed_session() -> Result<()> {
Ok(())
}
#[test]
fn test_list_files_from_current_session() -> Result<()> {
let repository = test_repository()?;
let project = test_project(&repository)?;
let gb_repo_path = tempdir()?.path().to_str().unwrap().to_string();
let storage = storage::Storage::from_path(tempdir()?.path().to_path_buf());
let project_store = projects::Storage::new(storage.clone());
project_store.add_project(&project)?;
let user_store = users::Storage::new(storage);
// files are there before the session is created
std::fs::write(
repository.path().parent().unwrap().join("test.txt"),
"Hello World",
)?;
let gb_repo = gb_repository::Repository::open(
gb_repo_path,
project.id.clone(),
project_store.clone(),
user_store,
)?;
let session = gb_repo.get_or_create_current_session()?;
let reader = gb_repo.get_session_reader(session)?;
let files = reader.files(None)?;
assert_eq!(files.len(), 1);
assert_eq!(files.get("test.txt").unwrap(), "Hello World");
Ok(())
}
#[test]
fn test_list_files_from_flushed_session() -> Result<()> {
let repository = test_repository()?;
let project = test_project(&repository)?;
let gb_repo_path = tempdir()?.path().to_str().unwrap().to_string();
let storage = storage::Storage::from_path(tempdir()?.path().to_path_buf());
let project_store = projects::Storage::new(storage.clone());
project_store.add_project(&project)?;
let user_store = users::Storage::new(storage);
// files are there before the session is created
std::fs::write(
repository.path().parent().unwrap().join("test.txt"),
"Hello World",
)?;
let gb_repo = gb_repository::Repository::open(
gb_repo_path,
project.id.clone(),
project_store.clone(),
user_store,
)?;
gb_repo.get_or_create_current_session()?;
let session = gb_repo.flush()?.unwrap();
let reader = gb_repo.get_session_reader(session)?;
let files = reader.files(None)?;
assert_eq!(files.len(), 1);
assert_eq!(files.get("test.txt").unwrap(), "Hello World");
Ok(())
}

View File

@ -144,32 +144,34 @@ impl Reader for CommitReader<'_> {
fn list_files(&self, dir_path: &str) -> Result<Vec<String>> {
let mut files: Vec<String> = Vec::new();
let repo_root = self.repository.path().parent().unwrap();
let dir_path = std::path::Path::new(dir_path);
self.tree
.walk(git2::TreeWalkMode::PreOrder, |root, entry| {
if entry.name().is_none() {
return git2::TreeWalkResult::Ok;
}
let abs_dir_path = repo_root.join(dir_path);
let abs_entry_path = repo_root.join(root).join(entry.name().unwrap());
if !abs_entry_path.starts_with(&abs_dir_path) {
return git2::TreeWalkResult::Ok;
}
if abs_dir_path.eq(&abs_entry_path) {
return git2::TreeWalkResult::Ok;
}
if entry.kind() == Some(git2::ObjectType::Tree) {
return git2::TreeWalkResult::Ok;
}
let relpath = abs_entry_path.strip_prefix(abs_dir_path).unwrap();
if entry.name().is_none() {
return git2::TreeWalkResult::Ok;
}
let entry_path = std::path::Path::new(root).join(entry.name().unwrap());
files.push(relpath.to_str().unwrap().to_string());
if !entry_path.starts_with(dir_path) {
return git2::TreeWalkResult::Ok;
}
files.push(
entry_path
.strip_prefix(dir_path)
.unwrap()
.to_str()
.unwrap()
.to_string(),
);
git2::TreeWalkResult::Ok
})
.with_context(|| format!("{}: tree walk failed", dir_path))?;
.with_context(|| format!("{}: tree walk failed", dir_path.display()))?;
Ok(files)
}

View File

@ -76,6 +76,22 @@ fn test_commit_reader_read_file() -> Result<()> {
Ok(())
}
#[test]
fn test_reader_list_files_should_return_relative() -> Result<()> {
let dir = tempdir()?;
std::fs::write(dir.path().join("test1.txt"), "test")?;
std::fs::create_dir(dir.path().join("dir"))?;
std::fs::write(dir.path().join("dir").join("test.txt"), "test")?;
let reader = super::reader::DirReader::open(dir.path().to_path_buf());
let files = reader.list_files("dir")?;
assert_eq!(files.len(), 1);
assert!(files.contains(&"test.txt".to_string()));
Ok(())
}
#[test]
fn test_reader_list_files() -> Result<()> {
let dir = tempdir()?;
@ -85,7 +101,7 @@ fn test_reader_list_files() -> Result<()> {
std::fs::write(dir.path().join("dir").join("test.txt"), "test")?;
let reader = super::reader::DirReader::open(dir.path().to_path_buf());
let files = reader.list_files(".")?;
let files = reader.list_files("")?;
assert_eq!(files.len(), 2);
assert!(files.contains(&"test.txt".to_string()));
assert!(files.contains(&"dir/test.txt".to_string()));
@ -93,6 +109,38 @@ fn test_reader_list_files() -> Result<()> {
Ok(())
}
#[test]
fn test_commit_reader_list_files_should_return_relative() -> Result<()> {
let repository = test_repository()?;
std::fs::write(
&repository.path().parent().unwrap().join("test1.txt"),
"test",
)?;
std::fs::create_dir(&repository.path().parent().unwrap().join("dir"))?;
std::fs::write(
&repository
.path()
.parent()
.unwrap()
.join("dir")
.join("test.txt"),
"test",
)?;
let oid = commit(&repository)?;
std::fs::remove_dir_all(&repository.path().parent().unwrap().join("dir"))?;
let reader =
super::reader::CommitReader::from_commit(&repository, repository.find_commit(oid)?)?;
let files = reader.list_files("dir")?;
assert_eq!(files.len(), 1);
assert!(files.contains(&"test.txt".to_string()));
Ok(())
}
#[test]
fn test_commit_reader_list_files() -> Result<()> {
let repository = test_repository()?;
@ -118,7 +166,7 @@ fn test_commit_reader_list_files() -> Result<()> {
let reader =
super::reader::CommitReader::from_commit(&repository, repository.find_commit(oid)?)?;
let files = reader.list_files(".")?;
let files = reader.list_files("")?;
assert_eq!(files.len(), 2);
assert!(files.contains(&"test.txt".to_string()));
assert!(files.contains(&"dir/test.txt".to_string()));

View File

@ -6,7 +6,7 @@ use crate::{deltas, pty, sessions};
use super::{
gb_repository,
reader::{self, Reader},
reader::{self, CommitReader, Reader},
writer::{self, Writer},
};
@ -191,8 +191,10 @@ impl<'writer> SessionWriter<'writer> {
}
pub struct SessionReader<'reader> {
repository: &'reader gb_repository::Repository,
// reader for the current session. commit or wd
reader: Box<dyn reader::Reader + 'reader>,
// reader for the previous session's commit
previous_reader: Option<CommitReader<'reader>>,
}
impl Reader for SessionReader<'_> {
@ -229,9 +231,13 @@ impl<'reader> SessionReader<'reader> {
.unwrap(),
);
if current_session_id.is_ok() && current_session_id.as_ref().unwrap() == &session.id {
let head_commit = repository.git_repository.head()?.peel_to_commit()?;
return Ok(SessionReader {
reader: Box::new(wd_reader),
repository,
previous_reader: Some(CommitReader::from_commit(
&repository.git_repository,
head_commit,
)?),
});
}
@ -251,35 +257,49 @@ impl<'reader> SessionReader<'reader> {
.git_repository
.find_commit(oid)
.context("failed to get commit")?;
let commit_reader = reader::CommitReader::from_commit(&repository.git_repository, commit)?;
let parents_count = commit.parent_count();
let commit_reader =
reader::CommitReader::from_commit(&repository.git_repository, commit.clone())?;
let previous_reader = if parents_count > 0 {
Some(reader::CommitReader::from_commit(
&repository.git_repository,
commit.parent(0)?,
)?)
} else {
None
};
Ok(SessionReader {
reader: Box::new(commit_reader),
repository,
previous_reader,
})
}
pub fn files(&self, paths: Option<Vec<&str>>) -> Result<HashMap<String, String>> {
let files = self
.reader
.list_files(&self.repository.wd_path().to_str().unwrap())?;
let files_with_content = files
.iter()
.filter(|file| {
if let Some(paths) = paths.as_ref() {
paths.iter().any(|path| file.starts_with(path))
} else {
true
match &self.previous_reader {
None => Ok(HashMap::new()),
Some(previous_reader) => {
let files = previous_reader.list_files("wd")?;
let mut files_with_content = HashMap::new();
for file_path in files {
if let Some(paths) = paths.as_ref() {
if !paths.iter().any(|path| file_path.starts_with(path)) {
continue;
}
}
let file_content = previous_reader.read_to_string(
std::path::Path::new("wd")
.join(file_path.clone())
.to_str()
.unwrap(),
)?;
files_with_content.insert(file_path, file_content);
}
})
.map(|file| {
let content = self
.reader
.read_to_string(&self.repository.wd_path().join(file).to_str().unwrap())
.unwrap();
(file.to_string(), content)
})
.collect();
Ok(files_with_content)
Ok(files_with_content)
}
}
}
pub fn file_deltas<P: AsRef<std::path::Path>>(
@ -287,8 +307,11 @@ impl<'reader> SessionReader<'reader> {
paths: P,
) -> Result<Option<Vec<deltas::Delta>>> {
let path = paths.as_ref();
let deltas_path = self.repository.deltas_path().join(path);
match self.reader.read_to_string(deltas_path.to_str().unwrap()) {
let file_deltas_path = std::path::Path::new("session/deltas").join(path);
match self
.reader
.read_to_string(file_deltas_path.to_str().unwrap())
{
Ok(content) => Ok(Some(serde_json::from_str(&content)?)),
Err(reader::Error::NotFound) => Ok(None),
Err(err) => Err(err.into()),
@ -296,27 +319,20 @@ impl<'reader> SessionReader<'reader> {
}
pub fn deltas(&self, paths: Option<Vec<&str>>) -> Result<HashMap<String, Vec<deltas::Delta>>> {
let dir = std::path::Path::new("session/deltas");
let files = self.reader.list_files(dir.to_str().unwrap())?;
let files_with_content = files
.iter()
.filter(|file| {
if let Some(paths) = paths.as_ref() {
paths.iter().any(|path| file.starts_with(path))
} else {
true
let deltas_dir = std::path::Path::new("session/deltas");
let files = self.reader.list_files(deltas_dir.to_str().unwrap())?;
let mut result = HashMap::new();
for file_path in files {
if let Some(paths) = paths.as_ref() {
if !paths.iter().any(|path| file_path.starts_with(path)) {
continue;
}
})
.map(|file| {
let content = self
.reader
.read_to_string(dir.join(file).to_str().unwrap())
.unwrap();
let deltas: Vec<deltas::Delta> = serde_json::from_str(&content).unwrap();
(file.to_string(), deltas)
})
.collect();
Ok(files_with_content)
}
if let Some(deltas) = self.file_deltas(file_path.clone())? {
result.insert(file_path, deltas);
}
}
Ok(result)
}
}
@ -350,6 +366,13 @@ impl<'iterator> Iterator for SessionsIterator<'iterator> {
Result::Ok(commit) => commit,
Err(err) => return Some(Err(err.into())),
};
if commit.parent_count() == 0 {
// skip initial commit, as it's impossible to get a list of files from it
// it's only used to bootstrap the history
return None;
}
let commit_reader =
match reader::CommitReader::from_commit(self.git_repository, commit) {
Result::Ok(commit_reader) => commit_reader,

View File

@ -98,8 +98,7 @@ impl Deltas {
pub fn reindex_project(&mut self, repository: &app::gb_repository::Repository) -> Result<()> {
let mut sessions = repository
.get_sessions_iterator()
.with_context(|| "Could not list sessions for project")?
.skip(1);
.with_context(|| "Could not list sessions for project")?;
while let Some(session) = sessions.next() {
let session = session.with_context(|| "Could not read session")?;