Add test option for faking reverse requests

This commit is contained in:
Remco Smits
2024-12-26 23:04:57 +01:00
parent 569f500b52
commit ca970dd77d
2 changed files with 142 additions and 42 deletions

View File

@@ -270,6 +270,17 @@ impl DebugAdapterClient {
transport.as_fake().on_request::<R, F>(handler).await;
}
#[cfg(any(test, feature = "test-support"))]
pub async fn fake_reverse_request<R: dap_types::requests::Request>(&self, args: R::Arguments) {
self.send_message(Message::Request(dap_types::messages::Request {
seq: self.sequence_count.load(Ordering::Relaxed),
command: R::COMMAND.into(),
arguments: serde_json::to_value(args).ok(),
}))
.await
.unwrap();
}
#[cfg(any(test, feature = "test-support"))]
pub async fn fake_event(&self, event: dap_types::messages::Events) {
self.send_message(Message::Event(Box::new(event)))
@@ -285,10 +296,13 @@ mod tests {
adapters::FakeAdapter, client::DebugAdapterClient, debugger_settings::DebuggerSettings,
};
use dap_types::{
messages::Events, requests::Initialize, Capabilities, InitializeRequestArguments,
InitializeRequestArgumentsPathFormat,
messages::Events,
requests::{Initialize, Request, RunInTerminal},
Capabilities, InitializeRequestArguments, InitializeRequestArgumentsPathFormat,
RunInTerminalRequestArguments,
};
use gpui::TestAppContext;
use serde_json::json;
use settings::{Settings, SettingsStore};
use std::sync::atomic::{AtomicBool, Ordering};
@@ -430,4 +444,71 @@ mod tests {
client.shutdown().await.unwrap();
}
#[gpui::test]
pub async fn test_calls_event_handler_for_reverse_request(cx: &mut TestAppContext) {
init_test(cx);
let adapter = Arc::new(FakeAdapter::new());
let called_event_handler = Arc::new(AtomicBool::new(false));
let mut client = DebugAdapterClient::new(
crate::client::DebugAdapterClientId(1),
adapter,
DebugAdapterBinary {
command: "command".into(),
arguments: Default::default(),
envs: Default::default(),
cwd: None,
},
&mut cx.to_async(),
);
client
.start(
{
let called_event_handler = called_event_handler.clone();
move |event, _| {
called_event_handler.store(true, Ordering::SeqCst);
assert_eq!(
Message::Request(dap_types::messages::Request {
seq: 1,
command: RunInTerminal::COMMAND.into(),
arguments: Some(json!({
"cwd": "/project/path/src",
"args": ["node", "test.js"],
}))
}),
event
);
}
},
&mut cx.to_async(),
)
.await
.unwrap();
cx.run_until_parked();
client
.fake_reverse_request::<RunInTerminal>(RunInTerminalRequestArguments {
kind: None,
title: None,
cwd: "/project/path/src".into(),
args: vec!["node".into(), "test.js".into()],
env: None,
args_can_be_interpreted_by_shell: None,
})
.await;
cx.run_until_parked();
assert!(
called_event_handler.load(std::sync::atomic::Ordering::SeqCst),
"Event handler was not called"
);
client.shutdown().await.unwrap();
}
}

View File

@@ -809,6 +809,7 @@ impl Transport for FakeTransport {
_binary: &DebugAdapterBinary,
cx: &mut AsyncAppContext,
) -> Result<TransportPipe> {
use dap_types::requests::{Request, RunInTerminal, StartDebugging};
use serde_json::json;
let (stdin_writer, stdin_reader) = async_pipe::pipe();
@@ -817,51 +818,69 @@ impl Transport for FakeTransport {
let handlers = self.request_handlers.clone();
let stdout_writer = Arc::new(Mutex::new(stdout_writer));
cx.background_executor().spawn(async move {
let mut reader = BufReader::new(stdin_reader);
let mut buffer = String::new();
cx.background_executor()
.spawn(async move {
let mut reader = BufReader::new(stdin_reader);
let mut buffer = String::new();
loop {
let message = TransportDelegate::receive_server_message(
&mut reader,
&mut buffer,
None,
)
.await;
match message {
Err(error) => {
break anyhow!(error);
}
Ok(Message::Request(request)) => {
if let Some(handle) =
handlers.lock().await.get_mut(request.command.as_str())
{
handle(
request.seq,
request.arguments.unwrap_or(json!({})),
stdout_writer.clone(),
)
loop {
let message =
TransportDelegate::receive_server_message(&mut reader, &mut buffer, None)
.await;
} else {
log::debug!("No handler for {}", request.command);
match message {
Err(error) => {
break anyhow!(error);
}
Ok(message) => {
if let Message::Request(request) = message {
// redirect reverse requests to stdout writer/reader
if request.command == RunInTerminal::COMMAND
|| request.command == StartDebugging::COMMAND
{
let message =
serde_json::to_string(&Message::Request(request)).unwrap();
let mut writer = stdout_writer.lock().await;
writer
.write_all(
TransportDelegate::build_rpc_message(message)
.as_bytes(),
)
.await
.unwrap();
writer.flush().await.unwrap();
} else {
if let Some(handle) =
handlers.lock().await.get_mut(request.command.as_str())
{
handle(
request.seq,
request.arguments.unwrap_or(json!({})),
stdout_writer.clone(),
)
.await;
} else {
log::debug!("No handler for {}", request.command);
}
}
} else if let Message::Event(event) = message {
let message = serde_json::to_string(&Message::Event(event)).unwrap();
let mut writer = stdout_writer.lock().await;
writer
.write_all(TransportDelegate::build_rpc_message(message).as_bytes())
.await
.unwrap();
writer.flush().await.unwrap();
} else {
unreachable!("You can only send a request and an event that is redirected to the output reader")
}
}
}
Ok(Message::Event(event)) => {
let message = serde_json::to_string(&Message::Event(event)).unwrap();
let mut writer = stdout_writer.lock().await;
writer
.write_all(TransportDelegate::build_rpc_message(message).as_bytes())
.await
.unwrap();
writer.flush().await.unwrap();
}
_ => unreachable!("You can only send a request and an event that is redirected to the output reader"),
}
}
})
.detach();
})
.detach();
Ok(TransportPipe::new(
Box::new(stdin_writer),