Prevent randomized test from failing if another guest disconnects
This commit is contained in:
parent
eb6b545eeb
commit
62547e87dd
1 changed files with 504 additions and 485 deletions
|
@ -5858,7 +5858,7 @@ async fn test_random_collaboration(
|
||||||
while operations < max_operations {
|
while operations < max_operations {
|
||||||
let distribution = rng.lock().gen_range(0..100);
|
let distribution = rng.lock().gen_range(0..100);
|
||||||
match distribution {
|
match distribution {
|
||||||
0..=19 if !available_guests.is_empty() => {
|
_ if !available_guests.is_empty() => {
|
||||||
let guest_ix = rng.lock().gen_range(0..available_guests.len());
|
let guest_ix = rng.lock().gen_range(0..available_guests.len());
|
||||||
let guest_username = available_guests.remove(guest_ix);
|
let guest_username = available_guests.remove(guest_ix);
|
||||||
log::info!("Adding new connection for {}", guest_username);
|
log::info!("Adding new connection for {}", guest_username);
|
||||||
|
@ -5906,7 +5906,21 @@ async fn test_random_collaboration(
|
||||||
log::info!("Added connection for {}", guest_username);
|
log::info!("Added connection for {}", guest_username);
|
||||||
operations += 1;
|
operations += 1;
|
||||||
}
|
}
|
||||||
20..=29 if clients.len() > 1 => {
|
0..=69 if !op_start_signals.is_empty() => {
|
||||||
|
while operations < max_operations && rng.lock().gen_bool(0.7) {
|
||||||
|
op_start_signals
|
||||||
|
.choose(&mut *rng.lock())
|
||||||
|
.unwrap()
|
||||||
|
.unbounded_send(())
|
||||||
|
.unwrap();
|
||||||
|
operations += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if rng.lock().gen_bool(0.8) {
|
||||||
|
deterministic.run_until_parked();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
70..=79 if clients.len() > 1 => {
|
||||||
let guest_ix = rng.lock().gen_range(1..clients.len());
|
let guest_ix = rng.lock().gen_range(1..clients.len());
|
||||||
log::info!("Removing guest {}", user_ids[guest_ix]);
|
log::info!("Removing guest {}", user_ids[guest_ix]);
|
||||||
let removed_guest_id = user_ids.remove(guest_ix);
|
let removed_guest_id = user_ids.remove(guest_ix);
|
||||||
|
@ -5918,14 +5932,10 @@ async fn test_random_collaboration(
|
||||||
deterministic.advance_clock(RECEIVE_TIMEOUT);
|
deterministic.advance_clock(RECEIVE_TIMEOUT);
|
||||||
deterministic.start_waiting();
|
deterministic.start_waiting();
|
||||||
log::info!("Waiting for guest {} to exit...", removed_guest_id);
|
log::info!("Waiting for guest {} to exit...", removed_guest_id);
|
||||||
let (guest, mut guest_cx, guest_err) = guest.await;
|
let (guest, mut guest_cx) = guest.await;
|
||||||
deterministic.finish_waiting();
|
deterministic.finish_waiting();
|
||||||
server.allow_connections();
|
server.allow_connections();
|
||||||
|
|
||||||
if let Some(guest_err) = guest_err {
|
|
||||||
log::error!("{} error - {:?}", guest.username, guest_err);
|
|
||||||
}
|
|
||||||
|
|
||||||
for project in &guest.remote_projects {
|
for project in &guest.remote_projects {
|
||||||
project.read_with(&guest_cx, |project, _| assert!(project.is_read_only()));
|
project.read_with(&guest_cx, |project, _| assert!(project.is_read_only()));
|
||||||
}
|
}
|
||||||
|
@ -5956,20 +5966,6 @@ async fn test_random_collaboration(
|
||||||
|
|
||||||
operations += 1;
|
operations += 1;
|
||||||
}
|
}
|
||||||
_ if !op_start_signals.is_empty() => {
|
|
||||||
while operations < max_operations && rng.lock().gen_bool(0.7) {
|
|
||||||
op_start_signals
|
|
||||||
.choose(&mut *rng.lock())
|
|
||||||
.unwrap()
|
|
||||||
.unbounded_send(())
|
|
||||||
.unwrap();
|
|
||||||
operations += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if rng.lock().gen_bool(0.8) {
|
|
||||||
deterministic.run_until_parked();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5980,14 +5976,10 @@ async fn test_random_collaboration(
|
||||||
deterministic.finish_waiting();
|
deterministic.finish_waiting();
|
||||||
deterministic.run_until_parked();
|
deterministic.run_until_parked();
|
||||||
|
|
||||||
for (guest_client, guest_cx, guest_err) in &clients {
|
for (guest_client, guest_cx) in &clients {
|
||||||
if let Some(guest_err) = guest_err {
|
|
||||||
panic!("{} error - {:?}", guest_client.username, guest_err);
|
|
||||||
}
|
|
||||||
|
|
||||||
for guest_project in &guest_client.remote_projects {
|
for guest_project in &guest_client.remote_projects {
|
||||||
guest_project.read_with(guest_cx, |guest_project, cx| {
|
guest_project.read_with(guest_cx, |guest_project, cx| {
|
||||||
let host_project = clients.iter().find_map(|(client, cx, _)| {
|
let host_project = clients.iter().find_map(|(client, cx)| {
|
||||||
let project = client.local_projects.iter().find(|host_project| {
|
let project = client.local_projects.iter().find(|host_project| {
|
||||||
host_project.read_with(cx, |host_project, _| {
|
host_project.read_with(cx, |host_project, _| {
|
||||||
host_project.remote_id() == guest_project.remote_id()
|
host_project.remote_id() == guest_project.remote_id()
|
||||||
|
@ -6049,7 +6041,7 @@ async fn test_random_collaboration(
|
||||||
}
|
}
|
||||||
|
|
||||||
for (project_id, guest_buffers) in &guest_client.buffers {
|
for (project_id, guest_buffers) in &guest_client.buffers {
|
||||||
let host_project = clients.iter().find_map(|(client, cx, _)| {
|
let host_project = clients.iter().find_map(|(client, cx)| {
|
||||||
let project = client.local_projects.iter().find(|host_project| {
|
let project = client.local_projects.iter().find(|host_project| {
|
||||||
host_project.read_with(cx, |host_project, _| {
|
host_project.read_with(cx, |host_project, _| {
|
||||||
host_project.remote_id() == Some(*project_id)
|
host_project.remote_id() == Some(*project_id)
|
||||||
|
@ -6099,7 +6091,7 @@ async fn test_random_collaboration(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (client, mut cx, _) in clients {
|
for (client, mut cx) in clients {
|
||||||
cx.update(|cx| {
|
cx.update(|cx| {
|
||||||
cx.clear_globals();
|
cx.clear_globals();
|
||||||
drop(client);
|
drop(client);
|
||||||
|
@ -6517,141 +6509,22 @@ impl TestClient {
|
||||||
pub async fn simulate(
|
pub async fn simulate(
|
||||||
mut self,
|
mut self,
|
||||||
username: String,
|
username: String,
|
||||||
op_start_signal: futures::channel::mpsc::UnboundedReceiver<()>,
|
mut op_start_signal: futures::channel::mpsc::UnboundedReceiver<()>,
|
||||||
rng: Arc<Mutex<StdRng>>,
|
rng: Arc<Mutex<StdRng>>,
|
||||||
mut cx: TestAppContext,
|
mut cx: TestAppContext,
|
||||||
) -> (Self, TestAppContext, Option<anyhow::Error>) {
|
) -> (Self, TestAppContext) {
|
||||||
async fn simulate_internal(
|
async fn tick(
|
||||||
client: &mut TestClient,
|
client: &mut TestClient,
|
||||||
username: &str,
|
username: &str,
|
||||||
mut op_start_signal: futures::channel::mpsc::UnboundedReceiver<()>,
|
|
||||||
rng: Arc<Mutex<StdRng>>,
|
rng: Arc<Mutex<StdRng>>,
|
||||||
cx: &mut TestAppContext,
|
cx: &mut TestAppContext,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
// Setup language server
|
|
||||||
let mut language = Language::new(
|
|
||||||
LanguageConfig {
|
|
||||||
name: "Rust".into(),
|
|
||||||
path_suffixes: vec!["rs".to_string()],
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
language
|
|
||||||
.set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
|
|
||||||
name: "the-fake-language-server",
|
|
||||||
capabilities: lsp::LanguageServer::full_capabilities(),
|
|
||||||
initializer: Some(Box::new({
|
|
||||||
let rng = rng.clone();
|
|
||||||
let fs = client.fs.clone();
|
|
||||||
move |fake_server: &mut FakeLanguageServer| {
|
|
||||||
fake_server.handle_request::<lsp::request::Completion, _, _>(
|
|
||||||
|_, _| async move {
|
|
||||||
Ok(Some(lsp::CompletionResponse::Array(vec![
|
|
||||||
lsp::CompletionItem {
|
|
||||||
text_edit: Some(lsp::CompletionTextEdit::Edit(
|
|
||||||
lsp::TextEdit {
|
|
||||||
range: lsp::Range::new(
|
|
||||||
lsp::Position::new(0, 0),
|
|
||||||
lsp::Position::new(0, 0),
|
|
||||||
),
|
|
||||||
new_text: "the-new-text".to_string(),
|
|
||||||
},
|
|
||||||
)),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
])))
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
fake_server.handle_request::<lsp::request::CodeActionRequest, _, _>(
|
|
||||||
|_, _| async move {
|
|
||||||
Ok(Some(vec![lsp::CodeActionOrCommand::CodeAction(
|
|
||||||
lsp::CodeAction {
|
|
||||||
title: "the-code-action".to_string(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
)]))
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
fake_server.handle_request::<lsp::request::PrepareRenameRequest, _, _>(
|
|
||||||
|params, _| async move {
|
|
||||||
Ok(Some(lsp::PrepareRenameResponse::Range(lsp::Range::new(
|
|
||||||
params.position,
|
|
||||||
params.position,
|
|
||||||
))))
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
fake_server.handle_request::<lsp::request::GotoDefinition, _, _>({
|
|
||||||
let fs = fs.clone();
|
|
||||||
let rng = rng.clone();
|
|
||||||
move |_, _| {
|
|
||||||
let fs = fs.clone();
|
|
||||||
let rng = rng.clone();
|
|
||||||
async move {
|
|
||||||
let files = fs.files().await;
|
|
||||||
let mut rng = rng.lock();
|
|
||||||
let count = rng.gen_range::<usize, _>(1..3);
|
|
||||||
let files = (0..count)
|
|
||||||
.map(|_| files.choose(&mut *rng).unwrap())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
log::info!(
|
|
||||||
"LSP: Returning definitions in files {:?}",
|
|
||||||
&files
|
|
||||||
);
|
|
||||||
Ok(Some(lsp::GotoDefinitionResponse::Array(
|
|
||||||
files
|
|
||||||
.into_iter()
|
|
||||||
.map(|file| lsp::Location {
|
|
||||||
uri: lsp::Url::from_file_path(file).unwrap(),
|
|
||||||
range: Default::default(),
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
fake_server
|
|
||||||
.handle_request::<lsp::request::DocumentHighlightRequest, _, _>({
|
|
||||||
let rng = rng.clone();
|
|
||||||
move |_, _| {
|
|
||||||
let mut highlights = Vec::new();
|
|
||||||
let highlight_count = rng.lock().gen_range(1..=5);
|
|
||||||
for _ in 0..highlight_count {
|
|
||||||
let start = PointUtf16::new(
|
|
||||||
rng.lock().gen_range(0..100),
|
|
||||||
rng.lock().gen_range(0..100),
|
|
||||||
);
|
|
||||||
let end = PointUtf16::new(
|
|
||||||
rng.lock().gen_range(0..100),
|
|
||||||
rng.lock().gen_range(0..100),
|
|
||||||
);
|
|
||||||
let range =
|
|
||||||
if start > end { end..start } else { start..end };
|
|
||||||
highlights.push(lsp::DocumentHighlight {
|
|
||||||
range: range_to_lsp(range.clone()),
|
|
||||||
kind: Some(lsp::DocumentHighlightKind::READ),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
highlights.sort_unstable_by_key(|highlight| {
|
|
||||||
(highlight.range.start, highlight.range.end)
|
|
||||||
});
|
|
||||||
async move { Ok(Some(highlights)) }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})),
|
|
||||||
..Default::default()
|
|
||||||
}))
|
|
||||||
.await;
|
|
||||||
client.language_registry.add(Arc::new(language));
|
|
||||||
|
|
||||||
while op_start_signal.next().await.is_some() {
|
|
||||||
let active_call = cx.read(ActiveCall::global);
|
let active_call = cx.read(ActiveCall::global);
|
||||||
let room = active_call.read_with(cx, |call, _| call.room().unwrap().clone());
|
let room = active_call.read_with(cx, |call, _| {
|
||||||
|
call.room()
|
||||||
|
.ok_or_else(|| anyhow!("no active call"))
|
||||||
|
.cloned()
|
||||||
|
})?;
|
||||||
let remote_projects = room.read_with(cx, |room, _| {
|
let remote_projects = room.read_with(cx, |room, _| {
|
||||||
room.remote_participants()
|
room.remote_participants()
|
||||||
.values()
|
.values()
|
||||||
|
@ -6667,10 +6540,18 @@ impl TestClient {
|
||||||
username,
|
username,
|
||||||
post_inc(&mut client.next_root_dir_id)
|
post_inc(&mut client.next_root_dir_id)
|
||||||
);
|
);
|
||||||
client.fs.create_dir(Path::new(&root_path)).await.unwrap();
|
let root_path = Path::new(&root_path);
|
||||||
|
client.fs.create_dir(root_path).await.unwrap();
|
||||||
|
client
|
||||||
|
.fs
|
||||||
|
.create_file(&root_path.join("main.rs"), Default::default())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
log::info!("{}: opening local project at {:?}", username, root_path);
|
||||||
client.build_local_project(root_path, cx).await.0
|
client.build_local_project(root_path, cx).await.0
|
||||||
} else {
|
} else {
|
||||||
let root_path = paths.choose(&mut *rng.lock()).unwrap();
|
let root_path = paths.choose(&mut *rng.lock()).unwrap();
|
||||||
|
log::info!("{}: opening local project at {:?}", username, root_path);
|
||||||
client.build_local_project(root_path, cx).await.0
|
client.build_local_project(root_path, cx).await.0
|
||||||
};
|
};
|
||||||
client.local_projects.push(local_project.clone());
|
client.local_projects.push(local_project.clone());
|
||||||
|
@ -6684,11 +6565,30 @@ impl TestClient {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if client.remote_projects.is_empty() || rng.lock().gen() {
|
if client.remote_projects.is_empty() || rng.lock().gen() {
|
||||||
let remote_project_id =
|
let remote_project_id = remote_projects.choose(&mut *rng.lock()).unwrap().id;
|
||||||
remote_projects.choose(&mut *rng.lock()).unwrap().id;
|
let remote_project = if let Some(project) =
|
||||||
let remote_project =
|
client.remote_projects.iter().find(|project| {
|
||||||
client.build_remote_project(remote_project_id, cx).await;
|
project.read_with(cx, |project, _| {
|
||||||
|
project.remote_id() == Some(remote_project_id)
|
||||||
|
})
|
||||||
|
}) {
|
||||||
|
project.clone()
|
||||||
|
} else {
|
||||||
|
log::info!("{}: opening remote project {}", username, remote_project_id);
|
||||||
|
let remote_project = Project::remote(
|
||||||
|
remote_project_id,
|
||||||
|
client.client.clone(),
|
||||||
|
client.user_store.clone(),
|
||||||
|
client.project_store.clone(),
|
||||||
|
client.language_registry.clone(),
|
||||||
|
FakeFs::new(cx.background()),
|
||||||
|
cx.to_async(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
client.remote_projects.push(remote_project.clone());
|
client.remote_projects.push(remote_project.clone());
|
||||||
|
remote_project
|
||||||
|
};
|
||||||
|
|
||||||
remote_project
|
remote_project
|
||||||
} else {
|
} else {
|
||||||
client
|
client
|
||||||
|
@ -6700,8 +6600,7 @@ impl TestClient {
|
||||||
};
|
};
|
||||||
let project_id = active_call
|
let project_id = active_call
|
||||||
.update(cx, |call, cx| call.share_project(project.clone(), cx))
|
.update(cx, |call, cx| call.share_project(project.clone(), cx))
|
||||||
.await
|
.await?;
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let buffers = client.buffers.entry(project_id).or_default();
|
let buffers = client.buffers.entry(project_id).or_default();
|
||||||
let buffer = if buffers.is_empty() || rng.lock().gen() {
|
let buffer = if buffers.is_empty() || rng.lock().gen() {
|
||||||
|
@ -6710,19 +6609,17 @@ impl TestClient {
|
||||||
.worktrees(cx)
|
.worktrees(cx)
|
||||||
.filter(|worktree| {
|
.filter(|worktree| {
|
||||||
let worktree = worktree.read(cx);
|
let worktree = worktree.read(cx);
|
||||||
worktree.is_visible()
|
worktree.is_visible() && worktree.entries(false).any(|e| e.is_file())
|
||||||
&& worktree.entries(false).any(|e| e.is_file())
|
|
||||||
})
|
})
|
||||||
.choose(&mut *rng.lock())
|
.choose(&mut *rng.lock())
|
||||||
}) {
|
}) {
|
||||||
worktree
|
worktree
|
||||||
} else {
|
} else {
|
||||||
cx.background().simulate_random_delay().await;
|
cx.background().simulate_random_delay().await;
|
||||||
continue;
|
return Ok(());
|
||||||
};
|
};
|
||||||
|
|
||||||
let (worktree_root_name, project_path) =
|
let (worktree_root_name, project_path) = worktree.read_with(cx, |worktree, _| {
|
||||||
worktree.read_with(cx, |worktree, _| {
|
|
||||||
let entry = worktree
|
let entry = worktree
|
||||||
.entries(false)
|
.entries(false)
|
||||||
.filter(|e| e.is_file())
|
.filter(|e| e.is_file())
|
||||||
|
@ -6885,9 +6782,7 @@ impl TestClient {
|
||||||
log::info!("{}: detaching definitions request", username);
|
log::info!("{}: detaching definitions request", username);
|
||||||
cx.update(|cx| definitions.detach_and_log_err(cx));
|
cx.update(|cx| definitions.detach_and_log_err(cx));
|
||||||
} else {
|
} else {
|
||||||
buffers.extend(
|
buffers.extend(definitions.await?.into_iter().map(|loc| loc.target.buffer));
|
||||||
definitions.await?.into_iter().map(|loc| loc.target.buffer),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
50..=54 => {
|
50..=54 => {
|
||||||
|
@ -6992,15 +6887,139 @@ impl TestClient {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cx.background().simulate_random_delay().await;
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = simulate_internal(&mut self, &username, op_start_signal, rng, &mut cx).await;
|
// Setup language server
|
||||||
|
let mut language = Language::new(
|
||||||
|
LanguageConfig {
|
||||||
|
name: "Rust".into(),
|
||||||
|
path_suffixes: vec!["rs".to_string()],
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
language
|
||||||
|
.set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
|
||||||
|
name: "the-fake-language-server",
|
||||||
|
capabilities: lsp::LanguageServer::full_capabilities(),
|
||||||
|
initializer: Some(Box::new({
|
||||||
|
let rng = rng.clone();
|
||||||
|
let fs = self.fs.clone();
|
||||||
|
move |fake_server: &mut FakeLanguageServer| {
|
||||||
|
fake_server.handle_request::<lsp::request::Completion, _, _>(
|
||||||
|
|_, _| async move {
|
||||||
|
Ok(Some(lsp::CompletionResponse::Array(vec![
|
||||||
|
lsp::CompletionItem {
|
||||||
|
text_edit: Some(lsp::CompletionTextEdit::Edit(
|
||||||
|
lsp::TextEdit {
|
||||||
|
range: lsp::Range::new(
|
||||||
|
lsp::Position::new(0, 0),
|
||||||
|
lsp::Position::new(0, 0),
|
||||||
|
),
|
||||||
|
new_text: "the-new-text".to_string(),
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
])))
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
fake_server.handle_request::<lsp::request::CodeActionRequest, _, _>(
|
||||||
|
|_, _| async move {
|
||||||
|
Ok(Some(vec![lsp::CodeActionOrCommand::CodeAction(
|
||||||
|
lsp::CodeAction {
|
||||||
|
title: "the-code-action".to_string(),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)]))
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
fake_server.handle_request::<lsp::request::PrepareRenameRequest, _, _>(
|
||||||
|
|params, _| async move {
|
||||||
|
Ok(Some(lsp::PrepareRenameResponse::Range(lsp::Range::new(
|
||||||
|
params.position,
|
||||||
|
params.position,
|
||||||
|
))))
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
fake_server.handle_request::<lsp::request::GotoDefinition, _, _>({
|
||||||
|
let fs = fs.clone();
|
||||||
|
let rng = rng.clone();
|
||||||
|
move |_, _| {
|
||||||
|
let fs = fs.clone();
|
||||||
|
let rng = rng.clone();
|
||||||
|
async move {
|
||||||
|
let files = fs.files().await;
|
||||||
|
let mut rng = rng.lock();
|
||||||
|
let count = rng.gen_range::<usize, _>(1..3);
|
||||||
|
let files = (0..count)
|
||||||
|
.map(|_| files.choose(&mut *rng).unwrap())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
log::info!("LSP: Returning definitions in files {:?}", &files);
|
||||||
|
Ok(Some(lsp::GotoDefinitionResponse::Array(
|
||||||
|
files
|
||||||
|
.into_iter()
|
||||||
|
.map(|file| lsp::Location {
|
||||||
|
uri: lsp::Url::from_file_path(file).unwrap(),
|
||||||
|
range: Default::default(),
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
fake_server.handle_request::<lsp::request::DocumentHighlightRequest, _, _>(
|
||||||
|
{
|
||||||
|
let rng = rng.clone();
|
||||||
|
move |_, _| {
|
||||||
|
let mut highlights = Vec::new();
|
||||||
|
let highlight_count = rng.lock().gen_range(1..=5);
|
||||||
|
for _ in 0..highlight_count {
|
||||||
|
let start = PointUtf16::new(
|
||||||
|
rng.lock().gen_range(0..100),
|
||||||
|
rng.lock().gen_range(0..100),
|
||||||
|
);
|
||||||
|
let end = PointUtf16::new(
|
||||||
|
rng.lock().gen_range(0..100),
|
||||||
|
rng.lock().gen_range(0..100),
|
||||||
|
);
|
||||||
|
let range =
|
||||||
|
if start > end { end..start } else { start..end };
|
||||||
|
highlights.push(lsp::DocumentHighlight {
|
||||||
|
range: range_to_lsp(range.clone()),
|
||||||
|
kind: Some(lsp::DocumentHighlightKind::READ),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
highlights.sort_unstable_by_key(|highlight| {
|
||||||
|
(highlight.range.start, highlight.range.end)
|
||||||
|
});
|
||||||
|
async move { Ok(Some(highlights)) }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})),
|
||||||
|
..Default::default()
|
||||||
|
}))
|
||||||
|
.await;
|
||||||
|
self.language_registry.add(Arc::new(language));
|
||||||
|
|
||||||
|
while op_start_signal.next().await.is_some() {
|
||||||
|
if let Err(error) = tick(&mut self, &username, rng.clone(), &mut cx).await {
|
||||||
|
log::info!("{} error: {:?}", username, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
cx.background().simulate_random_delay().await;
|
||||||
|
}
|
||||||
log::info!("{}: done", username);
|
log::info!("{}: done", username);
|
||||||
|
|
||||||
(self, cx, result.err())
|
(self, cx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue