refactor: Move quota_needs_update calculation to a separate function (#5683)

And add a unit test for this function. At least this way we protect from the recently fixed bug when
a wrong comparison operator was used.
This commit is contained in:
iequidoo
2024-06-27 16:31:01 -03:00
committed by iequidoo
parent ee2fffb52b
commit 170cbb6635
3 changed files with 38 additions and 22 deletions

View File

@@ -541,18 +541,10 @@ impl Context {
}
// update quota (to send warning if full) - but only check it once in a while
let quota_needs_update = {
let quota = self.quota.read().await;
quota
.as_ref()
.filter(|quota| {
time_elapsed(&quota.modified)
< Duration::from_secs(DC_BACKGROUND_FETCH_QUOTA_CHECK_RATELIMIT)
})
.is_none()
};
if quota_needs_update {
if self
.quota_needs_update(DC_BACKGROUND_FETCH_QUOTA_CHECK_RATELIMIT)
.await
{
if let Err(err) = self.update_recent_quota(&mut session).await {
warn!(self, "Failed to update quota: {err:#}.");
}

View File

@@ -1,6 +1,7 @@
//! # Support for IMAP QUOTA extension.
use std::collections::BTreeMap;
use std::time::Duration;
use anyhow::{anyhow, Context as _, Result};
use async_imap::types::{Quota, QuotaResource};
@@ -11,7 +12,7 @@ use crate::context::Context;
use crate::imap::scan_folders::get_watched_folders;
use crate::imap::session::Session as ImapSession;
use crate::message::{Message, Viewtype};
use crate::tools;
use crate::tools::{self, time_elapsed};
use crate::{stock_str, EventType};
/// warn about a nearly full mailbox after this usage percentage is reached.
@@ -102,6 +103,16 @@ pub fn needs_quota_warning(curr_percentage: u64, warned_at_percentage: u64) -> b
}
impl Context {
/// Returns whether the quota value needs an update. If so, `update_recent_quota()` should be
/// called.
pub(crate) async fn quota_needs_update(&self, ratelimit_secs: u64) -> bool {
let quota = self.quota.read().await;
quota
.as_ref()
.filter(|quota| time_elapsed(&quota.modified) < Duration::from_secs(ratelimit_secs))
.is_none()
}
/// Updates `quota.recent`, sets `quota.modified` to the current time
/// and emits an event to let the UIs update connectivity view.
///
@@ -155,6 +166,7 @@ impl Context {
#[cfg(test)]
mod tests {
use super::*;
use crate::test_utils::TestContextManager;
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_needs_quota_warning() -> Result<()> {
@@ -183,4 +195,24 @@ mod tests {
assert!(QUOTA_ERROR_THRESHOLD_PERCENTAGE < 100);
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_quota_needs_update() {
let mut tcm = TestContextManager::new();
let t = &tcm.unconfigured().await;
const TIMEOUT: u64 = 60;
assert!(t.quota_needs_update(TIMEOUT).await);
*t.quota.write().await = Some(QuotaInfo {
recent: Ok(Default::default()),
modified: tools::Time::now() - Duration::from_secs(TIMEOUT + 1),
});
assert!(t.quota_needs_update(TIMEOUT).await);
*t.quota.write().await = Some(QuotaInfo {
recent: Ok(Default::default()),
modified: tools::Time::now(),
});
assert!(!t.quota_needs_update(TIMEOUT).await);
}
}

View File

@@ -2,7 +2,6 @@ use std::cmp;
use std::iter::{self, once};
use std::num::NonZeroUsize;
use std::sync::atomic::Ordering;
use std::time::Duration;
use anyhow::{bail, Context as _, Error, Result};
use async_channel::{self as channel, Receiver, Sender};
@@ -473,14 +472,7 @@ async fn inbox_fetch_idle(ctx: &Context, imap: &mut Imap, mut session: Session)
.await?;
// Update quota no more than once a minute.
let quota_needs_update = {
let quota = ctx.quota.read().await;
quota
.as_ref()
.filter(|quota| time_elapsed(&quota.modified) < Duration::from_secs(60))
.is_none()
};
if quota_needs_update {
if ctx.quota_needs_update(60).await {
if let Err(err) = ctx.update_recent_quota(&mut session).await {
warn!(ctx, "Failed to update quota: {:#}.", err);
}