use config::*;
use std::mem::take;
use std::sync::{
atomic::{AtomicU8, Ordering},
Arc, Mutex,
};
use tokens::{ChangeToken, SharedChangeToken, SingleChangeToken};
#[derive(Default)]
struct Trigger {
token: Mutex<SharedChangeToken<SingleChangeToken>>,
}
impl Trigger {
fn fire(&self) {
let token = take(&mut *self.token.lock().unwrap());
token.notify();
}
}
struct ReloadableProvider {
counter: AtomicU8,
trigger: Arc<Trigger>,
}
impl ReloadableProvider {
fn new(trigger: Arc<Trigger>) -> Self {
Self {
counter: AtomicU8::new(1),
trigger,
}
}
}
impl Default for ReloadableProvider {
fn default() -> Self {
Self {
counter: AtomicU8::new(1),
trigger: Default::default(),
}
}
}
impl Provider for ReloadableProvider {
fn name(&self) -> &str {
"Test"
}
fn load(&self, settings: &mut Settings) -> Result {
settings.insert("Test", self.counter.fetch_add(1, Ordering::Relaxed).to_string());
Ok(())
}
fn reload_token(&self) -> Box<dyn ChangeToken> {
Box::new((*self.trigger.token.lock().unwrap()).clone())
}
}
#[test]
fn load_should_reload_providers() {
let mut builder = config::builder();
builder.add(ReloadableProvider::default());
let mut config = builder.build().unwrap();
assert_eq!(config.get("Test"), Some("1"));
config = builder.build().unwrap();
assert_eq!(config.get("Test"), Some("2"));
}
#[test]
fn reload_token_should_indicate_change_after_provider_change() {
let trigger = Arc::new(Trigger::default());
let data = Arc::<AtomicU8>::default();
let mut builder = config::builder();
builder.add(ReloadableProvider::new(trigger.clone()));
let config = builder.build().unwrap();
let _registration = config.change_token().register(
Box::new(|state| {
state
.unwrap()
.downcast_ref::<AtomicU8>()
.unwrap()
.store(1, Ordering::SeqCst)
}),
Some(data.clone()),
);
trigger.fire();
assert_eq!(data.load(Ordering::SeqCst), 1);
}