openrtc 2.9.5

OpenRTC: a Rust-first P2P runtime for device discovery, signaling, and iroh/QUIC networking.
Documentation
//! Deterministic persistence ordering tests; no endpoint or network is started.
use super::admission_impl::PersistedManagedScopeGrantRecord;
use super::core_impl::PERSISTENT_MANAGED_ADMISSION_SCOPE;
use super::*;

async fn client_with_storage() -> (Client, std::path::PathBuf, std::path::PathBuf) {
    let client = Client::new_provider_neutral("persistence-test".to_string(), Box::new(|| None));
    let directory = std::env::temp_dir().join(format!(
        "openrtc-grant-order-{}",
        crate::session_token::generate_nonce()
    ));
    tokio::fs::create_dir_all(&directory).await.unwrap();
    *client.native_device_base_dir.write().await = Some(directory.clone());
    let path = client
        .managed_scope_grant_path(PERSISTENT_MANAGED_ADMISSION_SCOPE)
        .await
        .unwrap();
    (client, directory, path)
}

fn serialized(token: &str) -> Vec<u8> {
    serde_json::to_vec(&PersistedManagedScopeGrantRecord {
        scope: PERSISTENT_MANAGED_ADMISSION_SCOPE.to_string(),
        token: token.to_string(),
        max_connections: 0,
    })
    .unwrap()
}

fn install_current(client: &Client, token: &str) {
    // Same owner order as the production issuer; persistence is exercised via
    // its actual Client methods below, without starting a transport endpoint.
    let mut cache = client.managed_scope_tickets.write().unwrap();
    cache.persistent_load_allowed = false;
    client.session_token_registry.register(
        token.to_string(),
        PERSISTENT_MANAGED_ADMISSION_SCOPE,
        0,
    );
    cache.insert(
        PERSISTENT_MANAGED_ADMISSION_SCOPE.to_string(),
        CachedManagedScopeTicket {
            scope: PERSISTENT_MANAGED_ADMISSION_SCOPE.into(),
            token: token.to_string(),
            max_connections: 0,
            compound_ticket: String::new(),
            iroh_ticket: String::new(),
        },
    );
}

async fn persisted_token(path: &std::path::Path) -> String {
    serde_json::from_slice::<PersistedManagedScopeGrantRecord>(
        &tokio::fs::read(path).await.unwrap(),
    )
    .unwrap()
    .token
}

#[tokio::test]
async fn old_scope_finish_cannot_delete_newly_persisted_same_scope_grant() {
    let (client, directory, path) = client_with_storage().await;
    install_current(&client, "old");
    client
        .persist_managed_scope_grant(PERSISTENT_MANAGED_ADMISSION_SCOPE, "old", 0)
        .await
        .unwrap();
    client.begin_revoke_tokens_by_scope(PERSISTENT_MANAGED_ADMISSION_SCOPE);
    install_current(&client, "fresh");
    client
        .persist_managed_scope_grant(PERSISTENT_MANAGED_ADMISSION_SCOPE, "fresh", 0)
        .await
        .unwrap();
    client
        .delete_persisted_managed_scope_grant(PERSISTENT_MANAGED_ADMISSION_SCOPE)
        .await
        .unwrap();
    assert_eq!(persisted_token(&path).await, "fresh");
    assert!(client
        .session_token_registry
        .validate_and_consume("old")
        .is_err());
    assert!(client
        .session_token_registry
        .validate_and_consume("fresh")
        .is_ok());
    tokio::fs::remove_dir_all(directory).await.unwrap();
}

#[tokio::test]
async fn prepared_old_write_cannot_overwrite_new_same_scope_grant() {
    let (client, directory, path) = client_with_storage().await;
    install_current(&client, "old");
    let prepared = Client::prepare_private_managed_scope_grant(&path, &serialized("old"))
        .await
        .unwrap();
    client.begin_revoke_tokens_by_scope(PERSISTENT_MANAGED_ADMISSION_SCOPE);
    install_current(&client, "fresh");
    client
        .persist_managed_scope_grant(PERSISTENT_MANAGED_ADMISSION_SCOPE, "fresh", 0)
        .await
        .unwrap();
    assert!(!client
        .commit_prepared_managed_scope_grant(
            &path,
            &prepared,
            PERSISTENT_MANAGED_ADMISSION_SCOPE,
            "old",
            0
        )
        .unwrap());
    assert_eq!(persisted_token(&path).await, "fresh");
    tokio::fs::remove_dir_all(directory).await.unwrap();
}

