mirror of
https://github.com/telemt/telemt.git
synced 2026-11-01 21:31:58 +03:00
Rustfmt
This commit is contained in:
@@ -48,6 +48,7 @@ async fn decoy_dns_watcher_publishes_dns_only_changes_once() {
|
||||
None,
|
||||
&mut state,
|
||||
None,
|
||||
false,
|
||||
)
|
||||
.unwrap();
|
||||
assert!(config_rx.has_changed().unwrap());
|
||||
@@ -62,13 +63,14 @@ async fn decoy_dns_watcher_publishes_dns_only_changes_once() {
|
||||
None,
|
||||
&mut state,
|
||||
None,
|
||||
false,
|
||||
)
|
||||
.unwrap();
|
||||
assert!(!config_rx.has_changed().unwrap());
|
||||
assert!(Arc::ptr_eq(&published, &config_rx.borrow()));
|
||||
|
||||
preparation::reload(
|
||||
&path, &config_tx, &log_tx, None, None, &mut state, None, false,
|
||||
&path, &config_tx, &log_tx, None, None, &mut state, None, false, None, None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
@@ -77,7 +79,7 @@ async fn decoy_dns_watcher_publishes_dns_only_changes_once() {
|
||||
|
||||
// Explicit reload bypasses the unchanged source hash and replaces the injected endpoint.
|
||||
preparation::reload(
|
||||
&path, &config_tx, &log_tx, None, None, &mut state, None, true,
|
||||
&path, &config_tx, &log_tx, None, None, &mut state, None, true, None, None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
@@ -87,7 +89,7 @@ async fn decoy_dns_watcher_publishes_dns_only_changes_once() {
|
||||
let current = config_rx.borrow_and_update().clone();
|
||||
std::fs::write(&path, SOURCE.replace("localhost:18081", "localhost:18080")).unwrap();
|
||||
preparation::reload(
|
||||
&path, &config_tx, &log_tx, None, None, &mut state, None, false,
|
||||
&path, &config_tx, &log_tx, None, None, &mut state, None, false, None, None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
@@ -111,7 +113,7 @@ async fn decoy_dns_unchanged_watcher_source_skips_resolution() {
|
||||
let mut state = ReloadState::new(Some(source.rendered_hash));
|
||||
assert!(preparation::source_matches_active(&initial, &source));
|
||||
preparation::reload(
|
||||
&path, &config_tx, &log_tx, None, None, &mut state, None, false,
|
||||
&path, &config_tx, &log_tx, None, None, &mut state, None, false, None, None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -34,9 +34,30 @@ pub(super) async fn reload(
|
||||
reload_state: &mut ReloadState,
|
||||
dns_resolver: Option<Arc<crate::network::dns_overrides::GenerationDnsResolver>>,
|
||||
force: bool,
|
||||
quota_mutation: Option<&Arc<tokio::sync::Mutex<()>>>,
|
||||
quota_source_refresh: Option<&(dyn Fn() -> bool + Send + Sync)>,
|
||||
) -> Option<WatchManifest> {
|
||||
// Serialize source acquisition with API lifecycle commits, then release before DNS.
|
||||
// The source timestamp fences any later mutation during asynchronous preparation.
|
||||
let guard = match quota_mutation {
|
||||
Some(gate) => Some(gate.lock().await),
|
||||
None => None,
|
||||
};
|
||||
let source = read_source(path).await?;
|
||||
let manifest = WatchManifest::from_source_files(&source.source_files);
|
||||
// A new file edit can restore the exact pre-creation bytes. Refresh only source
|
||||
// evidence for fenced accounts, retaining prepared DNS and immutable WEB state.
|
||||
if !force
|
||||
&& quota_source_refresh.is_some_and(|refresh| refresh())
|
||||
&& source_matches_active(&config_tx.borrow(), &source)
|
||||
{
|
||||
let mut refreshed = (**config_tx.borrow()).clone();
|
||||
refreshed.quota_source_read_at = source.config.quota_source_read_at;
|
||||
config_tx.send(Arc::new(refreshed)).ok();
|
||||
reload_state.mark_applied(source.rendered_hash);
|
||||
return Some(manifest);
|
||||
}
|
||||
drop(guard);
|
||||
if !force && reload_state.is_applied(source.rendered_hash) {
|
||||
return Some(manifest);
|
||||
}
|
||||
@@ -66,6 +87,7 @@ pub(super) async fn reload(
|
||||
detected_ip_v6,
|
||||
reload_state,
|
||||
dns_resolver.as_deref(),
|
||||
quota_source_refresh.is_some_and(|refresh| refresh()),
|
||||
),
|
||||
Ok(Err(error)) => {
|
||||
error!(
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn quota_period_unchanged_source_refreshes_only_fenced_accounts_without_dns() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let path = dir.path().join("config.toml");
|
||||
std::fs::write(
|
||||
&path,
|
||||
"[access.users]\nalice = '0123456789abcdef0123456789abcdef'\n",
|
||||
)
|
||||
.unwrap();
|
||||
let source = ProxyConfig::parse_source(&path).unwrap();
|
||||
let initial = Arc::new(source.config);
|
||||
let (tx, mut rx) = watch::channel(initial.clone());
|
||||
let (log, _) = watch::channel(initial.general.log_level.clone());
|
||||
let mut state = ReloadState::new(Some(source.rendered_hash));
|
||||
let gate = Arc::new(tokio::sync::Mutex::new(()));
|
||||
preparation::reload(
|
||||
&path,
|
||||
&tx,
|
||||
&log,
|
||||
None,
|
||||
None,
|
||||
&mut state,
|
||||
None,
|
||||
false,
|
||||
Some(&gate),
|
||||
Some(&|| true),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(rx.has_changed().unwrap());
|
||||
let refreshed = rx.borrow_and_update().clone();
|
||||
assert!(config_equal(&initial, &refreshed));
|
||||
assert!(refreshed.quota_source_read_at > initial.quota_source_read_at);
|
||||
preparation::reload(
|
||||
&path,
|
||||
&tx,
|
||||
&log,
|
||||
None,
|
||||
None,
|
||||
&mut state,
|
||||
None,
|
||||
false,
|
||||
Some(&gate),
|
||||
Some(&|| false),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(!rx.has_changed().unwrap());
|
||||
assert!(Arc::ptr_eq(&refreshed, &rx.borrow()));
|
||||
preparation::reload(
|
||||
&path,
|
||||
&tx,
|
||||
&log,
|
||||
None,
|
||||
None,
|
||||
&mut state,
|
||||
None,
|
||||
true,
|
||||
Some(&gate),
|
||||
Some(&|| true),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(rx.has_changed().unwrap());
|
||||
assert!(rx.borrow().quota_source_read_at > refreshed.quota_source_read_at);
|
||||
assert!(config_equal(&refreshed, &rx.borrow()));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn quota_period_watcher_initialization_refreshes_pending_identical_source() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let path = dir.path().join("config.toml");
|
||||
std::fs::write(
|
||||
&path,
|
||||
"[access.users]\nalice = '0123456789abcdef0123456789abcdef'\n",
|
||||
)
|
||||
.unwrap();
|
||||
let initial = Arc::new(ProxyConfig::load(&path).unwrap());
|
||||
let cancel = tokio_util::sync::CancellationToken::new();
|
||||
let (mut rx, _, task) = spawn_config_watcher(
|
||||
path,
|
||||
initial.clone(),
|
||||
None,
|
||||
None,
|
||||
cancel.clone(),
|
||||
None,
|
||||
None,
|
||||
Some(Arc::new(tokio::sync::Mutex::new(()))),
|
||||
Some(Arc::new(|| true)),
|
||||
);
|
||||
let task = tokio::spawn(task);
|
||||
tokio::time::timeout(Duration::from_secs(5), rx.changed())
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert!(config_equal(&initial, &rx.borrow()));
|
||||
assert!(rx.borrow().quota_source_read_at > initial.quota_source_read_at);
|
||||
cancel.cancel();
|
||||
tokio::time::timeout(Duration::from_secs(5), task)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
}
|
||||
Reference in New Issue
Block a user