Clean up how applications are marked as inapplicable

This commit is contained in:
Max Brunsfeld 2023-01-12 22:09:36 -08:00
parent e04d0be853
commit 1a9ff2420e

View file

@ -6,7 +6,7 @@ use crate::{
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use call::ActiveCall; use call::ActiveCall;
use client::RECEIVE_TIMEOUT; use client::RECEIVE_TIMEOUT;
use collections::{BTreeMap, HashSet}; use collections::BTreeMap;
use editor::Bias; use editor::Bias;
use fs::{FakeFs, Fs as _}; use fs::{FakeFs, Fs as _};
use futures::StreamExt as _; use futures::StreamExt as _;
@ -490,12 +490,12 @@ async fn apply_client_operation(
client: &TestClient, client: &TestClient,
operation: ClientOperation, operation: ClientOperation,
cx: &mut TestAppContext, cx: &mut TestAppContext,
) -> Result<bool> { ) -> Result<(), TestError> {
match operation { match operation {
ClientOperation::AcceptIncomingCall => { ClientOperation::AcceptIncomingCall => {
let active_call = cx.read(ActiveCall::global); let active_call = cx.read(ActiveCall::global);
if active_call.read_with(cx, |call, _| call.incoming().borrow().is_none()) { if active_call.read_with(cx, |call, _| call.incoming().borrow().is_none()) {
return Ok(false); Err(TestError::Inapplicable)?;
} }
log::info!("{}: accepting incoming call", client.username); log::info!("{}: accepting incoming call", client.username);
@ -507,7 +507,7 @@ async fn apply_client_operation(
ClientOperation::RejectIncomingCall => { ClientOperation::RejectIncomingCall => {
let active_call = cx.read(ActiveCall::global); let active_call = cx.read(ActiveCall::global);
if active_call.read_with(cx, |call, _| call.incoming().borrow().is_none()) { if active_call.read_with(cx, |call, _| call.incoming().borrow().is_none()) {
return Ok(false); Err(TestError::Inapplicable)?;
} }
log::info!("{}: declining incoming call", client.username); log::info!("{}: declining incoming call", client.username);
@ -517,7 +517,7 @@ async fn apply_client_operation(
ClientOperation::LeaveCall => { ClientOperation::LeaveCall => {
let active_call = cx.read(ActiveCall::global); let active_call = cx.read(ActiveCall::global);
if active_call.read_with(cx, |call, _| call.room().is_none()) { if active_call.read_with(cx, |call, _| call.room().is_none()) {
return Ok(false); Err(TestError::Inapplicable)?;
} }
log::info!("{}: hanging up", client.username); log::info!("{}: hanging up", client.username);
@ -557,9 +557,8 @@ async fn apply_client_operation(
project_root_name, project_root_name,
new_root_path, new_root_path,
} => { } => {
let Some(project) = project_for_root_name(client, &project_root_name, cx) else { let project = project_for_root_name(client, &project_root_name, cx)
return Ok(false) .ok_or(TestError::Inapplicable)?;
};
log::info!( log::info!(
"{}: finding/creating local worktree at {:?} to project with root path {}", "{}: finding/creating local worktree at {:?} to project with root path {}",
@ -581,9 +580,8 @@ async fn apply_client_operation(
} }
ClientOperation::CloseRemoteProject { project_root_name } => { ClientOperation::CloseRemoteProject { project_root_name } => {
let Some(project) = project_for_root_name(client, &project_root_name, cx) else { let project = project_for_root_name(client, &project_root_name, cx)
return Ok(false) .ok_or(TestError::Inapplicable)?;
};
log::info!( log::info!(
"{}: closing remote project with root path {}", "{}: closing remote project with root path {}",
@ -608,29 +606,28 @@ async fn apply_client_operation(
first_root_name, first_root_name,
} => { } => {
let active_call = cx.read(ActiveCall::global); let active_call = cx.read(ActiveCall::global);
let project = active_call.update(cx, |call, cx| { let project = active_call
let room = call.room().cloned()?; .update(cx, |call, cx| {
let participant = room let room = call.room().cloned()?;
.read(cx) let participant = room
.remote_participants() .read(cx)
.get(&host_id.to_proto())?; .remote_participants()
let project_id = participant .get(&host_id.to_proto())?;
.projects let project_id = participant
.iter() .projects
.find(|project| project.worktree_root_names[0] == first_root_name)? .iter()
.id; .find(|project| project.worktree_root_names[0] == first_root_name)?
Some(room.update(cx, |room, cx| { .id;
room.join_project( Some(room.update(cx, |room, cx| {
project_id, room.join_project(
client.language_registry.clone(), project_id,
FakeFs::new(cx.background().clone()), client.language_registry.clone(),
cx, FakeFs::new(cx.background().clone()),
) cx,
})) )
}); }))
let Some(project) = project else { })
return Ok(false) .ok_or(TestError::Inapplicable)?;
};
log::info!( log::info!(
"{}: joining remote project of user {}, root name {}", "{}: joining remote project of user {}, root name {}",
@ -649,12 +646,10 @@ async fn apply_client_operation(
full_path, full_path,
is_dir, is_dir,
} => { } => {
let Some(project) = project_for_root_name(client, &project_root_name, cx) else { let project = project_for_root_name(client, &project_root_name, cx)
return Ok(false); .ok_or(TestError::Inapplicable)?;
}; let project_path = project_path_for_full_path(&project, &full_path, cx)
let Some(project_path) = project_path_for_full_path(&project, &full_path, cx) else { .ok_or(TestError::Inapplicable)?;
return Ok(false);
};
log::info!( log::info!(
"{}: creating {} at path {:?} in {} project {}", "{}: creating {} at path {:?} in {} project {}",
@ -677,12 +672,10 @@ async fn apply_client_operation(
is_local, is_local,
full_path, full_path,
} => { } => {
let Some(project) = project_for_root_name(client, &project_root_name, cx) else { let project = project_for_root_name(client, &project_root_name, cx)
return Ok(false); .ok_or(TestError::Inapplicable)?;
}; let project_path = project_path_for_full_path(&project, &full_path, cx)
let Some(project_path) = project_path_for_full_path(&project, &full_path, cx) else { .ok_or(TestError::Inapplicable)?;
return Ok(false);
};
log::info!( log::info!(
"{}: opening buffer {:?} in {} project {}", "{}: opening buffer {:?} in {} project {}",
@ -705,13 +698,10 @@ async fn apply_client_operation(
full_path, full_path,
edits, edits,
} => { } => {
let Some(project) = project_for_root_name(client, &project_root_name, cx) else { let project = project_for_root_name(client, &project_root_name, cx)
return Ok(false); .ok_or(TestError::Inapplicable)?;
}; let buffer = buffer_for_full_path(client, &project, &full_path, cx)
let Some(buffer) = .ok_or(TestError::Inapplicable)?;
buffer_for_full_path(&*client.buffers_for_project(&project), &full_path, cx) else {
return Ok(false);
};
log::info!( log::info!(
"{}: editing buffer {:?} in {} project {} with {:?}", "{}: editing buffer {:?} in {} project {} with {:?}",
@ -742,13 +732,10 @@ async fn apply_client_operation(
is_local, is_local,
full_path, full_path,
} => { } => {
let Some(project) = project_for_root_name(client, &project_root_name, cx) else { let project = project_for_root_name(client, &project_root_name, cx)
return Ok(false); .ok_or(TestError::Inapplicable)?;
}; let buffer = buffer_for_full_path(client, &project, &full_path, cx)
let Some(buffer) = .ok_or(TestError::Inapplicable)?;
buffer_for_full_path(&*client.buffers_for_project(&project), &full_path, cx) else {
return Ok(false);
};
log::info!( log::info!(
"{}: closing buffer {:?} in {} project {}", "{}: closing buffer {:?} in {} project {}",
@ -771,13 +758,10 @@ async fn apply_client_operation(
full_path, full_path,
detach, detach,
} => { } => {
let Some(project) = project_for_root_name(client, &project_root_name, cx) else { let project = project_for_root_name(client, &project_root_name, cx)
return Ok(false); .ok_or(TestError::Inapplicable)?;
}; let buffer = buffer_for_full_path(client, &project, &full_path, cx)
let Some(buffer) = .ok_or(TestError::Inapplicable)?;
buffer_for_full_path(&*client.buffers_for_project(&project), &full_path, cx) else {
return Ok(false);
};
log::info!( log::info!(
"{}: saving buffer {:?} in {} project {}{}", "{}: saving buffer {:?} in {} project {}{}",
@ -813,13 +797,10 @@ async fn apply_client_operation(
kind, kind,
detach, detach,
} => { } => {
let Some(project) = project_for_root_name(client, &project_root_name, cx) else { let project = project_for_root_name(client, &project_root_name, cx)
return Ok(false); .ok_or(TestError::Inapplicable)?;
}; let buffer = buffer_for_full_path(client, &project, &full_path, cx)
let Some(buffer) = .ok_or(TestError::Inapplicable)?;
buffer_for_full_path(&*client.buffers_for_project(&project), &full_path, cx) else {
return Ok(false);
};
log::info!( log::info!(
"{}: request LSP {:?} for buffer {:?} in {} project {}{}", "{}: request LSP {:?} for buffer {:?} in {} project {}{}",
@ -877,9 +858,8 @@ async fn apply_client_operation(
query, query,
detach, detach,
} => { } => {
let Some(project) = project_for_root_name(client, &project_root_name, cx) else { let project = project_for_root_name(client, &project_root_name, cx)
return Ok(false); .ok_or(TestError::Inapplicable)?;
};
log::info!( log::info!(
"{}: search {} project {} for {:?}{}", "{}: search {} project {} for {:?}{}",
@ -906,9 +886,11 @@ async fn apply_client_operation(
} }
ClientOperation::CreateFsEntry { path, is_dir } => { ClientOperation::CreateFsEntry { path, is_dir } => {
if client.fs.metadata(&path.parent().unwrap()).await?.is_none() { client
return Ok(false); .fs
} .metadata(&path.parent().unwrap())
.await?
.ok_or(TestError::Inapplicable)?;
log::info!( log::info!(
"{}: creating {} at {:?}", "{}: creating {} at {:?}",
@ -938,7 +920,7 @@ async fn apply_client_operation(
.await? .await?
.map_or(false, |m| m.is_dir) .map_or(false, |m| m.is_dir)
{ {
return Ok(false); Err(TestError::Inapplicable)?;
} }
log::info!( log::info!(
@ -959,7 +941,7 @@ async fn apply_client_operation(
client.fs.set_index_for_repo(&dot_git_dir, &contents).await; client.fs.set_index_for_repo(&dot_git_dir, &contents).await;
} }
} }
Ok(true) Ok(())
} }
struct TestPlan { struct TestPlan {
@ -1098,6 +1080,17 @@ enum LspRequestKind {
Highlights, Highlights,
} }
enum TestError {
Inapplicable,
Other(anyhow::Error),
}
impl From<anyhow::Error> for TestError {
fn from(value: anyhow::Error) -> Self {
Self::Other(value)
}
}
impl TestPlan { impl TestPlan {
fn new(mut rng: StdRng, users: Vec<UserTestPlan>, max_operations: usize) -> Self { fn new(mut rng: StdRng, users: Vec<UserTestPlan>, max_operations: usize) -> Self {
Self { Self {
@ -1782,14 +1775,11 @@ async fn simulate_client(
while let Some(batch_id) = operation_rx.next().await { while let Some(batch_id) = operation_rx.next().await {
let Some((operation, skipped)) = plan.lock().next_client_operation(&client, batch_id, &cx) else { break }; let Some((operation, skipped)) = plan.lock().next_client_operation(&client, batch_id, &cx) else { break };
match apply_client_operation(&client, operation, &mut cx).await { match apply_client_operation(&client, operation, &mut cx).await {
Err(error) => { Ok(()) => {}
Err(TestError::Inapplicable) => skipped.store(true, SeqCst),
Err(TestError::Other(error)) => {
log::error!("{} error: {}", client.username, error); log::error!("{} error: {}", client.username, error);
} }
Ok(applied) => {
if !applied {
skipped.store(true, SeqCst);
}
}
} }
cx.background().simulate_random_delay().await; cx.background().simulate_random_delay().await;
} }
@ -1797,11 +1787,13 @@ async fn simulate_client(
} }
fn buffer_for_full_path( fn buffer_for_full_path(
buffers: &HashSet<ModelHandle<language::Buffer>>, client: &TestClient,
project: &ModelHandle<Project>,
full_path: &PathBuf, full_path: &PathBuf,
cx: &TestAppContext, cx: &TestAppContext,
) -> Option<ModelHandle<language::Buffer>> { ) -> Option<ModelHandle<language::Buffer>> {
buffers client
.buffers_for_project(project)
.iter() .iter()
.find(|buffer| { .find(|buffer| {
buffer.read_with(cx, |buffer, cx| { buffer.read_with(cx, |buffer, cx| {