#![cfg(feature = "discovery-etcd")]
use rs_zero::discovery::{Discovery, InstanceEndpoint, ServiceInstance};
use rs_zero::discovery_etcd::{
BackoffConfig, EtcdClientFactory, EtcdDiscoveryConfig, EtcdDiscoveryError, EtcdRegistry,
decode_instance, encode_instance, instance_key, service_prefix, split_instance_key,
};
#[test]
fn etcd_codec_keys_and_config_validate_without_external_service() {
let instance = ServiceInstance::new(
"api",
"api-1",
InstanceEndpoint::new("127.0.0.1", 8080).expect("endpoint"),
);
let encoded = encode_instance(&instance).expect("encode");
assert_eq!(decode_instance(&encoded).expect("decode"), instance);
let config = EtcdDiscoveryConfig::default();
assert_eq!(instance_key(&config, "api", "api-1"), "/rs-zero/api/api-1");
assert_eq!(service_prefix(&config, "api"), "/rs-zero/api/");
let parsed = split_instance_key(&config, "/rs-zero/api/api-1")
.expect("split")
.expect("key parts");
assert_eq!(parsed.service, "api");
assert_eq!(parsed.id, "api-1");
let error = EtcdClientFactory::new(EtcdDiscoveryConfig {
endpoints: Vec::new(),
..EtcdDiscoveryConfig::default()
})
.expect_err("missing endpoint");
assert!(matches!(error, EtcdDiscoveryError::MissingEndpoint));
}
#[tokio::test]
async fn disconnected_registry_fails_explicitly_without_memory_fallback() {
let registry = EtcdRegistry::new(EtcdDiscoveryConfig::default());
let error = registry.discover("api").await.expect_err("not connected");
assert!(error.to_string().contains("etcd"));
assert!(error.to_string().contains("connect"));
}
#[test]
fn backoff_is_capped_and_uses_first_attempt_as_initial_delay() {
let config = BackoffConfig::default();
assert_eq!(config.delay_for_attempt(0), config.initial);
assert!(config.delay_for_attempt(10) <= config.max);
}