mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-09 10:56:20 +00:00
Tweak operation rates
This commit is contained in:
parent
f243633f3e
commit
f1b3692a35
1 changed files with 133 additions and 104 deletions
|
@ -230,11 +230,7 @@ async fn test_random_collaboration(
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Operation::RunUntilParked => {
|
Operation::MutateClients { user_ids, quiesce } => {
|
||||||
deterministic.run_until_parked();
|
|
||||||
}
|
|
||||||
|
|
||||||
Operation::MutateClients(user_ids) => {
|
|
||||||
for user_id in user_ids {
|
for user_id in user_ids {
|
||||||
let client_ix = clients
|
let client_ix = clients
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -243,6 +239,10 @@ async fn test_random_collaboration(
|
||||||
operation_channels[client_ix].unbounded_send(()).unwrap();
|
operation_channels[client_ix].unbounded_send(()).unwrap();
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if quiesce {
|
||||||
|
deterministic.run_until_parked();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -444,12 +444,20 @@ struct UserTestPlan {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Operation {
|
enum Operation {
|
||||||
AddConnection { user_id: UserId },
|
AddConnection {
|
||||||
RemoveConnection { user_id: UserId },
|
user_id: UserId,
|
||||||
BounceConnection { user_id: UserId },
|
},
|
||||||
|
RemoveConnection {
|
||||||
|
user_id: UserId,
|
||||||
|
},
|
||||||
|
BounceConnection {
|
||||||
|
user_id: UserId,
|
||||||
|
},
|
||||||
RestartServer,
|
RestartServer,
|
||||||
RunUntilParked,
|
MutateClients {
|
||||||
MutateClients(Vec<UserId>),
|
user_ids: Vec<UserId>,
|
||||||
|
quiesce: bool,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -490,7 +498,7 @@ impl TestPlan {
|
||||||
async fn next_operation(&mut self, clients: &[(Rc<TestClient>, TestAppContext)]) -> Operation {
|
async fn next_operation(&mut self, clients: &[(Rc<TestClient>, TestAppContext)]) -> Operation {
|
||||||
let operation = loop {
|
let operation = loop {
|
||||||
break match self.rng.gen_range(0..100) {
|
break match self.rng.gen_range(0..100) {
|
||||||
0..=19 if clients.len() < self.users.len() => {
|
0..=29 if clients.len() < self.users.len() => {
|
||||||
let user = self
|
let user = self
|
||||||
.users
|
.users
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -501,20 +509,19 @@ impl TestPlan {
|
||||||
user_id: user.user_id,
|
user_id: user.user_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
20..=24 if clients.len() > 1 && self.allow_client_disconnection => {
|
30..=34 if clients.len() > 1 && self.allow_client_disconnection => {
|
||||||
let (client, cx) = &clients[self.rng.gen_range(0..clients.len())];
|
let (client, cx) = &clients[self.rng.gen_range(0..clients.len())];
|
||||||
let user_id = client.current_user_id(cx);
|
let user_id = client.current_user_id(cx);
|
||||||
Operation::RemoveConnection { user_id }
|
Operation::RemoveConnection { user_id }
|
||||||
}
|
}
|
||||||
25..=29 if clients.len() > 1 && self.allow_client_reconnection => {
|
35..=39 if clients.len() > 1 && self.allow_client_reconnection => {
|
||||||
let (client, cx) = &clients[self.rng.gen_range(0..clients.len())];
|
let (client, cx) = &clients[self.rng.gen_range(0..clients.len())];
|
||||||
let user_id = client.current_user_id(cx);
|
let user_id = client.current_user_id(cx);
|
||||||
Operation::BounceConnection { user_id }
|
Operation::BounceConnection { user_id }
|
||||||
}
|
}
|
||||||
30..=34 if self.allow_server_restarts && clients.len() > 1 => {
|
40..=44 if self.allow_server_restarts && clients.len() > 1 => {
|
||||||
Operation::RestartServer
|
Operation::RestartServer
|
||||||
}
|
}
|
||||||
35..=39 => Operation::RunUntilParked,
|
|
||||||
_ if !clients.is_empty() => {
|
_ if !clients.is_empty() => {
|
||||||
let user_ids = (0..self.rng.gen_range(0..10))
|
let user_ids = (0..self.rng.gen_range(0..10))
|
||||||
.map(|_| {
|
.map(|_| {
|
||||||
|
@ -523,7 +530,10 @@ impl TestPlan {
|
||||||
client.current_user_id(cx)
|
client.current_user_id(cx)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
Operation::MutateClients(user_ids)
|
Operation::MutateClients {
|
||||||
|
user_ids,
|
||||||
|
quiesce: self.rng.gen(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => continue,
|
_ => continue,
|
||||||
};
|
};
|
||||||
|
@ -541,78 +551,95 @@ impl TestPlan {
|
||||||
let operation = loop {
|
let operation = loop {
|
||||||
match self.rng.gen_range(0..100) {
|
match self.rng.gen_range(0..100) {
|
||||||
// Mutate the call
|
// Mutate the call
|
||||||
0..=19 => match self.rng.gen_range(0..100_u32) {
|
0..=29 => {
|
||||||
// Respond to an incoming call
|
// Respond to an incoming call
|
||||||
0..=39 => {
|
if call.read_with(cx, |call, _| call.incoming().borrow().is_some()) {
|
||||||
if call.read_with(cx, |call, _| call.incoming().borrow().is_some()) {
|
break if self.rng.gen_bool(0.7) {
|
||||||
break if self.rng.gen_bool(0.7) {
|
ClientOperation::AcceptIncomingCall
|
||||||
ClientOperation::AcceptIncomingCall
|
} else {
|
||||||
} else {
|
ClientOperation::RejectIncomingCall
|
||||||
ClientOperation::RejectIncomingCall
|
};
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invite a contact to the current call
|
match self.rng.gen_range(0..100_u32) {
|
||||||
30..=89 => {
|
// Invite a contact to the current call
|
||||||
let available_contacts =
|
0..=70 => {
|
||||||
client.user_store.read_with(cx, |user_store, _| {
|
let available_contacts =
|
||||||
user_store
|
client.user_store.read_with(cx, |user_store, _| {
|
||||||
.contacts()
|
user_store
|
||||||
.iter()
|
.contacts()
|
||||||
.filter(|contact| contact.online && !contact.busy)
|
.iter()
|
||||||
.cloned()
|
.filter(|contact| contact.online && !contact.busy)
|
||||||
.collect::<Vec<_>>()
|
.cloned()
|
||||||
});
|
.collect::<Vec<_>>()
|
||||||
if !available_contacts.is_empty() {
|
});
|
||||||
let contact = available_contacts.choose(&mut self.rng).unwrap();
|
if !available_contacts.is_empty() {
|
||||||
break ClientOperation::InviteContactToCall {
|
let contact = available_contacts.choose(&mut self.rng).unwrap();
|
||||||
user_id: UserId(contact.user.id as i32),
|
break ClientOperation::InviteContactToCall {
|
||||||
};
|
user_id: UserId(contact.user.id as i32),
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Leave the current call
|
// Leave the current call
|
||||||
90.. => {
|
71.. => {
|
||||||
if self.allow_client_disconnection
|
if self.allow_client_disconnection
|
||||||
&& call.read_with(cx, |call, _| call.room().is_some())
|
&& call.read_with(cx, |call, _| call.room().is_some())
|
||||||
{
|
{
|
||||||
break ClientOperation::LeaveCall;
|
break ClientOperation::LeaveCall;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
// Mutate projects
|
// Mutate projects
|
||||||
20..=39 => match self.rng.gen_range(0..100_u32) {
|
39..=59 => match self.rng.gen_range(0..100_u32) {
|
||||||
// Open a remote project
|
// Open a new project
|
||||||
0..=30 => {
|
0..=70 => {
|
||||||
|
// Open a remote project
|
||||||
if let Some(room) = call.read_with(cx, |call, _| call.room().cloned()) {
|
if let Some(room) = call.read_with(cx, |call, _| call.room().cloned()) {
|
||||||
let remote_projects = room.read_with(cx, |room, _| {
|
let existing_remote_project_ids = cx.read(|cx| {
|
||||||
|
client
|
||||||
|
.remote_projects()
|
||||||
|
.iter()
|
||||||
|
.map(|p| p.read(cx).remote_id().unwrap())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
});
|
||||||
|
let new_remote_projects = room.read_with(cx, |room, _| {
|
||||||
room.remote_participants()
|
room.remote_participants()
|
||||||
.values()
|
.values()
|
||||||
.flat_map(|participant| {
|
.flat_map(|participant| {
|
||||||
participant.projects.iter().map(|project| {
|
participant.projects.iter().filter_map(|project| {
|
||||||
(
|
if existing_remote_project_ids.contains(&project.id) {
|
||||||
UserId::from_proto(participant.user.id),
|
None
|
||||||
project.worktree_root_names[0].clone(),
|
} else {
|
||||||
)
|
Some((
|
||||||
|
UserId::from_proto(participant.user.id),
|
||||||
|
project.worktree_root_names[0].clone(),
|
||||||
|
))
|
||||||
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
});
|
});
|
||||||
if !remote_projects.is_empty() {
|
if !new_remote_projects.is_empty() {
|
||||||
let (host_id, first_root_name) =
|
let (host_id, first_root_name) =
|
||||||
remote_projects.choose(&mut self.rng).unwrap().clone();
|
new_remote_projects.choose(&mut self.rng).unwrap().clone();
|
||||||
break ClientOperation::OpenRemoteProject {
|
break ClientOperation::OpenRemoteProject {
|
||||||
host_id,
|
host_id,
|
||||||
first_root_name,
|
first_root_name,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Open a local project
|
||||||
|
else {
|
||||||
|
let first_root_name = self.next_root_dir_name(user_id);
|
||||||
|
break ClientOperation::OpenLocalProject { first_root_name };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close a remote project
|
// Close a remote project
|
||||||
31..=40 => {
|
71..=80 => {
|
||||||
if !client.remote_projects().is_empty() {
|
if !client.remote_projects().is_empty() {
|
||||||
let project = client
|
let project = client
|
||||||
.remote_projects()
|
.remote_projects()
|
||||||
|
@ -626,14 +653,8 @@ impl TestPlan {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open a local project
|
|
||||||
41..=60 => {
|
|
||||||
let first_root_name = self.next_root_dir_name(user_id);
|
|
||||||
break ClientOperation::OpenLocalProject { first_root_name };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a worktree to a local project
|
// Add a worktree to a local project
|
||||||
61.. => {
|
81.. => {
|
||||||
if !client.local_projects().is_empty() {
|
if !client.local_projects().is_empty() {
|
||||||
let project = client
|
let project = client
|
||||||
.local_projects()
|
.local_projects()
|
||||||
|
@ -659,7 +680,7 @@ impl TestPlan {
|
||||||
},
|
},
|
||||||
|
|
||||||
// Mutate buffers
|
// Mutate buffers
|
||||||
40..=79 => {
|
60.. => {
|
||||||
let Some(project) = choose_random_project(client, &mut self.rng) else { continue };
|
let Some(project) = choose_random_project(client, &mut self.rng) else { continue };
|
||||||
let project_root_name = root_name_for_project(&project, cx);
|
let project_root_name = root_name_for_project(&project, cx);
|
||||||
|
|
||||||
|
@ -871,9 +892,8 @@ async fn simulate_client(
|
||||||
let operation = plan.lock().next_client_operation(&client, &cx).await;
|
let operation = plan.lock().next_client_operation(&client, &cx).await;
|
||||||
if let Err(error) = apply_client_operation(&client, plan.clone(), operation, &mut cx).await
|
if let Err(error) = apply_client_operation(&client, plan.clone(), operation, &mut cx).await
|
||||||
{
|
{
|
||||||
log::error!("{} error: {:?}", client.username, error);
|
log::error!("{} error: {}", client.username, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
cx.background().simulate_random_delay().await;
|
cx.background().simulate_random_delay().await;
|
||||||
}
|
}
|
||||||
log::info!("{}: done", client.username);
|
log::info!("{}: done", client.username);
|
||||||
|
@ -928,34 +948,7 @@ async fn apply_client_operation(
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let project = client.build_local_project(root_path, cx).await.0;
|
let project = client.build_local_project(root_path, cx).await.0;
|
||||||
|
ensure_project_shared(&project, client, cx).await;
|
||||||
let active_call = cx.read(ActiveCall::global);
|
|
||||||
if active_call.read_with(cx, |call, _| call.room().is_some())
|
|
||||||
&& project.read_with(cx, |project, _| project.is_local() && !project.is_shared())
|
|
||||||
{
|
|
||||||
match active_call
|
|
||||||
.update(cx, |call, cx| call.share_project(project.clone(), cx))
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(project_id) => {
|
|
||||||
log::info!(
|
|
||||||
"{}: shared project {} with id {}",
|
|
||||||
client.username,
|
|
||||||
first_root_name,
|
|
||||||
project_id
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Err(error) => {
|
|
||||||
log::error!(
|
|
||||||
"{}: error sharing project {}: {:?}",
|
|
||||||
client.username,
|
|
||||||
first_root_name,
|
|
||||||
error
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
client.local_projects_mut().push(project.clone());
|
client.local_projects_mut().push(project.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -971,6 +964,7 @@ async fn apply_client_operation(
|
||||||
);
|
);
|
||||||
let project = project_for_root_name(client, &project_root_name, cx)
|
let project = project_for_root_name(client, &project_root_name, cx)
|
||||||
.expect("invalid project in test operation");
|
.expect("invalid project in test operation");
|
||||||
|
ensure_project_shared(&project, client, cx).await;
|
||||||
if !client.fs.paths().await.contains(&new_root_path) {
|
if !client.fs.paths().await.contains(&new_root_path) {
|
||||||
client.fs.create_dir(&new_root_path).await.unwrap();
|
client.fs.create_dir(&new_root_path).await.unwrap();
|
||||||
}
|
}
|
||||||
|
@ -984,13 +978,13 @@ async fn apply_client_operation(
|
||||||
|
|
||||||
ClientOperation::CloseRemoteProject { project_root_name } => {
|
ClientOperation::CloseRemoteProject { project_root_name } => {
|
||||||
log::info!(
|
log::info!(
|
||||||
"{}: dropping project with root path {}",
|
"{}: closing remote project with root path {}",
|
||||||
client.username,
|
client.username,
|
||||||
project_root_name,
|
project_root_name,
|
||||||
);
|
);
|
||||||
let ix = project_ix_for_root_name(&*client.remote_projects(), &project_root_name, cx)
|
let ix = project_ix_for_root_name(&*client.remote_projects(), &project_root_name, cx)
|
||||||
.expect("invalid project in test operation");
|
.expect("invalid project in test operation");
|
||||||
client.remote_projects_mut().remove(ix);
|
cx.update(|_| client.remote_projects_mut().remove(ix));
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientOperation::OpenRemoteProject {
|
ClientOperation::OpenRemoteProject {
|
||||||
|
@ -1027,13 +1021,14 @@ async fn apply_client_operation(
|
||||||
full_path,
|
full_path,
|
||||||
} => {
|
} => {
|
||||||
log::info!(
|
log::info!(
|
||||||
"{}: opening path {:?} in project {}",
|
"{}: opening buffer {:?} in project {}",
|
||||||
client.username,
|
client.username,
|
||||||
full_path,
|
full_path,
|
||||||
project_root_name,
|
project_root_name,
|
||||||
);
|
);
|
||||||
let project = project_for_root_name(client, &project_root_name, cx)
|
let project = project_for_root_name(client, &project_root_name, cx)
|
||||||
.expect("invalid project in test operation");
|
.expect("invalid project in test operation");
|
||||||
|
// ensure_project_shared(&project, client, cx).await;
|
||||||
let mut components = full_path.components();
|
let mut components = full_path.components();
|
||||||
let root_name = components.next().unwrap().as_os_str().to_str().unwrap();
|
let root_name = components.next().unwrap().as_os_str().to_str().unwrap();
|
||||||
let path = components.as_path();
|
let path = components.as_path();
|
||||||
|
@ -1086,10 +1081,10 @@ async fn apply_client_operation(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
ClientOperation::Other => {
|
||||||
let choice = plan.lock().rng.gen_range(0..100);
|
let choice = plan.lock().rng.gen_range(0..100);
|
||||||
match choice {
|
match choice {
|
||||||
50..=59
|
0..=59
|
||||||
if !client.local_projects().is_empty()
|
if !client.local_projects().is_empty()
|
||||||
|| !client.remote_projects().is_empty() =>
|
|| !client.remote_projects().is_empty() =>
|
||||||
{
|
{
|
||||||
|
@ -1147,6 +1142,40 @@ fn root_name_for_project(project: &ModelHandle<Project>, cx: &TestAppContext) ->
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn ensure_project_shared(
|
||||||
|
project: &ModelHandle<Project>,
|
||||||
|
client: &TestClient,
|
||||||
|
cx: &mut TestAppContext,
|
||||||
|
) {
|
||||||
|
let first_root_name = root_name_for_project(project, cx);
|
||||||
|
let active_call = cx.read(ActiveCall::global);
|
||||||
|
if active_call.read_with(cx, |call, _| call.room().is_some())
|
||||||
|
&& project.read_with(cx, |project, _| project.is_local() && !project.is_shared())
|
||||||
|
{
|
||||||
|
match active_call
|
||||||
|
.update(cx, |call, cx| call.share_project(project.clone(), cx))
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(project_id) => {
|
||||||
|
log::info!(
|
||||||
|
"{}: shared project {} with id {}",
|
||||||
|
client.username,
|
||||||
|
first_root_name,
|
||||||
|
project_id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
log::error!(
|
||||||
|
"{}: error sharing project {}: {:?}",
|
||||||
|
client.username,
|
||||||
|
first_root_name,
|
||||||
|
error
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn randomly_mutate_fs(client: &TestClient, plan: &Arc<Mutex<TestPlan>>) {
|
async fn randomly_mutate_fs(client: &TestClient, plan: &Arc<Mutex<TestPlan>>) {
|
||||||
let is_dir = plan.lock().rng.gen::<bool>();
|
let is_dir = plan.lock().rng.gen::<bool>();
|
||||||
let mut new_path = client
|
let mut new_path = client
|
||||||
|
|
Loading…
Reference in a new issue