Add randomized test for git statuses
This commit is contained in:
parent
9800a149a6
commit
fca3bb3b93
3 changed files with 207 additions and 94 deletions
|
@ -1576,6 +1576,45 @@ impl Database {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Repository Status Entries
|
||||||
|
for repository in worktree.updated_repositories.iter_mut() {
|
||||||
|
let repository_status_entry_filter =
|
||||||
|
if let Some(rejoined_worktree) = rejoined_worktree {
|
||||||
|
worktree_repository_statuses::Column::ScanId
|
||||||
|
.gt(rejoined_worktree.scan_id)
|
||||||
|
} else {
|
||||||
|
worktree_repository_statuses::Column::IsDeleted.eq(false)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut db_repository_statuses =
|
||||||
|
worktree_repository_statuses::Entity::find()
|
||||||
|
.filter(
|
||||||
|
Condition::all()
|
||||||
|
.add(
|
||||||
|
worktree_repository_statuses::Column::WorktreeId
|
||||||
|
.eq(worktree.id),
|
||||||
|
)
|
||||||
|
.add(
|
||||||
|
worktree_repository_statuses::Column::WorkDirectoryId
|
||||||
|
.eq(repository.work_directory_id),
|
||||||
|
)
|
||||||
|
.add(repository_status_entry_filter),
|
||||||
|
)
|
||||||
|
.stream(&*tx)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
while let Some(db_status_entry) = db_repository_statuses.next().await {
|
||||||
|
let db_status_entry = db_status_entry?;
|
||||||
|
if db_status_entry.is_deleted {
|
||||||
|
repository.removed_worktree_repo_paths.push(db_status_entry.repo_path);
|
||||||
|
} else {
|
||||||
|
repository.updated_worktree_statuses.push(proto::StatusEntry {
|
||||||
|
repo_path: db_status_entry.repo_path, status: db_status_entry.status as i32
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
worktrees.push(worktree);
|
worktrees.push(worktree);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ use call::ActiveCall;
|
||||||
use client::RECEIVE_TIMEOUT;
|
use client::RECEIVE_TIMEOUT;
|
||||||
use collections::BTreeMap;
|
use collections::BTreeMap;
|
||||||
use editor::Bias;
|
use editor::Bias;
|
||||||
use fs::{FakeFs, Fs as _};
|
use fs::{repository::GitFileStatus, FakeFs, Fs as _};
|
||||||
use futures::StreamExt as _;
|
use futures::StreamExt as _;
|
||||||
use gpui::{executor::Deterministic, ModelHandle, Task, TestAppContext};
|
use gpui::{executor::Deterministic, ModelHandle, Task, TestAppContext};
|
||||||
use language::{range_to_lsp, FakeLspAdapter, Language, LanguageConfig, PointUtf16};
|
use language::{range_to_lsp, FakeLspAdapter, Language, LanguageConfig, PointUtf16};
|
||||||
|
@ -32,6 +32,7 @@ use std::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
static ref PLAN_LOAD_PATH: Option<PathBuf> = path_env_var("LOAD_PLAN");
|
static ref PLAN_LOAD_PATH: Option<PathBuf> = path_env_var("LOAD_PLAN");
|
||||||
|
@ -763,53 +764,81 @@ async fn apply_client_operation(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientOperation::WriteGitIndex {
|
ClientOperation::GitOperation { operation } => match operation {
|
||||||
repo_path,
|
GitOperation::WriteGitIndex {
|
||||||
contents,
|
|
||||||
} => {
|
|
||||||
if !client.fs.directories().contains(&repo_path) {
|
|
||||||
return Err(TestError::Inapplicable);
|
|
||||||
}
|
|
||||||
|
|
||||||
log::info!(
|
|
||||||
"{}: writing git index for repo {:?}: {:?}",
|
|
||||||
client.username,
|
|
||||||
repo_path,
|
repo_path,
|
||||||
contents
|
contents,
|
||||||
);
|
} => {
|
||||||
|
if !client.fs.directories().contains(&repo_path) {
|
||||||
|
return Err(TestError::Inapplicable);
|
||||||
|
}
|
||||||
|
|
||||||
let dot_git_dir = repo_path.join(".git");
|
log::info!(
|
||||||
let contents = contents
|
"{}: writing git index for repo {:?}: {:?}",
|
||||||
.iter()
|
client.username,
|
||||||
.map(|(path, contents)| (path.as_path(), contents.clone()))
|
repo_path,
|
||||||
.collect::<Vec<_>>();
|
contents
|
||||||
if client.fs.metadata(&dot_git_dir).await?.is_none() {
|
);
|
||||||
client.fs.create_dir(&dot_git_dir).await?;
|
|
||||||
|
let dot_git_dir = repo_path.join(".git");
|
||||||
|
let contents = contents
|
||||||
|
.iter()
|
||||||
|
.map(|(path, contents)| (path.as_path(), contents.clone()))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
if client.fs.metadata(&dot_git_dir).await?.is_none() {
|
||||||
|
client.fs.create_dir(&dot_git_dir).await?;
|
||||||
|
}
|
||||||
|
client.fs.set_index_for_repo(&dot_git_dir, &contents).await;
|
||||||
}
|
}
|
||||||
client.fs.set_index_for_repo(&dot_git_dir, &contents).await;
|
GitOperation::WriteGitBranch {
|
||||||
}
|
|
||||||
|
|
||||||
ClientOperation::WriteGitBranch {
|
|
||||||
repo_path,
|
|
||||||
new_branch,
|
|
||||||
} => {
|
|
||||||
if !client.fs.directories().contains(&repo_path) {
|
|
||||||
return Err(TestError::Inapplicable);
|
|
||||||
}
|
|
||||||
|
|
||||||
log::info!(
|
|
||||||
"{}: writing git branch for repo {:?}: {:?}",
|
|
||||||
client.username,
|
|
||||||
repo_path,
|
repo_path,
|
||||||
new_branch
|
new_branch,
|
||||||
);
|
} => {
|
||||||
|
if !client.fs.directories().contains(&repo_path) {
|
||||||
|
return Err(TestError::Inapplicable);
|
||||||
|
}
|
||||||
|
|
||||||
let dot_git_dir = repo_path.join(".git");
|
log::info!(
|
||||||
if client.fs.metadata(&dot_git_dir).await?.is_none() {
|
"{}: writing git branch for repo {:?}: {:?}",
|
||||||
client.fs.create_dir(&dot_git_dir).await?;
|
client.username,
|
||||||
|
repo_path,
|
||||||
|
new_branch
|
||||||
|
);
|
||||||
|
|
||||||
|
let dot_git_dir = repo_path.join(".git");
|
||||||
|
if client.fs.metadata(&dot_git_dir).await?.is_none() {
|
||||||
|
client.fs.create_dir(&dot_git_dir).await?;
|
||||||
|
}
|
||||||
|
client.fs.set_branch_name(&dot_git_dir, new_branch).await;
|
||||||
}
|
}
|
||||||
client.fs.set_branch_name(&dot_git_dir, new_branch).await;
|
GitOperation::WriteGitStatuses {
|
||||||
}
|
repo_path,
|
||||||
|
statuses,
|
||||||
|
} => {
|
||||||
|
if !client.fs.directories().contains(&repo_path) {
|
||||||
|
return Err(TestError::Inapplicable);
|
||||||
|
}
|
||||||
|
|
||||||
|
log::info!(
|
||||||
|
"{}: writing git statuses for repo {:?}: {:?}",
|
||||||
|
client.username,
|
||||||
|
repo_path,
|
||||||
|
statuses
|
||||||
|
);
|
||||||
|
|
||||||
|
let dot_git_dir = repo_path.join(".git");
|
||||||
|
|
||||||
|
let statuses = statuses.iter()
|
||||||
|
.map(|(path, val)| (path.as_path(), val.clone()))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
if client.fs.metadata(&dot_git_dir).await?.is_none() {
|
||||||
|
client.fs.create_dir(&dot_git_dir).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
client.fs.set_status_for_repo(&dot_git_dir, statuses.as_slice()).await;
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1178,6 +1207,13 @@ enum ClientOperation {
|
||||||
is_dir: bool,
|
is_dir: bool,
|
||||||
content: String,
|
content: String,
|
||||||
},
|
},
|
||||||
|
GitOperation {
|
||||||
|
operation: GitOperation,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
enum GitOperation {
|
||||||
WriteGitIndex {
|
WriteGitIndex {
|
||||||
repo_path: PathBuf,
|
repo_path: PathBuf,
|
||||||
contents: Vec<(PathBuf, String)>,
|
contents: Vec<(PathBuf, String)>,
|
||||||
|
@ -1186,6 +1222,10 @@ enum ClientOperation {
|
||||||
repo_path: PathBuf,
|
repo_path: PathBuf,
|
||||||
new_branch: Option<String>,
|
new_branch: Option<String>,
|
||||||
},
|
},
|
||||||
|
WriteGitStatuses {
|
||||||
|
repo_path: PathBuf,
|
||||||
|
statuses: Vec<(PathBuf, GitFileStatus)>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
@ -1698,57 +1738,10 @@ impl TestPlan {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update a git index
|
// Update a git related action
|
||||||
91..=93 => {
|
91..=95 => {
|
||||||
let repo_path = client
|
break ClientOperation::GitOperation {
|
||||||
.fs
|
operation: self.generate_git_operation(client),
|
||||||
.directories()
|
|
||||||
.into_iter()
|
|
||||||
.choose(&mut self.rng)
|
|
||||||
.unwrap()
|
|
||||||
.clone();
|
|
||||||
|
|
||||||
let mut file_paths = client
|
|
||||||
.fs
|
|
||||||
.files()
|
|
||||||
.into_iter()
|
|
||||||
.filter(|path| path.starts_with(&repo_path))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let count = self.rng.gen_range(0..=file_paths.len());
|
|
||||||
file_paths.shuffle(&mut self.rng);
|
|
||||||
file_paths.truncate(count);
|
|
||||||
|
|
||||||
let mut contents = Vec::new();
|
|
||||||
for abs_child_file_path in &file_paths {
|
|
||||||
let child_file_path = abs_child_file_path
|
|
||||||
.strip_prefix(&repo_path)
|
|
||||||
.unwrap()
|
|
||||||
.to_path_buf();
|
|
||||||
let new_base = Alphanumeric.sample_string(&mut self.rng, 16);
|
|
||||||
contents.push((child_file_path, new_base));
|
|
||||||
}
|
|
||||||
|
|
||||||
break ClientOperation::WriteGitIndex {
|
|
||||||
repo_path,
|
|
||||||
contents,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update a git branch
|
|
||||||
94..=95 => {
|
|
||||||
let repo_path = client
|
|
||||||
.fs
|
|
||||||
.directories()
|
|
||||||
.choose(&mut self.rng)
|
|
||||||
.unwrap()
|
|
||||||
.clone();
|
|
||||||
|
|
||||||
let new_branch = (self.rng.gen_range(0..10) > 3)
|
|
||||||
.then(|| Alphanumeric.sample_string(&mut self.rng, 8));
|
|
||||||
|
|
||||||
break ClientOperation::WriteGitBranch {
|
|
||||||
repo_path,
|
|
||||||
new_branch,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1786,6 +1779,86 @@ impl TestPlan {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn generate_git_operation(&mut self, client: &TestClient) -> GitOperation {
|
||||||
|
fn generate_file_paths(
|
||||||
|
repo_path: &Path,
|
||||||
|
rng: &mut StdRng,
|
||||||
|
client: &TestClient,
|
||||||
|
) -> Vec<PathBuf> {
|
||||||
|
let mut paths = client
|
||||||
|
.fs
|
||||||
|
.files()
|
||||||
|
.into_iter()
|
||||||
|
.filter(|path| path.starts_with(repo_path))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let count = rng.gen_range(0..=paths.len());
|
||||||
|
paths.shuffle(rng);
|
||||||
|
paths.truncate(count);
|
||||||
|
|
||||||
|
paths
|
||||||
|
.iter()
|
||||||
|
.map(|path| path.strip_prefix(repo_path).unwrap().to_path_buf())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
let repo_path = client
|
||||||
|
.fs
|
||||||
|
.directories()
|
||||||
|
.choose(&mut self.rng)
|
||||||
|
.unwrap()
|
||||||
|
.clone();
|
||||||
|
|
||||||
|
match self.rng.gen_range(0..100_u32) {
|
||||||
|
0..=25 => {
|
||||||
|
let file_paths = generate_file_paths(&repo_path, &mut self.rng, client);
|
||||||
|
|
||||||
|
let contents = file_paths
|
||||||
|
.into_iter()
|
||||||
|
.map(|path| (path, Alphanumeric.sample_string(&mut self.rng, 16)))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
GitOperation::WriteGitIndex {
|
||||||
|
repo_path,
|
||||||
|
contents,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
26..=63 => {
|
||||||
|
let new_branch = (self.rng.gen_range(0..10) > 3)
|
||||||
|
.then(|| Alphanumeric.sample_string(&mut self.rng, 8));
|
||||||
|
|
||||||
|
GitOperation::WriteGitBranch {
|
||||||
|
repo_path,
|
||||||
|
new_branch,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
64..=100 => {
|
||||||
|
let file_paths = generate_file_paths(&repo_path, &mut self.rng, client);
|
||||||
|
|
||||||
|
let statuses = file_paths
|
||||||
|
.into_iter()
|
||||||
|
.map(|paths| {
|
||||||
|
(
|
||||||
|
paths,
|
||||||
|
match self.rng.gen_range(0..3_u32) {
|
||||||
|
0 => GitFileStatus::Added,
|
||||||
|
1 => GitFileStatus::Modified,
|
||||||
|
2 => GitFileStatus::Conflict,
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
GitOperation::WriteGitStatuses {
|
||||||
|
repo_path,
|
||||||
|
statuses,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn next_root_dir_name(&mut self, user_id: UserId) -> String {
|
fn next_root_dir_name(&mut self, user_id: UserId) -> String {
|
||||||
let user_ix = self
|
let user_ix = self
|
||||||
.users
|
.users
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
use serde_derive::{Serialize, Deserialize};
|
||||||
use std::{
|
use std::{
|
||||||
ffi::OsStr,
|
ffi::OsStr,
|
||||||
os::unix::prelude::OsStrExt,
|
os::unix::prelude::OsStrExt,
|
||||||
|
@ -183,7 +184,7 @@ fn check_path_to_repo_path_errors(relative_file_path: &Path) -> Result<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub enum GitFileStatus {
|
pub enum GitFileStatus {
|
||||||
Added,
|
Added,
|
||||||
Modified,
|
Modified,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue