use super::*;
use otel_arrow_dfe_config::ExtensionId;
use std::any::{Any, TypeId};
use std::collections::{HashMap, HashSet};
trait TestCapLocal {
fn value(&self) -> &str;
}
trait TestCapShared: Send + Sync {
fn value(&self) -> &str;
}
struct TestCap;
impl super::super::private::Sealed for TestCap {}
impl super::super::ExtensionCapability for TestCap {
const NAME: &'static str = "test_cap";
type Local = dyn TestCapLocal;
type Shared = dyn TestCapShared;
fn wrap_shared_as_local(shared: Box<Self::Shared>) -> Box<Self::Local> {
struct Adapter(Box<dyn TestCapShared>);
impl TestCapLocal for Adapter {
fn value(&self) -> &str {
self.0.value()
}
}
Box::new(Adapter(shared))
}
}
#[allow(unsafe_code)]
#[linkme::distributed_slice(super::super::KNOWN_CAPABILITIES)]
#[linkme(crate = linkme)]
static _TEST_CAP: super::super::KnownCapability = super::super::KnownCapability {
name: "test_cap",
description: "Test capability for unit tests",
type_id: || TypeId::of::<TestCap>(),
};
impl TestCap {
fn shared_entry<E>(
extension_id: ExtensionId,
factory: crate::capability::SharedInstanceFactory,
) -> SharedCapabilityEntry
where
E: TestCapShared + 'static,
{
let produce = move || -> Box<dyn Any + Send> {
let erased = factory.produce();
let concrete: Box<E> = erased
.downcast()
.expect("instance_factory produced wrong type");
let shared: Box<dyn TestCapShared> = concrete;
Box::new(shared) as Box<dyn Any + Send>
};
let adapt_as_local: fn(Box<dyn Any + Send>) -> Box<dyn Any> = |erased| {
let shared: Box<Box<dyn TestCapShared>> = erased.downcast().expect("envelope");
let boxed_local =
<TestCap as super::super::ExtensionCapability>::wrap_shared_as_local(*shared);
Box::new(boxed_local) as Box<dyn Any>
};
SharedCapabilityEntry::new(extension_id, produce, adapt_as_local)
}
fn local_entry<E>(
extension_id: ExtensionId,
factory: crate::capability::LocalInstanceFactory,
) -> LocalCapabilityEntry
where
E: TestCapLocal + 'static,
{
let produce = move || -> Box<dyn Any> {
let erased = factory.produce();
let concrete: Box<E> = erased
.downcast()
.expect("instance_factory produced wrong type");
let local: Box<dyn TestCapLocal> = concrete;
Box::new(local) as Box<dyn Any>
};
LocalCapabilityEntry::new(extension_id, produce)
}
}
#[derive(Clone)]
struct SharedImpl(&'static str);
impl TestCapShared for SharedImpl {
fn value(&self) -> &str {
self.0
}
}
#[derive(Clone)]
struct LocalImpl(&'static str);
impl TestCapLocal for LocalImpl {
fn value(&self) -> &str {
self.0
}
}
fn shared_instance_factory(val: &'static str) -> crate::capability::SharedInstanceFactory {
crate::capability::SharedInstanceFactory::new(move || {
Box::new(SharedImpl(val)) as Box<dyn Any + Send>
})
}
fn local_instance_factory(val: &'static str) -> crate::capability::LocalInstanceFactory {
crate::capability::LocalInstanceFactory::new(move || Box::new(LocalImpl(val)) as Box<dyn Any>)
}
fn register_shared(registry: &mut CapabilityRegistry, ext_id: &'static str, val: &'static str) {
let ext_id: ExtensionId = ext_id.into();
registry
.register_shared(
TypeId::of::<TestCap>(),
TestCap::shared_entry::<SharedImpl>(ext_id, shared_instance_factory(val)),
)
.unwrap();
}
fn register_local(registry: &mut CapabilityRegistry, ext_id: &'static str, val: &'static str) {
let ext_id: ExtensionId = ext_id.into();
registry
.register_local(
TypeId::of::<TestCap>(),
TestCap::local_entry::<LocalImpl>(ext_id, local_instance_factory(val)),
)
.unwrap();
}
fn bindings(
cap: &'static str,
ext: &'static str,
) -> HashMap<otel_arrow_dfe_config::CapabilityId, ExtensionId> {
let mut m = HashMap::new();
let _ = m.insert(cap.into(), ext.into());
m
}
fn known_exts(names: &[&'static str]) -> HashSet<ExtensionId> {
names.iter().map(|n| (*n).into()).collect()
}
#[test]
fn test_registry_register_and_get() {
let mut reg = CapabilityRegistry::new();
register_shared(&mut reg, "ext-a", "hello");
assert!(reg.get_shared(&TypeId::of::<TestCap>(), "ext-a").is_some());
assert!(reg.get_shared(&TypeId::of::<TestCap>(), "ext-b").is_none());
assert!(reg.get_local(&TypeId::of::<TestCap>(), "ext-a").is_none());
}
#[test]
fn test_resolve_bindings_shared_only() {
let mut reg = CapabilityRegistry::new();
register_shared(&mut reg, "ext-a", "shared-val");
let mut tracker = ConsumedTracker::new();
let caps_shared = resolve_bindings(
&bindings("test_cap", "ext-a"),
®,
&known_exts(&["ext-a"]),
&mut tracker,
)
.unwrap();
let shared = caps_shared.require_shared::<TestCap>().unwrap();
assert_eq!(shared.value(), "shared-val");
let caps_local = resolve_bindings(
&bindings("test_cap", "ext-a"),
®,
&known_exts(&["ext-a"]),
&mut tracker,
)
.unwrap();
let local = caps_local.require_local::<TestCap>().unwrap();
assert_eq!(local.value(), "shared-val");
}
#[test]
fn test_resolve_bindings_local_only() {
let mut reg = CapabilityRegistry::new();
register_local(&mut reg, "ext-a", "local-val");
let mut tracker = ConsumedTracker::new();
let caps = resolve_bindings(
&bindings("test_cap", "ext-a"),
®,
&known_exts(&["ext-a"]),
&mut tracker,
)
.unwrap();
let local = caps.require_local::<TestCap>().unwrap();
assert_eq!(local.value(), "local-val");
assert!(caps.require_shared::<TestCap>().is_err());
}
#[test]
fn test_resolve_bindings_step1_unknown_extension() {
let reg = CapabilityRegistry::new();
let mut tracker = ConsumedTracker::new();
let result = resolve_bindings(
&bindings("test_cap", "nonexistent"),
®,
&known_exts(&["ext-a"]),
&mut tracker,
);
assert!(result.is_err());
let msg = format!("{}", result.err().unwrap());
assert!(msg.contains("nonexistent"), "error: {msg}");
}
#[test]
fn test_resolve_bindings_step2_unknown_capability() {
let reg = CapabilityRegistry::new();
let mut tracker = ConsumedTracker::new();
let result = resolve_bindings(
&bindings("totally_unknown_cap", "ext-a"),
®,
&known_exts(&["ext-a"]),
&mut tracker,
);
assert!(result.is_err());
let msg = format!("{}", result.err().unwrap());
assert!(msg.contains("unknown capability"), "error: {msg}");
}
#[test]
fn test_resolve_bindings_step3_not_provided() {
let reg = CapabilityRegistry::new();
let mut tracker = ConsumedTracker::new();
let result = resolve_bindings(
&bindings("test_cap", "ext-a"),
®,
&known_exts(&["ext-a"]),
&mut tracker,
);
assert!(result.is_err());
let msg = format!("{}", result.err().unwrap());
assert!(msg.contains("no loaded extension provides"), "error: {msg}");
}
#[test]
fn test_resolve_bindings_step4_wrong_extension() {
let mut reg = CapabilityRegistry::new();
register_shared(&mut reg, "ext-b", "val");
let mut tracker = ConsumedTracker::new();
let result = resolve_bindings(
&bindings("test_cap", "ext-a"),
®,
&known_exts(&["ext-a", "ext-b"]),
&mut tracker,
);
assert!(result.is_err());
let msg = format!("{}", result.err().unwrap());
assert!(msg.contains("does not provide"), "error: {msg}");
}
#[test]
fn test_consumed_tracking_shared() {
let mut reg = CapabilityRegistry::new();
register_shared(&mut reg, "ext-a", "val");
let mut tracker = ConsumedTracker::new();
let caps = resolve_bindings(
&bindings("test_cap", "ext-a"),
®,
&known_exts(&["ext-a"]),
&mut tracker,
)
.unwrap();
assert_eq!(tracker.unconsumed_shared().len(), 1);
let _ = caps.require_shared::<TestCap>().unwrap();
assert!(tracker.unconsumed_shared().is_empty());
}
#[test]
fn test_consumed_tracking_local_marks_shared_via_adapter() {
let mut reg = CapabilityRegistry::new();
register_shared(&mut reg, "ext-a", "val");
let mut tracker = ConsumedTracker::new();
let caps = resolve_bindings(
&bindings("test_cap", "ext-a"),
®,
&known_exts(&["ext-a"]),
&mut tracker,
)
.unwrap();
let _ = caps.require_local::<TestCap>().unwrap();
assert!(tracker.unconsumed_local().is_empty());
assert!(
tracker.unconsumed_shared().is_empty(),
"consuming SharedAsLocal adapter must mark shared variant consumed",
);
}
#[test]
fn test_unconsumed_tracking() {
let mut reg = CapabilityRegistry::new();
register_shared(&mut reg, "ext-a", "val");
let mut tracker = ConsumedTracker::new();
let _caps = resolve_bindings(
&bindings("test_cap", "ext-a"),
®,
&known_exts(&["ext-a"]),
&mut tracker,
)
.unwrap();
let unconsumed = tracker.unconsumed_shared();
assert_eq!(unconsumed.len(), 1);
assert_eq!(unconsumed[0].0.as_ref(), "ext-a");
assert_eq!(unconsumed[0].1, "test_cap");
}
#[test]
fn test_optional_returns_none_when_not_bound() {
let caps = Capabilities::empty();
assert!(caps.optional_local::<TestCap>().unwrap().is_none());
assert!(caps.optional_shared::<TestCap>().unwrap().is_none());
}
#[test]
fn test_optional_shared_rejects_local_only_binding() {
let mut reg = CapabilityRegistry::new();
register_local(&mut reg, "ext-a", "local-val");
let mut tracker = ConsumedTracker::new();
let caps = resolve_bindings(
&bindings("test_cap", "ext-a"),
®,
&known_exts(&["ext-a"]),
&mut tracker,
)
.unwrap();
let error = match caps.optional_shared::<TestCap>() {
Err(error) => error,
Ok(_) => panic!("expected execution model mismatch"),
};
match error {
Error::CapabilityExecutionModelMismatch {
capability,
extension,
requested_execution_model,
available_execution_model,
} => {
assert_eq!(capability, "test_cap");
assert_eq!(extension.as_ref(), "ext-a");
assert_eq!(requested_execution_model, "shared");
assert_eq!(available_execution_model, "local");
}
other => panic!("expected execution model mismatch, got {other}"),
}
}
#[test]
fn test_require_shared_rejects_local_only_binding() {
let mut reg = CapabilityRegistry::new();
register_local(&mut reg, "ext-a", "local-val");
let mut tracker = ConsumedTracker::new();
let caps = resolve_bindings(
&bindings("test_cap", "ext-a"),
®,
&known_exts(&["ext-a"]),
&mut tracker,
)
.unwrap();
let error = match caps.require_shared::<TestCap>() {
Err(error) => error,
Ok(_) => panic!("expected execution model mismatch"),
};
assert!(matches!(
error,
Error::CapabilityExecutionModelMismatch {
requested_execution_model: "shared",
available_execution_model: "local",
..
}
));
}
#[test]
fn test_optional_local_adapts_shared_only_binding() {
let mut reg = CapabilityRegistry::new();
register_shared(&mut reg, "ext-a", "shared-val");
let mut tracker = ConsumedTracker::new();
let caps = resolve_bindings(
&bindings("test_cap", "ext-a"),
®,
&known_exts(&["ext-a"]),
&mut tracker,
)
.unwrap();
let local = caps
.optional_local::<TestCap>()
.unwrap()
.expect("shared binding should adapt to local");
assert_eq!(local.value(), "shared-val");
}
#[test]
fn test_extension_capabilities_shared_only() {
let ec = super::super::ExtensionCapabilities {
shared: &["bearer_token_provider"],
local: &[],
register_shared: |_, _, _| Ok(()),
register_local: |_, _, _| Ok(()),
};
assert_eq!(ec.shared, &["bearer_token_provider"]);
assert!(ec.local.is_empty());
}
#[test]
fn test_known_capabilities_contains_test_cap() {
let found = super::super::KNOWN_CAPABILITIES
.iter()
.any(|kc| kc.name == "test_cap");
assert!(found, "test_cap should be in KNOWN_CAPABILITIES");
}
#[test]
fn test_multiple_providers_same_capability() {
let mut reg = CapabilityRegistry::new();
register_shared(&mut reg, "ext-a", "value-a");
register_shared(&mut reg, "ext-b", "value-b");
assert!(reg.get_shared(&TypeId::of::<TestCap>(), "ext-a").is_some());
assert!(reg.get_shared(&TypeId::of::<TestCap>(), "ext-b").is_some());
let mut tracker = ConsumedTracker::new();
let caps_a = resolve_bindings(
&bindings("test_cap", "ext-a"),
®,
&known_exts(&["ext-a", "ext-b"]),
&mut tracker,
)
.unwrap();
let shared_a = caps_a.require_shared::<TestCap>().unwrap();
assert_eq!(shared_a.value(), "value-a");
let mut tracker = ConsumedTracker::new();
let caps_b = resolve_bindings(
&bindings("test_cap", "ext-b"),
®,
&known_exts(&["ext-a", "ext-b"]),
&mut tracker,
)
.unwrap();
let shared_b = caps_b.require_shared::<TestCap>().unwrap();
assert_eq!(shared_b.value(), "value-b");
}
#[test]
fn test_consumed_tracking_persists_across_nodes_local() {
let mut reg = CapabilityRegistry::new();
register_local(&mut reg, "ext-a", "val");
let mut tracker = ConsumedTracker::new();
let caps_a = resolve_bindings(
&bindings("test_cap", "ext-a"),
®,
&known_exts(&["ext-a"]),
&mut tracker,
)
.unwrap();
let _ = caps_a.require_local::<TestCap>().unwrap();
let _caps_b = resolve_bindings(
&bindings("test_cap", "ext-a"),
®,
&known_exts(&["ext-a"]),
&mut tracker,
)
.unwrap();
assert!(
tracker.unconsumed_local().is_empty(),
"unconsumed_local should be empty but got {:?}",
tracker.unconsumed_local()
);
}
#[test]
fn test_consumed_tracking_persists_across_nodes_shared() {
let mut reg = CapabilityRegistry::new();
register_shared(&mut reg, "ext-a", "val");
let mut tracker = ConsumedTracker::new();
let caps_a = resolve_bindings(
&bindings("test_cap", "ext-a"),
®,
&known_exts(&["ext-a"]),
&mut tracker,
)
.unwrap();
let _ = caps_a.require_shared::<TestCap>().unwrap();
let _caps_b = resolve_bindings(
&bindings("test_cap", "ext-a"),
®,
&known_exts(&["ext-a"]),
&mut tracker,
)
.unwrap();
assert!(tracker.unconsumed_shared().is_empty());
}
#[test]
fn test_shared_as_local_builds_new_adapter_per_node() {
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
let counter = Arc::new(AtomicUsize::new(0));
let counter_for_closure = Arc::clone(&counter);
let factory = crate::capability::SharedInstanceFactory::new(move || {
let _ = counter_for_closure.fetch_add(1, Ordering::SeqCst);
Box::new(SharedImpl("val")) as Box<dyn Any + Send>
});
let mut reg = CapabilityRegistry::new();
reg.register_shared(
TypeId::of::<TestCap>(),
TestCap::shared_entry::<SharedImpl>("ext-a".into(), factory),
)
.unwrap();
assert_eq!(counter.load(Ordering::SeqCst), 0);
let mut tracker = ConsumedTracker::new();
let caps_a = resolve_bindings(
&bindings("test_cap", "ext-a"),
®,
&known_exts(&["ext-a"]),
&mut tracker,
)
.unwrap();
let caps_b = resolve_bindings(
&bindings("test_cap", "ext-a"),
®,
&known_exts(&["ext-a"]),
&mut tracker,
)
.unwrap();
assert_eq!(
counter.load(Ordering::SeqCst),
0,
"fallback must not mint at resolve time",
);
let _ = caps_a.require_local::<TestCap>().unwrap();
let _ = caps_b.require_local::<TestCap>().unwrap();
assert_eq!(counter.load(Ordering::SeqCst), 2);
}
#[test]
fn test_register_local_rejects_duplicate() {
let mut reg = CapabilityRegistry::new();
register_local(&mut reg, "ext-a", "v1");
let err = reg
.register_local(
TypeId::of::<TestCap>(),
TestCap::local_entry::<LocalImpl>("ext-a".into(), local_instance_factory("v2")),
)
.unwrap_err();
let msg = format!("{err}");
assert!(msg.contains("duplicate"), "error: {msg}");
assert!(msg.contains("ext-a"), "error: {msg}");
}
#[test]
fn test_register_shared_rejects_duplicate() {
let mut reg = CapabilityRegistry::new();
register_shared(&mut reg, "ext-a", "v1");
let err = reg
.register_shared(
TypeId::of::<TestCap>(),
TestCap::shared_entry::<SharedImpl>("ext-a".into(), shared_instance_factory("v2")),
)
.unwrap_err();
let msg = format!("{err}");
assert!(msg.contains("duplicate"), "error: {msg}");
assert!(msg.contains("ext-a"), "error: {msg}");
}
#[test]
fn test_require_local_second_call_returns_already_consumed() {
let mut reg = CapabilityRegistry::new();
register_local(&mut reg, "ext-a", "val");
let mut tracker = ConsumedTracker::new();
let caps = resolve_bindings(
&bindings("test_cap", "ext-a"),
®,
&known_exts(&["ext-a"]),
&mut tracker,
)
.unwrap();
let _ = caps.require_local::<TestCap>().unwrap();
let err = match caps.require_local::<TestCap>() {
Err(e) => e,
Ok(_) => panic!("expected CapabilityAlreadyConsumed"),
};
assert!(
matches!(err, crate::error::Error::CapabilityAlreadyConsumed { ref capability } if capability == "test_cap"),
"expected CapabilityAlreadyConsumed, got {err:?}"
);
}
#[test]
fn test_require_shared_second_call_returns_already_consumed() {
let mut reg = CapabilityRegistry::new();
register_shared(&mut reg, "ext-a", "val");
let mut tracker = ConsumedTracker::new();
let caps = resolve_bindings(
&bindings("test_cap", "ext-a"),
®,
&known_exts(&["ext-a"]),
&mut tracker,
)
.unwrap();
let _ = caps.require_shared::<TestCap>().unwrap();
let err = match caps.require_shared::<TestCap>() {
Err(e) => e,
Ok(_) => panic!("expected CapabilityAlreadyConsumed"),
};
assert!(
matches!(err, crate::error::Error::CapabilityAlreadyConsumed { ref capability } if capability == "test_cap"),
"expected CapabilityAlreadyConsumed, got {err:?}"
);
}
#[test]
fn test_optional_local_second_call_returns_already_consumed() {
let mut reg = CapabilityRegistry::new();
register_local(&mut reg, "ext-a", "val");
let mut tracker = ConsumedTracker::new();
let caps = resolve_bindings(
&bindings("test_cap", "ext-a"),
®,
&known_exts(&["ext-a"]),
&mut tracker,
)
.unwrap();
let first = caps.optional_local::<TestCap>().unwrap();
assert!(first.is_some());
let err = match caps.optional_local::<TestCap>() {
Err(e) => e,
Ok(_) => panic!("expected CapabilityAlreadyConsumed"),
};
assert!(matches!(
err,
crate::error::Error::CapabilityAlreadyConsumed { .. }
));
}
#[test]
fn test_optional_shared_second_call_returns_already_consumed() {
let mut reg = CapabilityRegistry::new();
register_shared(&mut reg, "ext-a", "val");
let mut tracker = ConsumedTracker::new();
let caps = resolve_bindings(
&bindings("test_cap", "ext-a"),
®,
&known_exts(&["ext-a"]),
&mut tracker,
)
.unwrap();
let first = caps.optional_shared::<TestCap>().unwrap();
assert!(first.is_some());
let err = match caps.optional_shared::<TestCap>() {
Err(e) => e,
Ok(_) => panic!("expected CapabilityAlreadyConsumed"),
};
assert!(matches!(
err,
crate::error::Error::CapabilityAlreadyConsumed { .. }
));
}
#[test]
fn test_fallback_local_and_shared_share_one_shot_guard() {
let mut reg = CapabilityRegistry::new();
register_shared(&mut reg, "ext-a", "val");
let mut tracker = ConsumedTracker::new();
let caps = resolve_bindings(
&bindings("test_cap", "ext-a"),
®,
&known_exts(&["ext-a"]),
&mut tracker,
)
.unwrap();
let local = caps.require_local::<TestCap>().unwrap();
assert_eq!(local.value(), "val");
match caps.require_shared::<TestCap>() {
Err(crate::error::Error::CapabilityAlreadyConsumed { capability }) => {
assert_eq!(capability, "test_cap");
}
Err(other) => panic!("expected CapabilityAlreadyConsumed, got {other:?}"),
Ok(_) => panic!("expected CapabilityAlreadyConsumed after fallback-local claim, got Ok"),
}
let mut tracker = ConsumedTracker::new();
let caps = resolve_bindings(
&bindings("test_cap", "ext-a"),
®,
&known_exts(&["ext-a"]),
&mut tracker,
)
.unwrap();
let shared = caps.require_shared::<TestCap>().unwrap();
assert_eq!(shared.value(), "val");
match caps.require_local::<TestCap>() {
Err(crate::error::Error::CapabilityAlreadyConsumed { capability }) => {
assert_eq!(capability, "test_cap");
}
Err(other) => panic!("expected CapabilityAlreadyConsumed, got {other:?}"),
Ok(_) => panic!("expected CapabilityAlreadyConsumed after native-shared claim, got Ok"),
}
}
#[test]
fn test_end_to_end_shared_only_via_bundle() {
use crate::capability::ExtensionCapabilities;
use crate::config::ExtensionConfig;
use crate::extension::ExtensionWrapper;
use otel_arrow_dfe_config::extension::ExtensionUserConfig;
use std::sync::Arc;
let name: ExtensionId = "azure-auth".into();
let user_config = Arc::new(ExtensionUserConfig::new(
"urn:test:extension:azure".into(),
serde_json::Value::Null,
));
let runtime_config = ExtensionConfig::new("azure-auth");
let bundle = ExtensionWrapper::builder(name.clone(), user_config, &runtime_config)
.passive()
.cloned()
.shared(SharedImpl("token-123"))
.build()
.expect("bundle builds");
let caps = ExtensionCapabilities {
shared: &["test_cap"],
local: &[],
register_shared: |ext_id, factory, registry| {
registry.register_shared(
TypeId::of::<TestCap>(),
TestCap::shared_entry::<SharedImpl>(ext_id, factory),
)
},
register_local: |_, _, _| Ok(()),
};
let mut registry = CapabilityRegistry::new();
bundle
.register_into(Some(&caps), &mut registry)
.expect("register_into");
let mut tracker = ConsumedTracker::new();
let resolved = resolve_bindings(
&bindings("test_cap", "azure-auth"),
®istry,
&known_exts(&["azure-auth"]),
&mut tracker,
)
.expect("resolve");
let shared = resolved
.require_shared::<TestCap>()
.expect("require_shared");
assert_eq!(shared.value(), "token-123");
let resolved2 = resolve_bindings(
&bindings("test_cap", "azure-auth"),
®istry,
&known_exts(&["azure-auth"]),
&mut tracker,
)
.expect("resolve");
let local = resolved2.require_local::<TestCap>().expect("require_local");
assert_eq!(local.value(), "token-123");
}
#[test]
fn test_end_to_end_local_only_via_bundle() {
use crate::capability::ExtensionCapabilities;
use crate::config::ExtensionConfig;
use crate::extension::ExtensionWrapper;
use otel_arrow_dfe_config::extension::ExtensionUserConfig;
use std::sync::Arc;
let name: ExtensionId = "kv".into();
let user_config = Arc::new(ExtensionUserConfig::new(
"urn:test:extension:kv".into(),
serde_json::Value::Null,
));
let runtime_config = ExtensionConfig::new("kv");
let bundle = ExtensionWrapper::builder(name.clone(), user_config, &runtime_config)
.passive()
.cloned()
.local(LocalImpl("kv-value"))
.build()
.expect("bundle builds");
let caps = ExtensionCapabilities {
shared: &[],
local: &["test_cap"],
register_shared: |_, _, _| Ok(()),
register_local: |ext_id, factory, registry| {
registry.register_local(
TypeId::of::<TestCap>(),
TestCap::local_entry::<LocalImpl>(ext_id, factory),
)
},
};
let mut registry = CapabilityRegistry::new();
bundle
.register_into(Some(&caps), &mut registry)
.expect("register_into");
let mut tracker = ConsumedTracker::new();
let resolved = resolve_bindings(
&bindings("test_cap", "kv"),
®istry,
&known_exts(&["kv"]),
&mut tracker,
)
.expect("resolve");
let local = resolved.require_local::<TestCap>().expect("require_local");
assert_eq!(local.value(), "kv-value");
}
#[test]
fn test_end_to_end_shared_constructed_policy_mints_independent_instances() {
use crate::capability::ExtensionCapabilities;
use crate::config::ExtensionConfig;
use crate::extension::ExtensionWrapper;
use otel_arrow_dfe_config::extension::ExtensionUserConfig;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
let name: ExtensionId = "counter".into();
let user_config = Arc::new(ExtensionUserConfig::new(
"urn:test:extension:counter".into(),
serde_json::Value::Null,
));
let runtime_config = ExtensionConfig::new("counter");
#[derive(Clone)]
struct ConstructedImpl(&'static str);
impl TestCapShared for ConstructedImpl {
fn value(&self) -> &str {
self.0
}
}
let counter = Arc::new(AtomicUsize::new(0));
let counter_for_closure = Arc::clone(&counter);
let bundle = ExtensionWrapper::builder(name.clone(), user_config, &runtime_config)
.passive()
.constructed()
.shared::<ConstructedImpl, _>(move || {
let _ = counter_for_closure.fetch_add(1, Ordering::SeqCst);
ConstructedImpl("constructed")
})
.build()
.expect("bundle builds");
let caps = ExtensionCapabilities {
shared: &["test_cap"],
local: &[],
register_shared: |ext_id, factory, registry| {
registry.register_shared(
TypeId::of::<TestCap>(),
TestCap::shared_entry::<ConstructedImpl>(ext_id, factory),
)
},
register_local: |_, _, _| Ok(()),
};
let mut registry = CapabilityRegistry::new();
bundle
.register_into(Some(&caps), &mut registry)
.expect("register_into");
let mut tracker = ConsumedTracker::new();
let resolved_a = resolve_bindings(
&bindings("test_cap", "counter"),
®istry,
&known_exts(&["counter"]),
&mut tracker,
)
.expect("resolve");
let resolved_b = resolve_bindings(
&bindings("test_cap", "counter"),
®istry,
&known_exts(&["counter"]),
&mut tracker,
)
.expect("resolve");
let s1 = resolved_a.require_shared::<TestCap>().unwrap();
let s2 = resolved_b.require_shared::<TestCap>().unwrap();
assert_eq!(s1.value(), "constructed");
assert_eq!(s2.value(), "constructed");
assert_eq!(
counter.load(Ordering::SeqCst),
2,
"constructed factory should have been invoked exactly 2x (one per require_shared consumer)"
);
}
#[test]
fn test_register_into_rejects_metadata_vs_bundle_mismatch() {
use crate::capability::ExtensionCapabilities;
use crate::config::ExtensionConfig;
use crate::extension::ExtensionWrapper;
use otel_arrow_dfe_config::extension::ExtensionUserConfig;
use std::sync::Arc;
let name: ExtensionId = "drifty".into();
let user_config = Arc::new(ExtensionUserConfig::new(
"urn:test:extension:drifty".into(),
serde_json::Value::Null,
));
let runtime_config = ExtensionConfig::new("drifty");
let bundle = ExtensionWrapper::builder(name.clone(), user_config, &runtime_config)
.passive()
.cloned()
.shared(SharedImpl("v"))
.build()
.expect("bundle builds");
let caps = ExtensionCapabilities {
shared: &["test_cap"],
local: &["test_cap"],
register_shared: |ext_id, factory, registry| {
registry.register_shared(
TypeId::of::<TestCap>(),
TestCap::shared_entry::<SharedImpl>(ext_id, factory),
)
},
register_local: |_ext_id, _factory, _registry| Ok(()),
};
let mut registry = CapabilityRegistry::new();
let err = bundle
.register_into(Some(&caps), &mut registry)
.expect_err("register_into must reject metadata-vs-bundle drift");
match err {
Error::InternalError { message } => {
assert!(
message.contains("local") && message.contains("drifty"),
"InternalError message should name the extension and the missing execution model; got: {message}",
);
}
other => panic!("expected InternalError, got {other:?}"),
}
let local_only_name: ExtensionId = "drifty-local".into();
let local_only_user_config = Arc::new(ExtensionUserConfig::new(
"urn:test:extension:drifty-local".into(),
serde_json::Value::Null,
));
let local_only_runtime_config = ExtensionConfig::new("drifty-local");
let bundle = ExtensionWrapper::builder(
local_only_name,
local_only_user_config,
&local_only_runtime_config,
)
.passive()
.cloned()
.local(LocalImpl("v"))
.build()
.expect("bundle builds");
let caps = ExtensionCapabilities {
shared: &["test_cap"],
local: &["test_cap"],
register_shared: |_ext_id, _factory, _registry| Ok(()),
register_local: |ext_id, factory, registry| {
registry.register_local(
TypeId::of::<TestCap>(),
TestCap::local_entry::<LocalImpl>(ext_id, factory),
)
},
};
let err = bundle
.register_into(Some(&caps), &mut registry)
.expect_err("register_into must reject metadata-vs-bundle drift");
match err {
Error::InternalError { message } => {
assert!(
message.contains("shared") && message.contains("drifty-local"),
"InternalError message should name the extension and the missing execution model; got: {message}",
);
}
other => panic!("expected InternalError, got {other:?}"),
}
}
#[test]
fn test_shared_entry_produce_uses_double_box_envelope() {
let factory = shared_instance_factory("envelope-val");
let entry = TestCap::shared_entry::<SharedImpl>("ext-env".into(), factory);
let erased: Box<dyn Any + Send> = (entry.produce)();
let boxed_trait_object: Box<Box<dyn TestCapShared>> = erased
.downcast::<Box<dyn TestCapShared>>()
.expect("shared_entry must emit Box<Box<dyn C::Shared>> erased as Box<dyn Any + Send>");
assert_eq!((*boxed_trait_object).value(), "envelope-val");
}
#[test]
fn test_require_local_unbound_returns_capability_not_bound() {
let reg = CapabilityRegistry::new();
let mut tracker = ConsumedTracker::new();
let caps = resolve_bindings(&HashMap::new(), ®, &known_exts(&[]), &mut tracker).unwrap();
match caps.require_local::<TestCap>() {
Err(Error::CapabilityNotBound {
capability,
execution_model,
}) => {
assert_eq!(capability, "test_cap");
assert_eq!(execution_model, "local");
}
Err(other) => panic!("expected CapabilityNotBound, got {other:?}"),
Ok(_) => panic!("expected CapabilityNotBound, got Ok"),
}
}
#[test]
fn test_require_shared_unbound_returns_capability_not_bound() {
let reg = CapabilityRegistry::new();
let mut tracker = ConsumedTracker::new();
let caps = resolve_bindings(&HashMap::new(), ®, &known_exts(&[]), &mut tracker).unwrap();
match caps.require_shared::<TestCap>() {
Err(Error::CapabilityNotBound {
capability,
execution_model,
}) => {
assert_eq!(capability, "test_cap");
assert_eq!(execution_model, "shared");
}
Err(other) => panic!("expected CapabilityNotBound, got {other:?}"),
Ok(_) => panic!("expected CapabilityNotBound, got Ok"),
}
}
#[test]
fn test_fallback_local_consumption_flips_shared_bucket() {
let mut reg = CapabilityRegistry::new();
register_shared(&mut reg, "ext-only-shared", "val");
let mut tracker = ConsumedTracker::new();
let caps = resolve_bindings(
&bindings("test_cap", "ext-only-shared"),
®,
&known_exts(&["ext-only-shared"]),
&mut tracker,
)
.unwrap();
assert!(
tracker
.unconsumed_shared()
.iter()
.any(|(ext, _)| ext.as_ref() == "ext-only-shared"),
"shared bucket should list ext-only-shared before the fallback claim",
);
assert!(
tracker.unconsumed_local().is_empty(),
"no native local registration was made, so the local bucket must be empty",
);
let _ = caps.require_local::<TestCap>().unwrap();
assert!(
tracker.unconsumed_shared().is_empty(),
"fallback consumption must flip the shared bucket",
);
}
#[test]
fn test_native_dual_local_claim_invalidates_shared_on_same_node() {
let mut reg = CapabilityRegistry::new();
register_local(&mut reg, "ext-a", "local-val");
register_shared(&mut reg, "ext-a", "shared-val");
let mut tracker = ConsumedTracker::new();
let caps = resolve_bindings(
&bindings("test_cap", "ext-a"),
®,
&known_exts(&["ext-a"]),
&mut tracker,
)
.unwrap();
let local = caps.require_local::<TestCap>().unwrap();
assert_eq!(local.value(), "local-val");
match caps.require_shared::<TestCap>() {
Err(crate::error::Error::CapabilityAlreadyConsumed { capability }) => {
assert_eq!(capability, "test_cap");
}
Err(other) => panic!("expected CapabilityAlreadyConsumed, got {other:?}"),
Ok(_) => panic!("expected CapabilityAlreadyConsumed after native-local claim, got Ok"),
}
assert!(matches!(
caps.require_local::<TestCap>(),
Err(crate::error::Error::CapabilityAlreadyConsumed { .. })
));
assert!(
tracker.unconsumed_local().is_empty(),
"native local claim must flip the local bucket",
);
assert_eq!(
tracker.unconsumed_shared().len(),
1,
"native local claim must NOT flip the shared bucket \u{2014} invalidating \
the shared alternative is not the same as consuming it",
);
}
#[test]
fn test_native_dual_shared_claim_invalidates_local_on_same_node() {
let mut reg = CapabilityRegistry::new();
register_local(&mut reg, "ext-a", "local-val");
register_shared(&mut reg, "ext-a", "shared-val");
let mut tracker = ConsumedTracker::new();
let caps = resolve_bindings(
&bindings("test_cap", "ext-a"),
®,
&known_exts(&["ext-a"]),
&mut tracker,
)
.unwrap();
let shared = caps.require_shared::<TestCap>().unwrap();
assert_eq!(shared.value(), "shared-val");
match caps.require_local::<TestCap>() {
Err(crate::error::Error::CapabilityAlreadyConsumed { capability }) => {
assert_eq!(capability, "test_cap");
}
Err(other) => panic!("expected CapabilityAlreadyConsumed, got {other:?}"),
Ok(_) => panic!("expected CapabilityAlreadyConsumed after native-shared claim, got Ok"),
}
assert!(matches!(
caps.require_shared::<TestCap>(),
Err(crate::error::Error::CapabilityAlreadyConsumed { .. })
));
assert!(
tracker.unconsumed_shared().is_empty(),
"native shared claim must flip the shared bucket",
);
assert_eq!(
tracker.unconsumed_local().len(),
1,
"native shared claim must NOT flip the local bucket \u{2014} invalidating \
the local alternative is not the same as consuming it",
);
}
#[test]
fn test_register_into_background_no_op() {
use crate::config::ExtensionConfig;
use crate::control::ExtensionControlMsg;
use crate::error::Error as EngineError;
use crate::extension::ExtensionWrapper;
use crate::shared::extension as shared_ext;
use crate::terminal_state::TerminalState;
use async_trait::async_trait;
use otel_arrow_dfe_config::extension::ExtensionUserConfig;
use std::sync::Arc;
#[derive(Clone)]
struct BgTask;
#[async_trait]
impl shared_ext::Extension for BgTask {
async fn start(
self: Box<Self>,
mut ctrl: shared_ext::ControlChannel,
_eh: crate::extension::EffectHandler,
) -> Result<TerminalState, EngineError> {
loop {
if let ExtensionControlMsg::Shutdown { .. } = ctrl.recv().await? {
break;
}
}
Ok(TerminalState::default())
}
}
let name: ExtensionId = "bg".into();
let user_config = Arc::new(ExtensionUserConfig::new(
"urn:test:extension:bg".into(),
serde_json::Value::Null,
));
let runtime_config = ExtensionConfig::new("bg");
let bundle = ExtensionWrapper::builder(name.clone(), user_config, &runtime_config)
.background()
.shared(BgTask)
.build()
.expect("background bundle builds");
let mut registry = CapabilityRegistry::new();
bundle
.register_into(None, &mut registry)
.expect("background register_into is a no-op");
assert!(
registry
.get_shared(&TypeId::of::<TestCap>(), "bg")
.is_none()
);
assert!(registry.get_local(&TypeId::of::<TestCap>(), "bg").is_none());
let tracker = ConsumedTracker::new();
assert!(tracker.unconsumed_shared().is_empty());
assert!(tracker.unconsumed_local().is_empty());
}
#[test]
fn test_resolve_bindings_background_not_a_provider() {
let mut reg = CapabilityRegistry::new();
register_shared(&mut reg, "provider-ext", "v");
let mut tracker = ConsumedTracker::new();
let result = resolve_bindings(
&bindings("test_cap", "bg-ext"),
®,
&known_exts(&["bg-ext", "provider-ext"]),
&mut tracker,
);
let err = result.expect_err("must reject binding to Background extension");
let msg = format!("{err}");
assert!(
msg.contains("does not provide"),
"expected Step-4 'does not provide' error; got: {msg}",
);
}
#[test]
fn test_local_entry_produce_uses_double_box_envelope() {
let factory = local_instance_factory("envelope-val");
let entry = TestCap::local_entry::<LocalImpl>("ext-env".into(), factory);
let erased: Box<dyn Any> = (entry.produce)();
let boxed_trait_object: Box<Box<dyn TestCapLocal>> = erased
.downcast::<Box<dyn TestCapLocal>>()
.expect("local_entry must emit Box<Box<dyn C::Local>> erased as Box<dyn Any>");
assert_eq!((*boxed_trait_object).value(), "envelope-val");
}
trait MutSelfCapLocal {
fn bump(&mut self) -> u32;
}
trait MutSelfCapShared: Send + Sync {
fn bump(&mut self) -> u32;
}
struct MutSelfCap;
impl super::super::private::Sealed for MutSelfCap {}
impl super::super::ExtensionCapability for MutSelfCap {
const NAME: &'static str = "mut_self_cap";
type Local = dyn MutSelfCapLocal;
type Shared = dyn MutSelfCapShared;
fn wrap_shared_as_local(shared: Box<Self::Shared>) -> Box<Self::Local> {
struct Adapter(Box<dyn MutSelfCapShared>);
impl MutSelfCapLocal for Adapter {
fn bump(&mut self) -> u32 {
self.0.bump()
}
}
Box::new(Adapter(shared))
}
}
#[allow(unsafe_code)]
#[linkme::distributed_slice(super::super::KNOWN_CAPABILITIES)]
#[linkme(crate = linkme)]
static _MUT_SELF_CAP: super::super::KnownCapability = super::super::KnownCapability {
name: "mut_self_cap",
description: "Test capability with &mut self method",
type_id: || TypeId::of::<MutSelfCap>(),
};
impl MutSelfCap {
fn shared_entry<E>(
extension_id: ExtensionId,
factory: crate::capability::SharedInstanceFactory,
) -> SharedCapabilityEntry
where
E: MutSelfCapShared + 'static,
{
let produce = move || -> Box<dyn Any + Send> {
let erased = factory.produce();
let concrete: Box<E> = erased.downcast().expect("instance factory");
let shared: Box<dyn MutSelfCapShared> = concrete;
Box::new(shared) as Box<dyn Any + Send>
};
let adapt_as_local: fn(Box<dyn Any + Send>) -> Box<dyn Any> = |erased| {
let shared: Box<Box<dyn MutSelfCapShared>> = erased.downcast().expect("envelope");
let boxed_local =
<MutSelfCap as super::super::ExtensionCapability>::wrap_shared_as_local(*shared);
Box::new(boxed_local) as Box<dyn Any>
};
SharedCapabilityEntry::new(extension_id, produce, adapt_as_local)
}
fn local_entry<E>(
extension_id: ExtensionId,
factory: crate::capability::LocalInstanceFactory,
) -> LocalCapabilityEntry
where
E: MutSelfCapLocal + 'static,
{
let produce = move || -> Box<dyn Any> {
let erased = factory.produce();
let concrete: Box<E> = erased.downcast().expect("instance factory");
let local: Box<dyn MutSelfCapLocal> = concrete;
Box::new(local) as Box<dyn Any>
};
LocalCapabilityEntry::new(extension_id, produce)
}
}
#[derive(Clone)]
struct MutSelfImpl {
counter: u32,
}
impl MutSelfCapLocal for MutSelfImpl {
fn bump(&mut self) -> u32 {
self.counter += 1;
self.counter
}
}
impl MutSelfCapShared for MutSelfImpl {
fn bump(&mut self) -> u32 {
self.counter += 1;
self.counter
}
}
#[test]
fn test_local_capability_supports_mut_self_native() {
let mut reg = CapabilityRegistry::new();
let factory = crate::capability::LocalInstanceFactory::new(|| {
Box::new(MutSelfImpl { counter: 0 }) as Box<dyn Any>
});
reg.register_local(
TypeId::of::<MutSelfCap>(),
MutSelfCap::local_entry::<MutSelfImpl>("ext".into(), factory),
)
.unwrap();
let mut tracker = ConsumedTracker::new();
let caps = resolve_bindings(
&bindings("mut_self_cap", "ext"),
®,
&known_exts(&["ext"]),
&mut tracker,
)
.unwrap();
let mut handle = caps.require_local::<MutSelfCap>().unwrap();
assert_eq!(handle.bump(), 1);
assert_eq!(handle.bump(), 2);
assert_eq!(handle.bump(), 3);
}
#[test]
fn test_local_capability_supports_mut_self_via_shared_as_local() {
let mut reg = CapabilityRegistry::new();
let factory = crate::capability::SharedInstanceFactory::new(|| {
Box::new(MutSelfImpl { counter: 0 }) as Box<dyn Any + Send>
});
reg.register_shared(
TypeId::of::<MutSelfCap>(),
MutSelfCap::shared_entry::<MutSelfImpl>("ext".into(), factory),
)
.unwrap();
let mut tracker = ConsumedTracker::new();
let caps = resolve_bindings(
&bindings("mut_self_cap", "ext"),
®,
&known_exts(&["ext"]),
&mut tracker,
)
.unwrap();
let mut handle = caps.require_local::<MutSelfCap>().unwrap();
assert_eq!(handle.bump(), 1);
assert_eq!(handle.bump(), 2);
}
#[test]
fn test_passive_cloned_local_hands_out_independent_clones() {
let mut reg = CapabilityRegistry::new();
let prototype = MutSelfImpl { counter: 0 };
let factory = crate::capability::LocalInstanceFactory::new(move || {
Box::new(prototype.clone()) as Box<dyn Any>
});
reg.register_local(
TypeId::of::<MutSelfCap>(),
MutSelfCap::local_entry::<MutSelfImpl>("ext".into(), factory),
)
.unwrap();
let mut tracker = ConsumedTracker::new();
let caps_a = resolve_bindings(
&bindings("mut_self_cap", "ext"),
®,
&known_exts(&["ext"]),
&mut tracker,
)
.unwrap();
let caps_b = resolve_bindings(
&bindings("mut_self_cap", "ext"),
®,
&known_exts(&["ext"]),
&mut tracker,
)
.unwrap();
let mut handle_a = caps_a.require_local::<MutSelfCap>().unwrap();
let mut handle_b = caps_b.require_local::<MutSelfCap>().unwrap();
assert_eq!(handle_a.bump(), 1);
assert_eq!(handle_a.bump(), 2);
assert_eq!(handle_b.bump(), 1, "consumer B must start from prototype");
assert_eq!(handle_a.bump(), 3, "consumer A must keep its own counter");
assert_eq!(handle_b.bump(), 2, "consumer B must keep its own counter");
}
#[test]
fn test_tracker_consumed_local_any_capability_consumed() {
let mut tracker = ConsumedTracker::new();
let ext: ExtensionId = "multi-cap-ext".into();
let cap_a =
tracker.ensure_local_consumer_slot(TypeId::of::<TestCap>(), "test_cap", ext.clone());
let _cap_b =
tracker.ensure_local_consumer_slot(TypeId::of::<MutSelfCap>(), "mut_self_cap", ext.clone());
cap_a.set(true);
let unconsumed: HashSet<ExtensionId> = tracker
.unconsumed_local()
.into_iter()
.map(|(e, _)| e)
.collect();
assert!(
unconsumed.contains(&ext),
"cap_b is still unbound, so ext appears under the per-capability unconsumed view"
);
let consumed = tracker.consumed_local();
assert!(
consumed.contains(&ext),
"consumed_local must report ext because cap_a was consumed"
);
}
#[test]
fn test_tracker_consumed_shared_any_capability_consumed() {
let mut tracker = ConsumedTracker::new();
let ext: ExtensionId = "multi-cap-ext".into();
let _cap_a =
tracker.ensure_shared_consumer_slot(TypeId::of::<TestCap>(), "test_cap", ext.clone());
let cap_b = tracker.ensure_shared_consumer_slot(
TypeId::of::<MutSelfCap>(),
"mut_self_cap",
ext.clone(),
);
cap_b.set(true);
let consumed = tracker.consumed_shared();
assert!(
consumed.contains(&ext),
"consumed_shared must report ext because cap_b was consumed"
);
}
#[test]
fn test_tracker_consumed_empty_when_no_capability_consumed() {
let mut tracker = ConsumedTracker::new();
let ext: ExtensionId = "unused-ext".into();
let _ = tracker.ensure_local_consumer_slot(TypeId::of::<TestCap>(), "test_cap", ext.clone());
let _ = tracker.ensure_shared_consumer_slot(TypeId::of::<MutSelfCap>(), "mut_self_cap", ext);
assert!(tracker.consumed_local().is_empty());
assert!(tracker.consumed_shared().is_empty());
}