eventcore-memory 0.1.7

In-memory adapter for EventCore event sourcing library (for testing)
Documentation
# eventcore-memory

In-memory event store adapter for EventCore - perfect for testing and development.

## Features

- **Zero setup** - No database required
- **Thread-safe** - Safe for concurrent testing
- **Fast** - No I/O overhead
- **Deterministic** - Consistent test results
- **Full API compatibility** - Drop-in replacement

## Installation

```toml
[dev-dependencies]
eventcore-memory = "0.1"
```

## Usage in Tests

```rust
use eventcore_memory::MemoryEventStore;
use eventcore::{CommandExecutor, testing::*};

#[tokio::test]
async fn test_my_command() {
    // Create store - no setup needed!
    let store = MemoryEventStore::new();
    let executor = CommandExecutor::new(store);
    
    // Test your commands
    let result = executor.execute(MyCommand { ... }).await;
    assert!(result.is_ok());
}
```

## Test Patterns

### Given-When-Then Testing

```rust
use eventcore::testing::CommandTestHarness;

#[tokio::test]
async fn transfer_should_move_money() {
    CommandTestHarness::new()
        .given_events(vec![
            AccountOpened { id: "alice", balance: Money::new(1000) },
            AccountOpened { id: "bob", balance: Money::new(0) },
        ])
        .when(TransferMoney { 
            from: "alice", 
            to: "bob", 
            amount: Money::new(100) 
        })
        .then_expect_events(vec![
            MoneyWithdrawn { account: "alice", amount: Money::new(100) },
            MoneyDeposited { account: "bob", amount: Money::new(100) },
        ])
        .run()
        .await
        .unwrap();
}
```

### Testing Concurrency

```rust
#[tokio::test]
async fn concurrent_transfers_should_not_overdraw() {
    let store = MemoryEventStore::new();
    let executor = CommandExecutor::new(store);
    
    // Setup account
    executor.execute(OpenAccount { 
        id: "alice", 
        initial: Money::new(100) 
    }).await.unwrap();
    
    // Try concurrent transfers
    let transfer1 = executor.execute(TransferMoney {
        from: "alice", to: "bob", amount: Money::new(60)
    });
    
    let transfer2 = executor.execute(TransferMoney {
        from: "alice", to: "charlie", amount: Money::new(60)
    });
    
    let (result1, result2) = tokio::join!(transfer1, transfer2);
    
    // One should succeed, one should fail
    assert!(result1.is_ok() ^ result2.is_ok());
}
```

### Testing Projections

```rust
#[tokio::test]
async fn projection_should_track_balances() {
    let store = MemoryEventStore::new();
    let mut projection = BalanceProjection::new();
    
    // Apply events
    let events = vec![
        AccountOpened { id: "alice", balance: Money::new(1000) },
        MoneyWithdrawn { account: "alice", amount: Money::new(100) },
    ];
    
    for event in events {
        projection.apply(&event).await.unwrap();
    }
    
    // Check projection state
    assert_eq!(projection.balance("alice"), Money::new(900));
}
```

## Limitations

The memory adapter is **for testing only**:

- ❌ No persistence - data lost on restart
- ❌ No distributed transactions
- ❌ Limited concurrency control compared to PostgreSQL
- ❌ No query capabilities beyond basic operations

For production, use [eventcore-postgres](../eventcore-postgres/).

## Advanced Testing

### Snapshot Testing

```rust
#[test]
fn test_with_snapshot() {
    let store = MemoryEventStore::new();
    
    // Take snapshot
    let snapshot = store.snapshot();
    
    // Make changes
    store.append_events(...).await.unwrap();
    
    // Restore snapshot
    store.restore(snapshot);
    
    // Store is back to original state
}
```

### Chaos Testing

```rust
#[test]
async fn test_random_failures() {
    let store = MemoryEventStore::with_chaos(ChaosConfig {
        failure_rate: 0.1,  // 10% chance of failure
        latency: Some(Duration::from_millis(100)),
    });
    
    // Test your error handling
}
```

### Performance Testing

```rust
#[test]
async fn benchmark_command_throughput() {
    let store = MemoryEventStore::new();
    let executor = CommandExecutor::new(store);
    
    let start = Instant::now();
    for i in 0..10_000 {
        executor.execute(TestCommand { id: i }).await.unwrap();
    }
    let elapsed = start.elapsed();
    
    println!("Commands/sec: {}", 10_000.0 / elapsed.as_secs_f64());
}
```

## Integration with Test Frameworks

### With `rstest`

```rust
use rstest::*;

#[fixture]
fn event_store() -> MemoryEventStore {
    MemoryEventStore::new()
}

#[fixture]
fn executor(event_store: MemoryEventStore) -> CommandExecutor<MemoryEventStore> {
    CommandExecutor::new(event_store)
}

#[rstest]
#[tokio::test]
async fn test_with_fixtures(executor: CommandExecutor<MemoryEventStore>) {
    // Your test here
}
```

### With `proptest`

```rust
use proptest::prelude::*;

proptest! {
    #[test]
    fn transfer_properties(
        amount in 1..1000u64,
        initial in 1000..10000u64
    ) {
        let rt = tokio::runtime::Runtime::new().unwrap();
        rt.block_on(async {
            let store = MemoryEventStore::new();
            // Property-based testing
        });
    }
}
```

## Debugging

Enable trace logging to see all operations:

```rust
#[test]
fn debug_test() {
    let _ = env_logger::builder()
        .filter_level(log::LevelFilter::Trace)
        .try_init();
        
    let store = MemoryEventStore::new();
    // All operations will be logged
}
```

## See Also

- [EventCore Core]../eventcore/ - Core library documentation
- [Test Utilities]../eventcore/src/testing/ - Testing helpers
- [Examples]../eventcore-examples/ - Complete test examples