Skip to content

Unsafe environment variable mutations in daemon tests lack synchronisation #75

@coderabbitai

Description

@coderabbitai

Problem

The daemon tests in crates/comenqd/tests/retry_helper.rs contain unsafe environment variable mutations that are not properly synchronised, creating a race condition when tests run in parallel.

Problematic locations:

  • calculate_timeout_caps_bounds test function
  • calculate_timeout_scales_with_ci_env test function

Current unsafe code:

#[test]
fn calculate_timeout_caps_bounds() {
    unsafe {
        env::remove_var("CI");
    }
    // ... test logic
    unsafe {
        env::set_var("CI", "1");
    }
    unsafe {
        env::remove_var("CI");
    }
}

Issues:

  1. Race condition - Multiple tests can corrupt each other's "CI" environment variable when running in parallel
  2. Potential flaky failures - Tests may fail unpredictably due to environment state races
  3. Unsafe code blocks - Multiple unsafe environment mutations throughout tests

Solution

Use the existing EnvVarGuard infrastructure from test-support/src/env_guard.rs which provides RAII-based environment variable management:

Add import:

use test_support::EnvVarGuard;

Replace unsafe blocks with safe RAII guards:

#[test]
fn calculate_timeout_caps_bounds() {
    // Test without CI environment
    let _guard = EnvVarGuard::remove("CI");
    let cfg = TimeoutConfig::new(1, TestComplexity::Simple);
    assert_eq\!(cfg.calculate_timeout(), Duration::from_secs(MIN_TIMEOUT_SECS));
    
    // Test with CI environment (guard automatically restores on drop)
    let _guard = EnvVarGuard::set("CI", "1");
    let cfg = TimeoutConfig::new(400, TestComplexity::Complex);
    assert_eq\!(cfg.calculate_timeout(), Duration::from_secs(MAX_TIMEOUT_SECS));
    // Guard automatically restores original environment state on drop
}

#[test]
fn calculate_timeout_scales_with_ci_env() {
    let _guard = EnvVarGuard::set("CI", "1");
    let cfg = TimeoutConfig::new(10, TestComplexity::Simple);
    let timeout = cfg.calculate_timeout();
    
    let _guard_no_ci = EnvVarGuard::remove("CI");  
    let timeout_no_ci = cfg.calculate_timeout();
    
    assert\!(timeout >= timeout_no_ci);
    // Both guards restore environment automatically
}

Benefits of this approach:

  • Uses existing infrastructure - EnvVarGuard is already tested and proven
  • RAII-based cleanup - Automatic restoration prevents test interference
  • Thread-safe - No global state mutations or race conditions
  • Eliminates unsafe blocks - All environment changes are safe
  • Consistent with codebase - Follows patterns used in other tests

Verification

After fixing, test with:

  • cargo test (parallel execution)
  • cargo test -- --test-threads=1 (serial execution)

Both should pass consistently without race conditions.

Related:

Metadata

Metadata

Assignees

Labels

mediumCould be disruptive, but might not happen

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions