wsb-daemon 0.248.6265

wsb's daemon: the workbench, the GitHub mirror's schedule and peer continuity, for every workspace on the machine
//! What the nudge must never do: lose a wake, or wait forever for one.

use super::*;
use std::time::Instant;

/// TEST9988: a nudge that arrives before anybody waits is still delivered.
///
/// The race this exists for: a file is saved while a reconciliation pass is
/// running. The wake happens when nobody is waiting, and if it were a bare
/// condvar signal it would be lost — the edit would then wait for the sweep,
/// which is exactly the delay the watcher exists to remove.
#[test]
fn test9988_a_nudge_before_the_wait_is_not_lost() {
    let nudge = Nudge::default();
    nudge.wake();

    let started = Instant::now();
    nudge.wait(Duration::from_secs(30));
    assert!(
        started.elapsed() < Duration::from_secs(5),
        "a nudge raised before the wait was lost: waited {:?}",
        started.elapsed()
    );

    // And it is spent: the next wait has nothing to collect, so it waits.
    let started = Instant::now();
    nudge.wait(Duration::from_millis(300));
    assert!(
        started.elapsed() >= Duration::from_millis(250),
        "a spent nudge woke a second wait"
    );
}

/// TEST9989: with no events at all, the wait still ends.
///
/// The watcher is an optimisation, and this is what makes it one: if every
/// event were lost — an unwatchable tree, a filled inotify budget, a platform
/// without a backend — reconciliation still happens on the timeout.
#[test]
fn test9989_the_wait_ends_without_any_nudge() {
    let nudge = Nudge::default();
    let started = Instant::now();
    nudge.wait(Duration::from_millis(200));
    let waited = started.elapsed();
    assert!(waited >= Duration::from_millis(150), "returned too early: {waited:?}");
    assert!(waited < Duration::from_secs(5), "did not return: {waited:?}");
}

/// TEST9990: a wake from another thread ends a wait that is already running.
#[test]
fn test9990_a_wake_ends_a_wait_in_progress() {
    let nudge = Arc::new(Nudge::default());
    let waker = nudge.clone();
    std::thread::spawn(move || {
        std::thread::sleep(Duration::from_millis(100));
        waker.wake();
    });

    let started = Instant::now();
    nudge.wait(Duration::from_secs(30));
    assert!(
        started.elapsed() < Duration::from_secs(5),
        "the wait ignored a wake and ran to its timeout"
    );
}