blob: 08ac99352deca73f083b41cf4b4042a0c8a0f01a [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#![cfg(test)]
use fdio::{SpawnAction, SpawnOptions};
use fuchsia_async as fasync;
use fuchsia_runtime::{job_default, HandleInfo, HandleType};
use fuchsia_zircon::{self as zx, ProcessInfo};
use futures::io::{AsyncBufReadExt as _, AsyncReadExt as _, BufReader};
use libc::{STDERR_FILENO, STDOUT_FILENO};
use std::{convert::TryInto as _, ffi::CString};
const BINARY_PATH: &str = "/pkg/bin/tcpdump";
#[fuchsia::test]
async fn version_test() {
let (stdout_reader, stdout_writer) =
zx::Socket::create(zx::SocketOpts::STREAM).expect("create stdout socket");
let (stderr_reader, stderr_writer) =
zx::Socket::create(zx::SocketOpts::STREAM).expect("create stderr socket");
// The reader-ends should not write.
let () = stdout_reader.half_close().expect("stdout_reader.half_close");
let () = stderr_reader.half_close().expect("stderr_reader.half_close");
let path = CString::new(BINARY_PATH).expect("cstring path");
let path = path.as_c_str();
let process = fdio::spawn_etc(
&job_default(),
SpawnOptions::DEFAULT_LOADER,
path,
&[path, CString::new("--version").expect("cstring versiona arg").as_c_str()][..],
None,
&mut [
// Provide the socket that TCPDump should use for stdout.
SpawnAction::add_handle(
HandleInfo::new(
HandleType::FileDescriptor,
STDOUT_FILENO.try_into().expect("STDOUT_FILENO.try_into"),
),
stdout_writer.into(),
),
// Provide the socket that TCPDump should use for stderr.
SpawnAction::add_handle(
HandleInfo::new(
HandleType::FileDescriptor,
STDERR_FILENO.try_into().expect("STDERR_FILENO.try_into"),
),
stderr_writer.into(),
),
],
)
.expect("spawn tcpdump");
assert_eq!(
fasync::OnSignals::new(&process, zx::Signals::PROCESS_TERMINATED)
.await
.expect("wait for process termination"),
zx::Signals::PROCESS_TERMINATED
);
let ProcessInfo { return_code, start_time: _, flags: _ } =
process.info().expect("process info");
assert_eq!(return_code, 0);
let mut stdout_reader =
BufReader::new(fasync::Socket::from_socket(stdout_reader).expect("async socket stdout"));
let mut patterns = vec![
"tcpdump version tcpdump-4.99.0 (2fef164426273c4c610a3c060b7990db0e99914d)",
"libpcap version libpcap-1.10.1 (c7642e2cc0c5bd65754685b160d25dc23c76c6bd)",
];
while !patterns.is_empty() {
let mut stdout = String::new();
let read_bytes = stdout_reader.read_line(&mut stdout).await.expect("stdout read_line");
if read_bytes == 0 {
let mut stderr = String::new();
let _read_bytes: usize = fasync::Socket::from_socket(stderr_reader)
.expect("async socket stdout")
.read_to_string(&mut stderr)
.await
.expect("read stderr to string");
panic!(
"failed to match all patterns from stdout; patterns = {:?}\nSTDERR:\n{}",
patterns, stderr
);
}
// Trim the trailing new line.
let stdout = &stdout[..stdout.len() - 1];
let () = patterns.retain(|pattern| &stdout != pattern);
}
}