feat(endpoint): add tests and mark tasks 1-7 as completed
- Add 7 registry tests (handler_registry_*) to registry.rs - Add 4 dispatch tests (build_auth_context_*, dispatch_decision_logic_*) to dispatch.rs - Add 6 endpoint tests to endpoint.rs: - debug_for_alknet_endpoint_is_implemented_without_panicking - endpoint_constructs_with_iroh_raw_key_identity (adapted for new API) - iroh_endpoint_runs_accept_loop_and_shutdown (adapted for new API) - with_iroh_sets_field (replaces has_iroh_identity_true_for_raw_key) - without_iroh_field_is_none (replaces has_iroh_identity_false_for_x509) - endpoint_works_without_iroh (replaces has_iroh_identity_false_when_no_identity) - Add async-trait as dev-dependency - All 17 tests pass with iroh feature - All 8 tests pass without features - Workspace tests all pass (no breakage) - Mark tasks 1-7 as completed
This commit is contained in:
1 parent
2755b995c6
commit
5467c30892
12 files changed
+451
-7
No files matched your search
Generated
+1
@@ -103,6 +103,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"alknet-core",
|
"alknet-core",
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
|
"async-trait",
|
||||||
"iroh",
|
"iroh",
|
||||||
"quinn",
|
"quinn",
|
||||||
"rustls",
|
"rustls",
|
||||||
|
|||||||
@@ -25,3 +25,6 @@ rustls = "0.23"
|
|||||||
quinn = { version = "0.11", optional = true }
|
quinn = { version = "0.11", optional = true }
|
||||||
iroh = { version = "1.0", optional = true, default-features = false, features = ["tls-aws-lc-rs"] }
|
iroh = { version = "1.0", optional = true, default-features = false, features = ["tls-aws-lc-rs"] }
|
||||||
tokio-rustls = { version = "0.26", optional = true }
|
tokio-rustls = { version = "0.26", optional = true }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
async-trait = "0.1"
|
||||||
@@ -74,3 +74,165 @@ pub(crate) fn build_auth_context(
|
|||||||
tls_client_fingerprint,
|
tls_client_fingerprint,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#[cfg(any(feature = "quinn", feature = "iroh", feature = "tcp"))]
|
||||||
|
use super::build_auth_context;
|
||||||
|
#[cfg(any(feature = "quinn", feature = "iroh", feature = "tcp"))]
|
||||||
|
use std::collections::HashMap;
|
||||||
|
#[cfg(any(feature = "quinn", feature = "iroh", feature = "tcp"))]
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
#[cfg(any(feature = "quinn", feature = "iroh", feature = "tcp"))]
|
||||||
|
use alknet_core::auth::{AuthToken, Identity, IdentityProvider};
|
||||||
|
#[cfg(any(feature = "quinn", feature = "iroh", feature = "tcp"))]
|
||||||
|
use alknet_core::types::{Connection, HandlerError};
|
||||||
|
#[cfg(any(feature = "quinn", feature = "iroh", feature = "tcp"))]
|
||||||
|
use async_trait::async_trait;
|
||||||
|
|
||||||
|
#[cfg(any(feature = "quinn", feature = "iroh", feature = "tcp"))]
|
||||||
|
use crate::registry::HandlerRegistry;
|
||||||
|
|
||||||
|
#[cfg(any(feature = "quinn", feature = "iroh", feature = "tcp"))]
|
||||||
|
struct DummyHandler {
|
||||||
|
alpn: &'static [u8],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "quinn", feature = "iroh", feature = "tcp"))]
|
||||||
|
#[async_trait]
|
||||||
|
impl alknet_core::types::ProtocolHandler for DummyHandler {
|
||||||
|
fn alpn(&self) -> &'static [u8] {
|
||||||
|
self.alpn
|
||||||
|
}
|
||||||
|
async fn handle(
|
||||||
|
&self,
|
||||||
|
_connection: Connection,
|
||||||
|
_auth: &alknet_core::auth::AuthContext,
|
||||||
|
) -> Result<(), HandlerError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "quinn", feature = "iroh", feature = "tcp"))]
|
||||||
|
fn make_handler(alpn: &'static [u8]) -> Arc<dyn alknet_core::types::ProtocolHandler> {
|
||||||
|
Arc::new(DummyHandler { alpn })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "quinn", feature = "iroh", feature = "tcp"))]
|
||||||
|
#[test]
|
||||||
|
fn build_auth_context_resolves_identity_from_fingerprint() {
|
||||||
|
struct StaticProvider;
|
||||||
|
impl IdentityProvider for StaticProvider {
|
||||||
|
fn resolve_from_fingerprint(&self, fp: &str) -> Option<Identity> {
|
||||||
|
if fp == "SHA256:known" {
|
||||||
|
Some(Identity {
|
||||||
|
id: "SHA256:known".to_string(),
|
||||||
|
scopes: vec![],
|
||||||
|
resources: HashMap::new(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn resolve_from_token(&self, _token: &AuthToken) -> Option<Identity> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let provider: Arc<dyn IdentityProvider> = Arc::new(StaticProvider);
|
||||||
|
let auth = build_auth_context(
|
||||||
|
b"alknet/test",
|
||||||
|
None,
|
||||||
|
Some("SHA256:known".to_string()),
|
||||||
|
&provider,
|
||||||
|
);
|
||||||
|
assert_eq!(auth.identity.as_ref().unwrap().id, "SHA256:known");
|
||||||
|
assert_eq!(auth.alpn, b"alknet/test");
|
||||||
|
assert_eq!(auth.tls_client_fingerprint.as_deref(), Some("SHA256:known"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "quinn", feature = "iroh", feature = "tcp"))]
|
||||||
|
#[test]
|
||||||
|
fn build_auth_context_no_fingerprint_no_identity() {
|
||||||
|
struct NoProvider;
|
||||||
|
impl IdentityProvider for NoProvider {
|
||||||
|
fn resolve_from_fingerprint(&self, _fp: &str) -> Option<Identity> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
fn resolve_from_token(&self, _token: &AuthToken) -> Option<Identity> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let provider: Arc<dyn IdentityProvider> = Arc::new(NoProvider);
|
||||||
|
let auth = build_auth_context(b"alknet/test", None, None, &provider);
|
||||||
|
assert!(auth.identity.is_none());
|
||||||
|
assert!(auth.tls_client_fingerprint.is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "quinn", feature = "iroh", feature = "tcp"))]
|
||||||
|
#[test]
|
||||||
|
fn build_auth_context_fingerprint_unknown_identity_none() {
|
||||||
|
struct StaticProvider;
|
||||||
|
impl IdentityProvider for StaticProvider {
|
||||||
|
fn resolve_from_fingerprint(&self, _fp: &str) -> Option<Identity> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
fn resolve_from_token(&self, _token: &AuthToken) -> Option<Identity> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let provider: Arc<dyn IdentityProvider> = Arc::new(StaticProvider);
|
||||||
|
let auth = build_auth_context(
|
||||||
|
b"alknet/test",
|
||||||
|
None,
|
||||||
|
Some("SHA256:unknown".to_string()),
|
||||||
|
&provider,
|
||||||
|
);
|
||||||
|
assert!(auth.identity.is_none());
|
||||||
|
assert!(auth.tls_client_fingerprint.is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "quinn", feature = "iroh", feature = "tcp"))]
|
||||||
|
#[test]
|
||||||
|
fn dispatch_decision_logic_lookup_and_auth() {
|
||||||
|
let mut registry = HandlerRegistry::new();
|
||||||
|
registry.register(make_handler(b"alknet/ssh"));
|
||||||
|
registry.register(make_handler(b"alknet/call"));
|
||||||
|
|
||||||
|
struct StaticProvider;
|
||||||
|
impl IdentityProvider for StaticProvider {
|
||||||
|
fn resolve_from_fingerprint(&self, fp: &str) -> Option<Identity> {
|
||||||
|
if fp == "SHA256:caller" {
|
||||||
|
Some(Identity {
|
||||||
|
id: "SHA256:caller".to_string(),
|
||||||
|
scopes: vec!["relay:connect".to_string()],
|
||||||
|
resources: HashMap::new(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn resolve_from_token(&self, _: &AuthToken) -> Option<Identity> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let provider: Arc<dyn IdentityProvider> = Arc::new(StaticProvider);
|
||||||
|
|
||||||
|
let ssh_handler = registry.get(b"alknet/ssh").expect("ssh handler registered");
|
||||||
|
assert_eq!(ssh_handler.alpn(), b"alknet/ssh");
|
||||||
|
let auth = build_auth_context(
|
||||||
|
b"alknet/ssh",
|
||||||
|
Some(std::net::SocketAddr::new(
|
||||||
|
std::net::IpAddr::V4(std::net::Ipv4Addr::LOCALHOST),
|
||||||
|
1234,
|
||||||
|
)),
|
||||||
|
Some("SHA256:caller".to_string()),
|
||||||
|
&provider,
|
||||||
|
);
|
||||||
|
assert_eq!(auth.identity.as_ref().unwrap().id, "SHA256:caller");
|
||||||
|
assert_eq!(auth.alpn, b"alknet/ssh");
|
||||||
|
|
||||||
|
let unknown = registry.get(b"alknet/unknown");
|
||||||
|
assert!(unknown.is_none(), "unknown ALPN has no handler");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -176,3 +176,189 @@ impl AlknetEndpoint {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use alknet_core::auth::{AuthToken, Identity, IdentityProvider};
|
||||||
|
use alknet_core::config::DynamicConfig;
|
||||||
|
#[cfg(feature = "iroh")]
|
||||||
|
use alknet_core::auth::AuthContext;
|
||||||
|
#[cfg(feature = "iroh")]
|
||||||
|
use alknet_core::types::{Connection, HandlerError};
|
||||||
|
#[cfg(feature = "iroh")]
|
||||||
|
use async_trait::async_trait;
|
||||||
|
|
||||||
|
#[cfg(feature = "iroh")]
|
||||||
|
struct DummyHandler {
|
||||||
|
alpn: &'static [u8],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "iroh")]
|
||||||
|
#[async_trait]
|
||||||
|
impl alknet_core::types::ProtocolHandler for DummyHandler {
|
||||||
|
fn alpn(&self) -> &'static [u8] {
|
||||||
|
self.alpn
|
||||||
|
}
|
||||||
|
async fn handle(
|
||||||
|
&self,
|
||||||
|
_connection: Connection,
|
||||||
|
_auth: &AuthContext,
|
||||||
|
) -> Result<(), HandlerError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "iroh")]
|
||||||
|
fn make_handler(alpn: &'static [u8]) -> Arc<dyn alknet_core::types::ProtocolHandler> {
|
||||||
|
Arc::new(DummyHandler { alpn })
|
||||||
|
}
|
||||||
|
|
||||||
|
struct NoProvider;
|
||||||
|
impl IdentityProvider for NoProvider {
|
||||||
|
fn resolve_from_fingerprint(&self, _: &str) -> Option<Identity> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
fn resolve_from_token(&self, _: &AuthToken) -> Option<Identity> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn debug_for_alknet_endpoint_is_implemented_without_panicking() {
|
||||||
|
let provider: Arc<dyn IdentityProvider> = Arc::new(NoProvider);
|
||||||
|
let dynamic = Arc::new(ArcSwap::from_pointee(DynamicConfig::default()));
|
||||||
|
let registry = HandlerRegistry::new();
|
||||||
|
let endpoint = AlknetEndpoint::new(registry, dynamic, provider, Duration::from_millis(10));
|
||||||
|
let s = format!("{endpoint:?}");
|
||||||
|
assert!(s.contains("AlknetEndpoint"));
|
||||||
|
assert!(s.contains("drain_timeout"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "iroh")]
|
||||||
|
#[tokio::test]
|
||||||
|
async fn endpoint_constructs_with_iroh_raw_key_identity() {
|
||||||
|
let provider: Arc<dyn IdentityProvider> = Arc::new(NoProvider);
|
||||||
|
let dynamic = Arc::new(ArcSwap::from_pointee(DynamicConfig::default()));
|
||||||
|
let mut registry = HandlerRegistry::new();
|
||||||
|
registry.register(make_handler(b"alknet/test"));
|
||||||
|
|
||||||
|
let iroh_endpoint = iroh::Endpoint::builder(iroh::endpoint::presets::Minimal)
|
||||||
|
.secret_key(iroh::SecretKey::generate())
|
||||||
|
.alpns(vec![b"alknet/test".to_vec()])
|
||||||
|
.relay_mode(iroh::RelayMode::Disabled)
|
||||||
|
.bind()
|
||||||
|
.await
|
||||||
|
.expect("iroh endpoint binds");
|
||||||
|
|
||||||
|
let endpoint = AlknetEndpoint::new(registry, dynamic, provider, Duration::from_millis(10))
|
||||||
|
.with_iroh(iroh_endpoint);
|
||||||
|
assert!(endpoint.shutdown_sender().send(true).is_ok());
|
||||||
|
endpoint.shutdown().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "iroh")]
|
||||||
|
#[tokio::test]
|
||||||
|
async fn iroh_endpoint_runs_accept_loop_and_shutdown() {
|
||||||
|
use std::sync::Mutex;
|
||||||
|
let provider: Arc<dyn IdentityProvider> = Arc::new(NoProvider);
|
||||||
|
let dynamic = Arc::new(ArcSwap::from_pointee(DynamicConfig::default()));
|
||||||
|
|
||||||
|
let connected = Arc::new(Mutex::new(false));
|
||||||
|
let connected_clone = connected.clone();
|
||||||
|
struct CountingHandler {
|
||||||
|
alpn: &'static [u8],
|
||||||
|
connected: Arc<Mutex<bool>>,
|
||||||
|
}
|
||||||
|
#[async_trait]
|
||||||
|
impl alknet_core::types::ProtocolHandler for CountingHandler {
|
||||||
|
fn alpn(&self) -> &'static [u8] {
|
||||||
|
self.alpn
|
||||||
|
}
|
||||||
|
async fn handle(
|
||||||
|
&self,
|
||||||
|
_conn: Connection,
|
||||||
|
_auth: &AuthContext,
|
||||||
|
) -> Result<(), HandlerError> {
|
||||||
|
*self.connected.lock().unwrap() = true;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut registry = HandlerRegistry::new();
|
||||||
|
registry.register(Arc::new(CountingHandler {
|
||||||
|
alpn: b"alknet/test",
|
||||||
|
connected: connected_clone,
|
||||||
|
}));
|
||||||
|
|
||||||
|
let iroh_endpoint = iroh::Endpoint::builder(iroh::endpoint::presets::Minimal)
|
||||||
|
.secret_key(iroh::SecretKey::generate())
|
||||||
|
.alpns(vec![b"alknet/test".to_vec()])
|
||||||
|
.relay_mode(iroh::RelayMode::Disabled)
|
||||||
|
.bind()
|
||||||
|
.await
|
||||||
|
.expect("iroh endpoint binds");
|
||||||
|
|
||||||
|
let endpoint = Arc::new(
|
||||||
|
AlknetEndpoint::new(registry, dynamic, provider, Duration::from_millis(20))
|
||||||
|
.with_iroh(iroh_endpoint),
|
||||||
|
);
|
||||||
|
|
||||||
|
let run_endpoint = endpoint.clone();
|
||||||
|
let run_task = tokio::spawn(async move {
|
||||||
|
run_endpoint.run().await;
|
||||||
|
});
|
||||||
|
|
||||||
|
let _ = endpoint.shutdown_sender().send(true);
|
||||||
|
endpoint.shutdown().await;
|
||||||
|
let _ = run_task.await;
|
||||||
|
assert!(!*connected.lock().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "iroh")]
|
||||||
|
#[test]
|
||||||
|
fn with_iroh_sets_field() {
|
||||||
|
let provider: Arc<dyn IdentityProvider> = Arc::new(NoProvider);
|
||||||
|
let dynamic = Arc::new(ArcSwap::from_pointee(DynamicConfig::default()));
|
||||||
|
let registry = HandlerRegistry::new();
|
||||||
|
|
||||||
|
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||||
|
let iroh_endpoint = rt.block_on(async {
|
||||||
|
iroh::Endpoint::builder(iroh::endpoint::presets::Minimal)
|
||||||
|
.secret_key(iroh::SecretKey::generate())
|
||||||
|
.alpns(vec![b"alknet/test".to_vec()])
|
||||||
|
.relay_mode(iroh::RelayMode::Disabled)
|
||||||
|
.bind()
|
||||||
|
.await
|
||||||
|
.expect("iroh endpoint binds")
|
||||||
|
});
|
||||||
|
|
||||||
|
let endpoint = AlknetEndpoint::new(registry, dynamic, provider, Duration::from_millis(10))
|
||||||
|
.with_iroh(iroh_endpoint);
|
||||||
|
assert!(endpoint.iroh.is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "iroh")]
|
||||||
|
#[test]
|
||||||
|
fn without_iroh_field_is_none() {
|
||||||
|
let provider: Arc<dyn IdentityProvider> = Arc::new(NoProvider);
|
||||||
|
let dynamic = Arc::new(ArcSwap::from_pointee(DynamicConfig::default()));
|
||||||
|
let registry = HandlerRegistry::new();
|
||||||
|
let endpoint = AlknetEndpoint::new(registry, dynamic, provider, Duration::from_millis(10));
|
||||||
|
assert!(endpoint.iroh.is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "iroh")]
|
||||||
|
#[test]
|
||||||
|
fn endpoint_works_without_iroh() {
|
||||||
|
let provider: Arc<dyn IdentityProvider> = Arc::new(NoProvider);
|
||||||
|
let dynamic = Arc::new(ArcSwap::from_pointee(DynamicConfig::default()));
|
||||||
|
let mut registry = HandlerRegistry::new();
|
||||||
|
registry.register(make_handler(b"alknet/test"));
|
||||||
|
let endpoint = AlknetEndpoint::new(registry, dynamic, provider, Duration::from_millis(10));
|
||||||
|
assert!(endpoint.iroh.is_none());
|
||||||
|
assert!(endpoint.shutdown_sender().send(true).is_ok());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -59,3 +59,95 @@ impl std::fmt::Debug for HandlerRegistry {
|
|||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use alknet_core::auth::AuthContext;
|
||||||
|
use alknet_core::types::{Connection, HandlerError};
|
||||||
|
use async_trait::async_trait;
|
||||||
|
|
||||||
|
struct DummyHandler {
|
||||||
|
alpn: &'static [u8],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl ProtocolHandler for DummyHandler {
|
||||||
|
fn alpn(&self) -> &'static [u8] {
|
||||||
|
self.alpn
|
||||||
|
}
|
||||||
|
async fn handle(
|
||||||
|
&self,
|
||||||
|
_connection: Connection,
|
||||||
|
_auth: &AuthContext,
|
||||||
|
) -> Result<(), HandlerError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_handler(alpn: &'static [u8]) -> Arc<dyn ProtocolHandler> {
|
||||||
|
Arc::new(DummyHandler { alpn })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn handler_registry_new_is_empty() {
|
||||||
|
let reg = HandlerRegistry::new();
|
||||||
|
assert!(reg.alpn_strings().is_empty());
|
||||||
|
assert!(reg.get(b"alknet/test").is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn handler_registry_register_then_get() {
|
||||||
|
let mut reg = HandlerRegistry::new();
|
||||||
|
reg.register(make_handler(b"alknet/test"));
|
||||||
|
assert_eq!(reg.alpn_strings(), vec![b"alknet/test".to_vec()]);
|
||||||
|
assert!(reg.get(b"alknet/test").is_some());
|
||||||
|
assert!(reg.get(b"alknet/other").is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn handler_registry_multiple_alpns() {
|
||||||
|
let mut reg = HandlerRegistry::new();
|
||||||
|
reg.register(make_handler(b"alknet/ssh"));
|
||||||
|
reg.register(make_handler(b"alknet/call"));
|
||||||
|
let mut alpns = reg
|
||||||
|
.alpn_strings()
|
||||||
|
.into_iter()
|
||||||
|
.map(|a| String::from_utf8(a).unwrap())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
alpns.sort();
|
||||||
|
assert_eq!(alpns, vec!["alknet/call", "alknet/ssh"]);
|
||||||
|
assert!(reg.get(b"alknet/ssh").is_some());
|
||||||
|
assert!(reg.get(b"alknet/call").is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "ALPN already registered")]
|
||||||
|
fn handler_registry_register_panics_on_duplicate() {
|
||||||
|
let mut reg = HandlerRegistry::new();
|
||||||
|
reg.register(make_handler(b"alknet/test"));
|
||||||
|
reg.register(make_handler(b"alknet/test"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn handler_registry_debug_lists_alpns() {
|
||||||
|
let mut reg = HandlerRegistry::new();
|
||||||
|
reg.register(make_handler(b"alknet/test"));
|
||||||
|
let s = format!("{:?}", reg);
|
||||||
|
assert!(s.contains("alknet/test"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn handler_registry_default_is_empty() {
|
||||||
|
let reg = HandlerRegistry::default();
|
||||||
|
assert!(reg.alpn_strings().is_empty());
|
||||||
|
assert!(reg.get(b"alknet/test").is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn handler_registry_debug_lists_alpns_via_default() {
|
||||||
|
let reg = HandlerRegistry::default();
|
||||||
|
let s = format!("{reg:?}");
|
||||||
|
assert!(s.contains("HandlerRegistry"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
id: endpoint/accept-iroh
|
id: endpoint/accept-iroh
|
||||||
name: Implement iroh accept loop and extractors in alknet-endpoint
|
name: Implement iroh accept loop and extractors in alknet-endpoint
|
||||||
status: pending
|
status: completed
|
||||||
depends_on: [endpoint/dispatch]
|
depends_on: [endpoint/dispatch]
|
||||||
scope: narrow
|
scope: narrow
|
||||||
risk: low
|
risk: low
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
id: endpoint/accept-quinn
|
id: endpoint/accept-quinn
|
||||||
name: Implement quinn accept loop and extractors in alknet-endpoint
|
name: Implement quinn accept loop and extractors in alknet-endpoint
|
||||||
status: pending
|
status: completed
|
||||||
depends_on: [endpoint/dispatch]
|
depends_on: [endpoint/dispatch]
|
||||||
scope: narrow
|
scope: narrow
|
||||||
risk: low
|
risk: low
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
id: endpoint/accept-tcp-tls
|
id: endpoint/accept-tcp-tls
|
||||||
name: Implement TCP+TLS accept loop and extractors in alknet-endpoint (new code)
|
name: Implement TCP+TLS accept loop and extractors in alknet-endpoint (new code)
|
||||||
status: pending
|
status: completed
|
||||||
depends_on: [endpoint/dispatch]
|
depends_on: [endpoint/dispatch]
|
||||||
scope: narrow
|
scope: narrow
|
||||||
risk: medium
|
risk: medium
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
id: endpoint/crate-init
|
id: endpoint/crate-init
|
||||||
name: Initialize alknet-endpoint crate with Cargo.toml, dependencies, and module skeleton
|
name: Initialize alknet-endpoint crate with Cargo.toml, dependencies, and module skeleton
|
||||||
status: pending
|
status: completed
|
||||||
depends_on: [tls/review-tls]
|
depends_on: [tls/review-tls]
|
||||||
scope: moderate
|
scope: moderate
|
||||||
risk: low
|
risk: low
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
id: endpoint/dispatch
|
id: endpoint/dispatch
|
||||||
name: Implement public dispatch, build_auth_context, and ACME guard
|
name: Implement public dispatch, build_auth_context, and ACME guard
|
||||||
status: pending
|
status: completed
|
||||||
depends_on: [endpoint/endpoint-core]
|
depends_on: [endpoint/endpoint-core]
|
||||||
scope: narrow
|
scope: narrow
|
||||||
risk: low
|
risk: low
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
id: endpoint/endpoint-core
|
id: endpoint/endpoint-core
|
||||||
name: Implement AlknetEndpoint struct, new, builder methods, run, and shutdown
|
name: Implement AlknetEndpoint struct, new, builder methods, run, and shutdown
|
||||||
status: pending
|
status: completed
|
||||||
depends_on: [endpoint/registry]
|
depends_on: [endpoint/registry]
|
||||||
scope: moderate
|
scope: moderate
|
||||||
risk: medium
|
risk: medium
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
id: endpoint/registry
|
id: endpoint/registry
|
||||||
name: Extract HandlerRegistry from alknet-core/endpoint.rs into alknet-endpoint
|
name: Extract HandlerRegistry from alknet-core/endpoint.rs into alknet-endpoint
|
||||||
status: pending
|
status: completed
|
||||||
depends_on: [endpoint/crate-init]
|
depends_on: [endpoint/crate-init]
|
||||||
scope: narrow
|
scope: narrow
|
||||||
risk: low
|
risk: low
|
||||||
|
|||||||
Reference in new issue
Block a user