dope-tls 0.49.0

TCP TLS streams for dope runtime, rustls-backed
use std::sync::Arc;

use dope::{
    core::driver::route::KeyTag,
    net::wire::{
        domain::{Bootstrap as _, Limits},
        open::{self, Runtime as _},
        send::Store as _,
    },
};
use dope_test::alloc::Tracker;
use dope_tls::{
    Error,
    config::raw::Identity,
    tls::{endpoint, protocol::Bootstrap, roles},
};

#[global_allocator]
static ALLOCATOR: Tracker = Tracker::new();

#[test]
fn alpn_allocation_retries() {
    let sessions = endpoint::Sessions::<roles::Client>::try_new(1).expect("one session slot");
    let mut native = Identity::client([7; 32]).expect("client configuration");
    native.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
    let config = endpoint::Config::client(
        Arc::new(native),
        "example.com".try_into().expect("borrowed server name"),
    );
    let mut runtime = Bootstrap::<roles::Client>::try_runtime::<KeyTag<0>>(
        Limits::fixed::<1, 0, 0, { 64 * 1024 }>(),
        config.bind(&sessions),
    )
    .expect("endpoint runtime");

    for allows in 0..3 {
        let (result, activity) = Tracker::activity(|| {
            Tracker::fail_after(allows, || {
                runtime.open(allows, |_, wire, send| {
                    open::Disposition::Commit((wire, send))
                })
            })
        });
        let (context, cause) = match result {
            open::Outcome::Failed { context, cause } => Some((context, cause)),
            _ => None,
        }
        .expect("ALPN allocation must fail before opening TLS");
        assert_eq!(context, allows);
        assert!(matches!(
            cause.into_cause(),
            Error::Allocation(o3::alloc::Error::Exhausted)
        ));
        assert_eq!(
            (activity.allocations, activity.deallocations),
            (allows, allows)
        );
        assert_eq!(activity.allocated_bytes, activity.deallocated_bytes);
    }

    let parts = match runtime.open((), |(), wire, send| open::Disposition::Commit((wire, send))) {
        open::Outcome::Opened(parts) => Some(parts),
        _ => None,
    }
    .expect("retry must reuse the session and send slots");
    assert!(!parts.1.as_slice().is_empty());
}