0

For some reason, I am unable to read from the child process stderr the second time. Here is what I do.

I am spawning a child process for cucumber tests. In the first step I spawn the process, take its stderr, save it, and then read from it. Here is the code:

pub fn wait_process_output(
    reader: &mut BufReader<ChildStderr>,
    output: Vec<(String, u16)>,
) -> Result<(), String> {
    let mut process_output = String::new();
    loop {
        match reader.read_line(&mut process_output) {
            Err(e) => {
                return Err(format!("Unable to read output: {}", e));
            }
            Ok(_) => {
                // processing here
            }
        };
    }
}

pub fn step1(world: &mut TestWorld) {
    world.app_handler = Some(
        Command::new(&world.app_bin)
            .stderr(Stdio::piped())
            .spawn()
            .unwrap(),
    );
    let app_stderr = world.app_handler.as_mut().unwrap().stderr.take().unwrap();
    world.app_reader = Some(BufReader::new(app_stderr));
    wait_process_output(world.app_reader.as_mut().unwrap(), /* expected data */).ok();
}

This code works correctly: stderr is being read as expected.

In the third test step, I try to read process output one more time:

pub fn step3(world: &mut TestWorld) {
    wait_process_output(world.app_reader.as_mut().unwrap(), /* expected data */).ok();
}

This time reader.read_line hangs infinitely: nothing is being read. I am sure the child process produces some output: I can see it if I run it within the same conditions separately.

Could you please suggest any ideas why the BufReader object becomes corrupted when I try to read from it the second time?

kasom
  • 43
  • 4
  • 1
    `step1()` reads until end-of-file is reached, thus there is nothing more to be read in `step3()`. – prog-fh Dec 12 '21 at 13:01

1 Answers1

0

I got to the solution. The issue was that app produced an output earlier than step3 started to read it. I thought that there is some kind of buffer implemented for this kind of situation but it seems I was wrong. So I finally used the following two methods to solve my issue:

pub fn wait_process_output(
    receiver: &Receiver<String>,
    output: Vec<(String, u16)>,
) -> Result<(), String> {
    loop {
        match receiver.try_recv() {
            // process output
        }
    }
}

pub fn start_listener(sender: Sender<String>, stream: ChildStderr) {
    spawn(move || {
        let mut f = BufReader::new(stream);
        loop {
            let mut buf = String::new();
            match f.read_line(&mut buf) {
                Ok(_) => {
                    sender.send(buf).unwrap();
                    continue;
                }
                Err(e) => {
                    println!("Unable to read process stderr: {:?}", e);
                    break;
                }
            }
        }
    });
}
kasom
  • 43
  • 4