#[tokio::test]
async fn revoke_during_pending_startup_load_prevents_old_secret_registration() {
    for revoke_token in [false, true] {
        let (client, directory, path) = client_with_storage().await;
        tokio::fs::write(&path, serialized("old")).await.unwrap();
        // Force the actual rehydration future to suspend before acquiring its
        // persistence path. The disk file deliberately remains after revoke.
        let path_owner = client.native_device_base_dir.write().await;
        let mut load =
            std::pin::pin!(client
                .rehydrate_persistent_managed_scope_ticket(PERSISTENT_MANAGED_ADMISSION_SCOPE));
        assert!(matches!(
            futures::poll!(load.as_mut()),
            std::task::Poll::Pending
        ));
        if revoke_token {
            client.revoke_session_token("old");
        } else {
            client.begin_revoke_tokens_by_scope(PERSISTENT_MANAGED_ADMISSION_SCOPE);
        }
        drop(path_owner);
        load.await.unwrap();
        assert!(!client
            .managed_scope_tickets
            .read()
            .unwrap()
            .contains_key(PERSISTENT_MANAGED_ADMISSION_SCOPE));
        assert!(client
            .session_token_registry
            .validate_and_consume("old")
            .is_err());
        tokio::fs::remove_dir_all(directory).await.unwrap();
    }
}

#[tokio::test]
async fn startup_import_is_consumed_and_failed_delete_cannot_resurrect_it() {
    let (client, directory, path) = client_with_storage().await;
    tokio::fs::write(&path, serialized("old")).await.unwrap();
    client
        .rehydrate_persistent_managed_scope_ticket(PERSISTENT_MANAGED_ADMISSION_SCOPE)
        .await
        .unwrap();
    assert_eq!(
        client
            .managed_scope_tickets
            .read()
            .unwrap()
            .get(PERSISTENT_MANAGED_ADMISSION_SCOPE)
            .unwrap()
            .token,
        "old"
    );
    client.begin_revoke_tokens_by_scope(PERSISTENT_MANAGED_ADMISSION_SCOPE);
    // Recreate the stale file to model failure/delay of physical deletion.
    tokio::fs::write(&path, serialized("old")).await.unwrap();
    client
        .rehydrate_persistent_managed_scope_ticket(PERSISTENT_MANAGED_ADMISSION_SCOPE)
        .await
        .unwrap();
    assert!(client
        .session_token_registry
        .validate_and_consume("old")
        .is_err());
    assert!(!client
        .managed_scope_tickets
        .read()
        .unwrap()
        .contains_key(PERSISTENT_MANAGED_ADMISSION_SCOPE));
    tokio::fs::remove_dir_all(directory).await.unwrap();
}

#[tokio::test]
async fn current_revocation_removes_disk_grant_and_unrelated_scope_preserves_startup() {
    let (client, directory, path) = client_with_storage().await;
    tokio::fs::write(&path, serialized("old")).await.unwrap();
    client.begin_revoke_tokens_by_scope("unrelated");
    client
        .rehydrate_persistent_managed_scope_ticket(PERSISTENT_MANAGED_ADMISSION_SCOPE)
        .await
        .unwrap();
    assert!(client
        .session_token_registry
        .validate_and_consume("old")
        .is_ok());
    client.begin_revoke_tokens_by_scope(PERSISTENT_MANAGED_ADMISSION_SCOPE);
    client
        .delete_persisted_managed_scope_grant(PERSISTENT_MANAGED_ADMISSION_SCOPE)
        .await
        .unwrap();
    assert!(!path.exists());
    tokio::fs::remove_dir_all(directory).await.unwrap();
}

#[tokio::test]
async fn unrelated_token_revoke_preserves_startup_grant_but_exact_revoke_blocks_it() {
    for matching in [false, true] {
        let (client, directory, path) = client_with_storage().await;
        tokio::fs::write(&path, serialized("persisted"))
            .await
            .unwrap();
        client.revoke_session_token(if matching { "persisted" } else { "unrelated" });
        assert_eq!(
            path.exists(),
            !matching,
            "exact disk-only revocation must also be durable"
        );
        client
            .rehydrate_persistent_managed_scope_ticket(PERSISTENT_MANAGED_ADMISSION_SCOPE)
            .await
            .unwrap();
        assert_eq!(
            client
                .session_token_registry
                .validate_and_consume("persisted")
                .is_ok(),
            !matching
        );
        tokio::fs::remove_dir_all(directory).await.unwrap();
    }
}

#[tokio::test]
async fn explicit_clear_prevents_pending_startup_import() {
    let (client, directory, path) = client_with_storage().await;
    tokio::fs::write(&path, serialized("old")).await.unwrap();
    client.clear_session_tokens();
    client
        .rehydrate_persistent_managed_scope_ticket(PERSISTENT_MANAGED_ADMISSION_SCOPE)
        .await
        .unwrap();
    assert!(client
        .session_token_registry
        .validate_and_consume("old")
        .is_err());
    tokio::fs::remove_dir_all(directory).await.unwrap();
}