Skip to content

Commit f4e2e7a

Browse files
aperezmeta-codesync[bot]
authored andcommitted
Preserve source breakpoint metadata over gRPC
Summary: Carry every DAP `SourceBreakpoint` field through the control-plane protobuf without collapsing present empty strings. Retain existing field tags for wire compatibility. Reviewed By: barsolo2000 Differential Revision: D113562969 fbshipit-source-id: 986092569733960a156fff00076f3d7935bdf16a
1 parent b722a9f commit f4e2e7a

2 files changed

Lines changed: 80 additions & 16 deletions

File tree

dapper_control_api/src/grpc.rs

Lines changed: 75 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -288,17 +288,11 @@ where
288288
.into_iter()
289289
.map(|bp| SourceBreakpoint {
290290
line: bp.line,
291-
condition: if bp.condition.is_empty() {
292-
None
293-
} else {
294-
Some(bp.condition)
295-
},
296-
log_message: if bp.log_message.is_empty() {
297-
None
298-
} else {
299-
Some(bp.log_message)
300-
},
301-
..Default::default()
291+
column: bp.column,
292+
condition: bp.condition,
293+
hit_condition: bp.hit_condition,
294+
log_message: bp.log_message,
295+
mode: bp.mode,
302296
})
303297
.collect()
304298
} else {
@@ -785,8 +779,11 @@ impl DapperControlPlane for DapperControlPlaneClient {
785779
.iter()
786780
.map(|bp| dapper_control_proto::SourceBreakpoint {
787781
line: bp.line,
788-
condition: bp.condition.clone().unwrap_or_default(),
789-
log_message: bp.log_message.clone().unwrap_or_default(),
782+
condition: bp.condition.clone(),
783+
hit_condition: bp.hit_condition.clone(),
784+
log_message: bp.log_message.clone(),
785+
column: bp.column,
786+
mode: bp.mode.clone(),
790787
})
791788
.collect();
792789
let lines: Vec<i64> = breakpoint_specs.iter().map(|bp| bp.line).collect();
@@ -877,6 +874,7 @@ impl DapperControlPlane for DapperControlPlaneClient {
877874
#[cfg(test)]
878875
mod tests {
879876
use std::sync::Arc;
877+
use std::sync::Mutex;
880878
use std::sync::atomic::AtomicBool;
881879
use std::sync::atomic::Ordering;
882880

@@ -912,10 +910,14 @@ mod tests {
912910

913911
struct TestServer {
914912
stop_was_called: Arc<AtomicBool>,
913+
breakpoint_specs: Arc<Mutex<Vec<SourceBreakpoint>>>,
915914
}
916915
impl TestServer {
917916
fn new(stop_was_called: Arc<AtomicBool>) -> Self {
918-
TestServer { stop_was_called }
917+
TestServer {
918+
stop_was_called,
919+
breakpoint_specs: Arc::new(Mutex::new(Vec::new())),
920+
}
919921
}
920922
}
921923
#[async_trait::async_trait]
@@ -1062,6 +1064,11 @@ mod tests {
10621064
clear_existing: bool,
10631065
breakpoint_specs: &[SourceBreakpoint],
10641066
) -> anyhow::Result<ControlPlaneResult<dapper_session::SetBreakpointsResult>> {
1067+
*self
1068+
.breakpoint_specs
1069+
.lock()
1070+
.expect("breakpoint recorder mutex should not be poisoned") =
1071+
breakpoint_specs.to_vec();
10651072
let breakpoints = breakpoint_specs
10661073
.iter()
10671074
.map(|bp| dapper_session::BreakpointInfo {
@@ -1165,6 +1172,60 @@ mod tests {
11651172
}
11661173
}
11671174

1175+
async fn round_trip_breakpoint_specs(
1176+
breakpoint_specs: &[SourceBreakpoint],
1177+
) -> anyhow::Result<Vec<SourceBreakpoint>> {
1178+
let server = TestServer::new(Arc::new(AtomicBool::new(false)));
1179+
let recorded_specs = Arc::clone(&server.breakpoint_specs);
1180+
let control_plane_server = serve(None, server).await?;
1181+
tokio::task::yield_now().await;
1182+
1183+
let client = DapperControlPlaneClient::for_port(control_plane_server.port);
1184+
let result = client
1185+
.set_breakpoints("/path/to/file.py", true, breakpoint_specs)
1186+
.await;
1187+
control_plane_server.handle.abort();
1188+
result?;
1189+
1190+
let specs = recorded_specs
1191+
.lock()
1192+
.expect("breakpoint recorder mutex should not be poisoned")
1193+
.clone();
1194+
Ok(specs)
1195+
}
1196+
1197+
#[tokio::test]
1198+
async fn set_breakpoints_grpc_preserves_source_breakpoint_metadata() -> anyhow::Result<()> {
1199+
let expected = SourceBreakpoint {
1200+
line: 42,
1201+
column: Some(7),
1202+
condition: Some("x > 0".into()),
1203+
hit_condition: Some("3".into()),
1204+
log_message: Some("hit {x}".into()),
1205+
mode: Some("hardware".into()),
1206+
};
1207+
1208+
let recorded = round_trip_breakpoint_specs(std::slice::from_ref(&expected)).await?;
1209+
assert_eq!(recorded, vec![expected]);
1210+
Ok(())
1211+
}
1212+
1213+
#[tokio::test]
1214+
async fn set_breakpoints_grpc_preserves_present_empty_strings() -> anyhow::Result<()> {
1215+
let expected = SourceBreakpoint {
1216+
line: 42,
1217+
condition: Some(String::new()),
1218+
hit_condition: Some(String::new()),
1219+
log_message: Some(String::new()),
1220+
mode: Some(String::new()),
1221+
..Default::default()
1222+
};
1223+
1224+
let recorded = round_trip_breakpoint_specs(std::slice::from_ref(&expected)).await?;
1225+
assert_eq!(recorded, vec![expected]);
1226+
Ok(())
1227+
}
1228+
11681229
#[tokio::test]
11691230
async fn client_calls_server() -> anyhow::Result<()> {
11701231
let stop_was_called = Arc::new(AtomicBool::new(false));

dapper_control_proto/control.proto

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,11 @@ message SetVariableResponse {
111111

112112
message SourceBreakpoint {
113113
int64 line = 1;
114-
string condition = 2;
115-
string log_message = 4;
114+
optional string condition = 2;
115+
optional string hit_condition = 3;
116+
optional string log_message = 4;
117+
optional int64 column = 5;
118+
optional string mode = 6;
116119
}
117120

118121
message SetBreakpointsRequest {

0 commit comments

Comments
 (0)