Clean up how applications are marked as inapplicable
This commit is contained in:
parent
e04d0be853
commit
1a9ff2420e
1 changed files with 82 additions and 90 deletions
|
@ -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,7 +606,8 @@ 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
|
||||||
|
.update(cx, |call, cx| {
|
||||||
let room = call.room().cloned()?;
|
let room = call.room().cloned()?;
|
||||||
let participant = room
|
let participant = room
|
||||||
.read(cx)
|
.read(cx)
|
||||||
|
@ -627,10 +626,8 @@ async fn apply_client_operation(
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
}))
|
}))
|
||||||
});
|
})
|
||||||
let Some(project) = project else {
|
.ok_or(TestError::Inapplicable)?;
|
||||||
return Ok(false)
|
|
||||||
};
|
|
||||||
|
|
||||||
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| {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue