Repository: tokio-rs/tokio
File: tokio/tests/net_named_pipe.rs (Rust)

Code before:
    const PIPE_NAME: &str = r"\\.\pipe\test-named-pipe-mode-message";

    let server = ServerOptions::new()
        .pipe_mode(PipeMode::Message)
        .create(PIPE_NAME)?;

    let _ = ClientOptions::new().open(PIPE_NAME)?;
    server.connect().await?;
    Ok(())
}

// This tests `NamedPipeServer::connect` with various access settings.
#[tokio::test]
async fn test_named_pipe_access() -> io::Result<()> {
    const PIPE_NAME: &str = r"\\.\pipe\test-named-pipe-access";

    for (inb, outb) in [(true, true), (true, false), (false, true)] {
        let server = tokio::spawn(async move {
            let s = ServerOptions::new()
                .access_inbound(inb)
                .access_outbound(outb)
                .create(PIPE_NAME)?;
            s.connect().await
        });
        // Wait for the server to call connect.
        time::sleep(Duration::from_millis(10)).await;
        let _ = ClientOptions::new().read(outb).write(inb).open(PIPE_NAME)?;
        server.await??;
    }
    Ok(())
}

fn num_instances(pipe_name: impl AsRef<str>) -> io::Result<u32> {
    use ntapi::ntioapi;
    use winapi::shared::ntdef;

    let mut name = pipe_name.as_ref().encode_utf16().collect::<Vec<_>>();
    let mut name = ntdef::UNICODE_STRING {
        Length: (name.len() * mem::size_of::<u16>()) as u16,
        MaximumLength: (name.len() * mem::size_of::<u16>()) as u16,
        Buffer: name.as_mut_ptr(),
    };
    let root = std::fs::File::open(r"\\.\Pipe\")?;
    let mut io_status_block = unsafe { mem::zeroed() };
    let mut file_directory_information = [0_u8; 1024];

    let status = unsafe {
        ntioapi::NtQueryDirectoryFile(
            root.as_raw_handle(),
            std::ptr::null_mut(),
            None,

Review comment (suggestion):
We can't have tests that depend on timing. They are brittle, and make the test suite take a long time. 10 ms sleeps add up to seconds surprisingly quickly if you have lots of tests.

You can do something like this:
```Rust
let (tx, rx) = tokio::sync::oneshot::channel();
let server = tokio::spawn(async move {
    let s = ServerOptions::new()
        .access_inbound(inb)
        .access_outbound(outb)
        .create(PIPE_NAME)?;

    let mut connect_fut = tokio_test::task::spawn(s.connect());
    assert!(connect_fut.poll().is_pending());

    let _ = tx.send(());

    connect_fut.await.unwrap();
});

// Wait for the server to call connect.
rx.await.unwrap();
let _ = ClientOptions::new().read(outb).write(inb).open(PIPE_NAME)?;
```

Code after:
    const PIPE_NAME: &str = r"\\.\pipe\test-named-pipe-mode-message";

    let server = ServerOptions::new()
        .pipe_mode(PipeMode::Message)
        .create(PIPE_NAME)?;

    let _ = ClientOptions::new().open(PIPE_NAME)?;
    server.connect().await?;
    Ok(())
}

// This tests `NamedPipeServer::connect` with various access settings.
#[tokio::test]
async fn test_named_pipe_access() -> io::Result<()> {
    const PIPE_NAME: &str = r"\\.\pipe\test-named-pipe-access";

    for (inb, outb) in [(true, true), (true, false), (false, true)] {
        let (tx, rx) = tokio::sync::oneshot::channel();
        let server = tokio::spawn(async move {
            let s = ServerOptions::new()
                .access_inbound(inb)
                .access_outbound(outb)
                .create(PIPE_NAME)?;
            let mut connect_fut = tokio_test::task::spawn(s.connect());
            assert!(connect_fut.poll().is_pending());
            tx.send(()).unwrap();
            connect_fut.await
        });

        // Wait for the server to call connect.
        rx.await.unwrap();
        let _ = ClientOptions::new().read(outb).write(inb).open(PIPE_NAME)?;

        server.await??;
    }
    Ok(())
}

fn num_instances(pipe_name: impl AsRef<str>) -> io::Result<u32> {
    use ntapi::ntioapi;
    use winapi::shared::ntdef;

    let mut name = pipe_name.as_ref().encode_utf16().collect::<Vec<_>>();
    let mut name = ntdef::UNICODE_STRING {
        Length: (name.len() * mem::size_of::<u16>()) as u16,
        MaximumLength: (name.len() * mem::size_of::<u16>()) as u16,
        Buffer: name.as_mut_ptr(),
    };
    let root = std::fs::File::open(r"\\.\Pipe\")?;
    let mut io_status_block = unsafe { mem::zeroed() };
    let mut file_directory_information = [0_u8; 1024];