Skip to content

Commit 3c4f92e

Browse files
committed
test-utils: surface dpd errors.
At the moment, DendriteInstance::start in omicron-test-utils doesn't catch errors in dpd. We spawn a child process, wait up to the timeout interval to discover the dpd port from its logs, and fail if we can't discover the port. But if dpd exits quickly, we still wait the timeout interval and swallow any errors. This patch captures the stderr of the dpd child process, checks it for an early exit, and prints the details if dpd crashes.
1 parent 2967351 commit 3c4f92e

File tree

1 file changed

+50
-15
lines changed

1 file changed

+50
-15
lines changed

test-utils/src/dev/dendrite.rs

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -63,27 +63,25 @@ impl DendriteInstance {
6363
args.push(socket_addr.to_string());
6464
}
6565

66-
let child = tokio::process::Command::new("dpd")
66+
let mut child = tokio::process::Command::new("dpd")
6767
.args(&args)
6868
.stdin(Stdio::null())
6969
.stdout(Stdio::from(redirect_file(
7070
temp_dir.path(),
7171
"dendrite_stdout",
7272
)?))
73-
.stderr(Stdio::from(redirect_file(
74-
temp_dir.path(),
75-
"dendrite_stderr",
76-
)?))
73+
.stderr(Stdio::piped())
7774
.spawn()
7875
.with_context(|| {
7976
format!("failed to spawn `dpd` (with args: {:?})", &args)
8077
})?;
81-
82-
let child = Some(child);
78+
let stderr = child.stderr.take().unwrap();
8379

8480
let temp_dir = temp_dir.keep();
8581
if port == 0 {
8682
port = discover_port(
83+
&mut child,
84+
stderr,
8785
temp_dir.join("dendrite_stdout").display().to_string(),
8886
)
8987
.await
@@ -95,7 +93,7 @@ impl DendriteInstance {
9593
})?;
9694
}
9795

98-
Ok(Self { port, args, child, data_dir: Some(temp_dir) })
96+
Ok(Self { port, args, child: Some(child), data_dir: Some(temp_dir) })
9997
}
10098

10199
pub async fn cleanup(&mut self) -> Result<(), anyhow::Error> {
@@ -145,20 +143,45 @@ fn redirect_file(
145143
.with_context(|| format!("open \"{}\"", out_path.display()))
146144
}
147145

148-
async fn discover_port(logfile: String) -> Result<u16, anyhow::Error> {
146+
async fn discover_port(
147+
child: &mut tokio::process::Child,
148+
stderr: tokio::process::ChildStderr,
149+
logfile: String,
150+
) -> Result<u16, anyhow::Error> {
149151
let timeout = Instant::now() + DENDRITE_TIMEOUT;
150-
tokio::time::timeout_at(timeout, find_dendrite_port_in_log(logfile))
151-
.await
152-
.context("time out while discovering dendrite port number")?
152+
tokio::time::timeout_at(
153+
timeout,
154+
find_dendrite_port_in_log(child, stderr, logfile),
155+
)
156+
.await
157+
.context("time out while discovering dendrite port number")?
153158
}
154159

155160
async fn find_dendrite_port_in_log(
161+
child: &mut tokio::process::Child,
162+
mut stderr: tokio::process::ChildStderr,
156163
logfile: String,
157164
) -> Result<u16, anyhow::Error> {
158165
let re = regex::Regex::new(r#""local_addr":"\[::1\]:([0-9]+)""#).unwrap();
159166
let mut reader = BufReader::new(File::open(&logfile).await?);
160167
let mut lines = reader.lines();
161168
loop {
169+
// Exit early if the process has exited.
170+
if let Some(exit_status) = child.try_wait()? {
171+
let mut stderr_contents = String::new();
172+
tokio::io::AsyncReadExt::read_to_string(
173+
&mut stderr,
174+
&mut stderr_contents,
175+
)
176+
.await?;
177+
178+
anyhow::bail!(
179+
"dpd exited with status {} before port could be discovered: {}",
180+
exit_status,
181+
stderr_contents
182+
);
183+
}
184+
162185
match lines.next_line().await? {
163186
Some(line) => {
164187
if let Some(cap) = re.captures(&line) {
@@ -212,10 +235,22 @@ mod tests {
212235
writeln!(file, "Another garbage line").unwrap();
213236
file.flush().unwrap();
214237

238+
let mut child = tokio::process::Command::new("dpd")
239+
.stdin(Stdio::null())
240+
.stdout(Stdio::null())
241+
.stderr(Stdio::piped())
242+
.spawn()
243+
.unwrap();
244+
let stderr = child.stderr.take().unwrap();
245+
215246
assert_eq!(
216-
find_dendrite_port_in_log(file.path().display().to_string())
217-
.await
218-
.unwrap(),
247+
find_dendrite_port_in_log(
248+
&mut child,
249+
stderr,
250+
file.path().display().to_string()
251+
)
252+
.await
253+
.unwrap(),
219254
EXPECTED_PORT
220255
);
221256
}

0 commit comments

Comments
 (0)