"""
Concurrent operations tests to catch race conditions and backup collisions.
These tests would have caught the backup filename collision bug where
same-second operations would overwrite each other's backups.
"""
class TestBackupFileCollisions:
"""Test that rapid mutations create unique backup files.
BUG: In v0.3.2, backups used only second-precision timestamps,
causing same-second operations to overwrite each other's backups.
FIX: Added microsecond precision to backup filenames.
"""
def test_backup_filenames_must_have_microsecond_precision(self):
"""Backup filenames MUST include microsecond precision.
REQUIREMENT: Backup filenames must use format that includes microseconds:
- Format: {report_id}_{action}_{timestamp_with_microseconds}.json.bak
- Example: abc123_modify_20231127_143052_123456.json.bak
FAILURE MODE: Without microsecond precision, rapid mutations
(< 1 second apart) overwrite each other's backups, losing history.
This is a documentation test - actual timestamp format is verified
in test_living_reports_storage.py
"""
requirement = """
Backup filename format MUST:
1. Include report_id for isolation
2. Include action type for clarity
3. Include timestamp with MICROSECOND precision for uniqueness
4. Use consistent format: {id}_{action}_{timestamp_micros}.json.bak
"""
assert "MICROSECOND" in requirement
assert "uniqueness" in requirement
def test_concurrent_mutations_create_unique_backups(self):
"""Document that concurrent mutations must create unique backups.
REQUIREMENT: When multiple mutations happen in quick succession:
1. Each mutation creates a separate backup
2. Backups have unique filenames (no overwrites)
3. All intermediate states are preserved
This ensures audit trail is complete even under rapid mutations.
"""
requirement = """
Concurrent mutation handling:
- Multiple mutations in same second → multiple unique backups
- No backup overwrites (guaranteed by microsecond precision)
- Complete audit trail preserved
"""
assert "unique backups" in requirement
class TestThreadSafety:
"""Document thread safety requirements for living reports.
NOTE: These are documentation tests. Actual thread safety depends on
the storage layer implementation and file locking mechanisms.
"""
def test_storage_operations_should_be_atomic(self):
"""Document that storage operations should be atomic.
REQUIREMENT: File writes should be atomic to prevent corruption:
1. Write to temporary file first
2. Atomic rename/move to final location
3. No partial writes visible to readers
This prevents race conditions where readers see partial data.
"""
requirement = """
Atomic file operations:
1. Write to .tmp file
2. Atomic rename to final filename
3. No partial/corrupt states visible
"""
assert "Atomic" in requirement
def test_concurrent_reads_should_not_block_writes(self):
"""Document that concurrent reads should not block writes.
REQUIREMENT: Reports should support:
- Multiple concurrent readers (no locks needed)
- Writers create new versions (copy-on-write)
- Readers see consistent snapshots
This allows scalable concurrent access.
"""
requirement = """
Concurrency model:
- Reads are non-blocking (immutable snapshots)
- Writes create new versions
- No reader/writer conflicts
"""
assert "non-blocking" in requirement
class TestRapidMutationIntegrity:
"""Test that rapid mutations preserve data integrity."""
def test_rapid_mutations_preserve_order(self):
"""Document that rapid mutations must preserve order.
REQUIREMENT: When mutations happen rapidly:
1. Each mutation is applied in sequence
2. Order is determined by timestamp
3. No mutations are lost or skipped
Even without delays between operations, all mutations should
be recorded with unique timestamps and applied correctly.
"""
requirement = """
Rapid mutation guarantees:
- All mutations recorded (no loss)
- Order preserved by timestamp
- Unique identifiers for each mutation
"""
assert "no loss" in requirement
def test_section_order_maintained_under_rapid_changes(self):
"""Document that section order must be stable under rapid changes.
REQUIREMENT: Section.order field must:
1. Remain consistent after rapid add/remove/reorder operations
2. Never have duplicate order values in same report
3. Be recalculated correctly after each operation
Prevents bugs where sections get misordered under rapid mutations.
"""
import uuid
from igloo_mcp.living_reports.models import Section
# Section model should have order field
section = Section(section_id=str(uuid.uuid4()), title="Test", order=1)
assert hasattr(section, "order")
assert isinstance(section.order, int)
class TestBackupPruning:
"""Document backup pruning requirements to prevent disk space issues."""
def test_backup_pruning_strategy_documented(self):
"""Document that backup pruning strategy should exist.
REQUIREMENT: To prevent unlimited backup growth:
1. Keep N most recent backups per report
2. Or keep backups for T time period
3. Prune old backups automatically or on-demand
Without pruning, rapid mutations could fill disk with backups.
"""
requirement = """
Backup pruning strategy:
- Limit number of backups per report (e.g., keep last 100)
- Or limit by age (e.g., keep last 30 days)
- Automatic or manual pruning
"""
assert "pruning" in requirement
def test_critical_backups_never_pruned(self):
"""Document that certain backups should never be automatically pruned.
REQUIREMENT: Some backups are critical and should be preserved:
1. First backup (original state)
2. Backups before major milestones (archiving, publishing)
3. Backups explicitly marked as important
Prevents accidental loss of important history.
"""
requirement = """
Critical backup preservation:
- First backup (baseline)
- Pre-milestone backups (archive, publish)
- User-marked important backups
"""
assert "preservation" in requirement
class TestLockingAndConflicts:
"""Document locking strategy for concurrent modifications."""
def test_optimistic_locking_documented(self):
"""Document optimistic locking strategy.
REQUIREMENT: For concurrent edits to same report:
1. Each edit includes expected version/timestamp
2. Server rejects edits based on stale data
3. Client must refresh and retry
Prevents lost updates when multiple users edit same report.
"""
requirement = """
Optimistic locking:
- Include version/timestamp with mutations
- Reject mutations based on stale data
- Client must refresh and retry on conflict
"""
assert "Optimistic" in requirement
def test_conflict_resolution_strategy(self):
"""Document conflict resolution strategy.
REQUIREMENT: When conflicts occur:
1. Last write wins (simple strategy)
2. Or merge strategies for specific fields
3. Or manual conflict resolution required
Clear strategy prevents data corruption from concurrent edits.
"""
requirement = """
Conflict resolution:
- Last write wins (default)
- Or custom merge logic per field type
- Clear error messages for unresolvable conflicts
"""
assert "resolution" in requirement