use processor::state::{
DistributedLock, LockGuard, PostgresConfig, PostgresStateBackend, RedisConfig,
RedisDistributedLock, RedisStateBackend, StateBackend,
};
use std::collections::HashSet;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::sync::Barrier;
mod unit_tests {
use super::*;
#[tokio::test]
#[ignore]
async fn test_redis_connection_pool() {
let config = RedisConfig::builder()
.url("redis://localhost:6379")
.key_prefix("test_pool:")
.pool_size(5, 20)
.build()
.unwrap();
let backend = RedisStateBackend::new(config).await.unwrap();
assert!(backend.health_check().await.unwrap());
}
#[tokio::test]
#[ignore]
async fn test_redis_config_validation() {
let config = RedisConfig::builder()
.url("redis://localhost:6379")
.pool_size(5, 10)
.build();
assert!(config.is_ok());
let bad_config = RedisConfig {
urls: vec!["redis://localhost:6379".to_string()],
key_prefix: "test:".to_string(),
min_connections: 10,
max_connections: 5, ..Default::default()
};
assert!(bad_config.max_connections < bad_config.min_connections);
}
#[tokio::test]
#[ignore]
async fn test_redis_cluster_config() {
let config = RedisConfig::builder()
.urls(vec![
"redis://node1:6379".to_string(),
"redis://node2:6379".to_string(),
"redis://node3:6379".to_string(),
])
.cluster_mode(true)
.key_prefix("cluster:")
.build()
.unwrap();
assert!(config.cluster_mode);
assert_eq!(config.urls.len(), 3);
}
#[tokio::test]
#[ignore]
async fn test_postgres_connection_pool() {
let config = PostgresConfig::new("postgresql://postgres:postgres@localhost:5432/optimizer_test")
.with_pool_size(2, 10);
let backend = PostgresStateBackend::new(config).await.unwrap();
assert!(backend.health_check().await.unwrap());
backend.close().await;
}
#[tokio::test]
#[ignore]
async fn test_postgres_ssl_modes() {
let configs = vec![
PostgresConfig::new("postgresql://localhost/test").with_ssl_mode("disable"),
PostgresConfig::new("postgresql://localhost/test").with_ssl_mode("prefer"),
PostgresConfig::new("postgresql://localhost/test").with_ssl_mode("require"),
];
for config in configs {
assert!(
["disable", "prefer", "require"].contains(&config.ssl_mode.as_str())
);
}
}
#[tokio::test]
#[ignore]
async fn test_redis_retry_configuration() {
let config = RedisConfig::builder()
.url("redis://localhost:6379")
.retries(5, Duration::from_millis(50), Duration::from_secs(2))
.build()
.unwrap();
assert_eq!(config.max_retries, 5);
assert_eq!(config.retry_base_delay, Duration::from_millis(50));
assert_eq!(config.retry_max_delay, Duration::from_secs(2));
}
#[tokio::test]
#[ignore]
async fn test_postgres_timeout_configuration() {
let config = PostgresConfig::new("postgresql://localhost/test")
.with_timeout(Duration::from_secs(30))
.with_retries(3, Duration::from_millis(100));
assert_eq!(config.connect_timeout, Duration::from_secs(30));
assert_eq!(config.query_timeout, Duration::from_secs(30));
assert_eq!(config.max_retries, 3);
}
}
mod crud_operations {
use super::*;
#[tokio::test]
#[ignore]
async fn test_redis_put_get_delete() {
let config = RedisConfig::builder()
.url("redis://localhost:6379")
.key_prefix("test_crud:")
.build()
.unwrap();
let backend = RedisStateBackend::new(config).await.unwrap();
backend.clear().await.unwrap();
backend.put(b"key1", b"value1").await.unwrap();
assert_eq!(backend.get(b"key1").await.unwrap(), Some(b"value1".to_vec()));
backend.put(b"key1", b"value2").await.unwrap();
assert_eq!(backend.get(b"key1").await.unwrap(), Some(b"value2".to_vec()));
backend.delete(b"key1").await.unwrap();
assert_eq!(backend.get(b"key1").await.unwrap(), None);
backend.delete(b"nonexistent").await.unwrap();
}
#[tokio::test]
#[ignore]
async fn test_postgres_put_get_delete() {
let config = PostgresConfig::new("postgresql://postgres:postgres@localhost:5432/optimizer_test");
let backend = PostgresStateBackend::new(config).await.unwrap();
backend.clear().await.unwrap();
backend.put(b"key1", b"value1").await.unwrap();
assert_eq!(backend.get(b"key1").await.unwrap(), Some(b"value1".to_vec()));
backend.put(b"key1", b"value2").await.unwrap();
assert_eq!(backend.get(b"key1").await.unwrap(), Some(b"value2".to_vec()));
backend.delete(b"key1").await.unwrap();
assert_eq!(backend.get(b"key1").await.unwrap(), None);
}
#[tokio::test]
#[ignore]
async fn test_redis_large_values() {
let config = RedisConfig::builder()
.url("redis://localhost:6379")
.key_prefix("test_large:")
.build()
.unwrap();
let backend = RedisStateBackend::new(config).await.unwrap();
backend.clear().await.unwrap();
let large_value = vec![0u8; 1024 * 1024];
backend.put(b"large_key", &large_value).await.unwrap();
let retrieved = backend.get(b"large_key").await.unwrap().unwrap();
assert_eq!(retrieved.len(), large_value.len());
}
#[tokio::test]
#[ignore]
async fn test_postgres_large_values() {
let config = PostgresConfig::new("postgresql://postgres:postgres@localhost:5432/optimizer_test");
let backend = PostgresStateBackend::new(config).await.unwrap();
backend.clear().await.unwrap();
let large_value = vec![0u8; 10 * 1024 * 1024];
backend.put(b"large_key", &large_value).await.unwrap();
let retrieved = backend.get(b"large_key").await.unwrap().unwrap();
assert_eq!(retrieved.len(), large_value.len());
}
#[tokio::test]
#[ignore]
async fn test_redis_binary_data() {
let config = RedisConfig::builder()
.url("redis://localhost:6379")
.key_prefix("test_binary:")
.build()
.unwrap();
let backend = RedisStateBackend::new(config).await.unwrap();
backend.clear().await.unwrap();
let binary_data: Vec<u8> = (0..=255).collect();
backend.put(b"binary_key", &binary_data).await.unwrap();
let retrieved = backend.get(b"binary_key").await.unwrap().unwrap();
assert_eq!(retrieved, binary_data);
}
#[tokio::test]
#[ignore]
async fn test_redis_unicode_keys() {
let config = RedisConfig::builder()
.url("redis://localhost:6379")
.key_prefix("test_unicode:")
.build()
.unwrap();
let backend = RedisStateBackend::new(config).await.unwrap();
backend.clear().await.unwrap();
let keys = vec![
"key_䏿–‡",
"key_日本語",
"key_한글",
"key_العربية",
"key_emoji_🚀",
];
for key in keys {
backend.put(key.as_bytes(), b"value").await.unwrap();
assert_eq!(backend.get(key.as_bytes()).await.unwrap(), Some(b"value".to_vec()));
}
}
}
mod batch_operations {
use super::*;
#[tokio::test]
#[ignore]
async fn test_redis_batch_put_get_delete() {
let config = RedisConfig::builder()
.url("redis://localhost:6379")
.key_prefix("test_batch:")
.pipeline_batch_size(100)
.build()
.unwrap();
let backend = RedisStateBackend::new(config).await.unwrap();
backend.clear().await.unwrap();
let pairs: Vec<(&[u8], &[u8])> = (0..50)
.map(|i| {
(
format!("key{}", i).as_bytes() as &[u8],
format!("value{}", i).as_bytes() as &[u8],
)
})
.collect();
let owned_data: Vec<(Vec<u8>, Vec<u8>)> = (0..50)
.map(|i| (format!("key{}", i).into_bytes(), format!("value{}", i).into_bytes()))
.collect();
let refs: Vec<(&[u8], &[u8])> = owned_data
.iter()
.map(|(k, v)| (k.as_slice(), v.as_slice()))
.collect();
backend.batch_put(&refs).await.unwrap();
let keys: Vec<&[u8]> = owned_data.iter().map(|(k, _)| k.as_slice()).collect();
let values = backend.batch_get(&keys).await.unwrap();
assert_eq!(values.len(), 50);
for (i, value) in values.iter().enumerate() {
assert_eq!(value, &Some(format!("value{}", i).into_bytes()));
}
let deleted = backend.batch_delete(&keys).await.unwrap();
assert_eq!(deleted, 50);
assert_eq!(backend.count().await.unwrap(), 0);
}
#[tokio::test]
#[ignore]
async fn test_postgres_batch_put() {
let config = PostgresConfig::new("postgresql://postgres:postgres@localhost:5432/optimizer_test");
let backend = PostgresStateBackend::new(config).await.unwrap();
backend.clear().await.unwrap();
let owned_data: Vec<(Vec<u8>, Vec<u8>)> = (0..100)
.map(|i| (format!("key{}", i).into_bytes(), format!("value{}", i).into_bytes()))
.collect();
let refs: Vec<(&[u8], &[u8])> = owned_data
.iter()
.map(|(k, v)| (k.as_slice(), v.as_slice()))
.collect();
backend.batch_put(&refs).await.unwrap();
assert_eq!(backend.count().await.unwrap(), 100);
}
#[tokio::test]
#[ignore]
async fn test_redis_batch_size_limits() {
let config = RedisConfig::builder()
.url("redis://localhost:6379")
.key_prefix("test_batch_limit:")
.pipeline_batch_size(50)
.build()
.unwrap();
let backend = RedisStateBackend::new(config).await.unwrap();
backend.clear().await.unwrap();
let owned_data: Vec<(Vec<u8>, Vec<u8>)> = (0..200)
.map(|i| (format!("key{}", i).into_bytes(), format!("value{}", i).into_bytes()))
.collect();
let refs: Vec<(&[u8], &[u8])> = owned_data
.iter()
.map(|(k, v)| (k.as_slice(), v.as_slice()))
.collect();
backend.batch_put(&refs).await.unwrap();
assert_eq!(backend.count().await.unwrap(), 200);
}
}
mod transaction_tests {
use super::*;
#[tokio::test]
#[ignore]
async fn test_postgres_transaction_commit() {
let config = PostgresConfig::new("postgresql://postgres:postgres@localhost:5432/optimizer_test");
let backend = PostgresStateBackend::new(config).await.unwrap();
backend.clear().await.unwrap();
backend.put(b"key1", b"value1").await.unwrap();
backend.put(b"key2", b"value2").await.unwrap();
assert_eq!(backend.count().await.unwrap(), 2);
}
#[tokio::test]
#[ignore]
async fn test_postgres_batch_atomicity() {
let config = PostgresConfig::new("postgresql://postgres:postgres@localhost:5432/optimizer_test");
let backend = PostgresStateBackend::new(config).await.unwrap();
backend.clear().await.unwrap();
let owned_data: Vec<(Vec<u8>, Vec<u8>)> = (0..10)
.map(|i| (format!("key{}", i).into_bytes(), format!("value{}", i).into_bytes()))
.collect();
let refs: Vec<(&[u8], &[u8])> = owned_data
.iter()
.map(|(k, v)| (k.as_slice(), v.as_slice()))
.collect();
backend.batch_put(&refs).await.unwrap();
assert_eq!(backend.count().await.unwrap(), 10);
}
}
mod distributed_locking {
use super::*;
#[tokio::test]
#[ignore]
async fn test_redis_lock_acquisition() {
let lock = RedisDistributedLock::new("redis://localhost:6379")
.await
.unwrap();
let resource = "test_resource";
let guard1 = lock.try_acquire(resource, Duration::from_secs(10)).await.unwrap();
assert!(guard1.is_some());
let guard2 = lock.try_acquire(resource, Duration::from_secs(10)).await.unwrap();
assert!(guard2.is_none());
drop(guard1);
tokio::time::sleep(Duration::from_millis(100)).await;
let guard3 = lock.try_acquire(resource, Duration::from_secs(10)).await.unwrap();
assert!(guard3.is_some());
}
#[tokio::test]
#[ignore]
async fn test_redis_lock_expiration() {
let lock = RedisDistributedLock::new("redis://localhost:6379")
.await
.unwrap();
let resource = "test_expire_resource";
let guard = lock.acquire(resource, Duration::from_secs(1)).await.unwrap();
std::mem::forget(guard);
tokio::time::sleep(Duration::from_secs(2)).await;
let guard2 = lock.try_acquire(resource, Duration::from_secs(10)).await.unwrap();
assert!(guard2.is_some());
}
#[tokio::test]
#[ignore]
async fn test_redis_lock_extension() {
let lock = RedisDistributedLock::new("redis://localhost:6379")
.await
.unwrap();
let resource = "test_extend_resource";
let mut guard = lock.acquire(resource, Duration::from_secs(2)).await.unwrap();
tokio::time::sleep(Duration::from_secs(1)).await;
lock.extend(&mut guard, Duration::from_secs(5)).await.unwrap();
tokio::time::sleep(Duration::from_secs(2)).await;
assert!(lock.is_locked(resource).await.unwrap());
}
#[tokio::test]
#[ignore]
async fn test_lock_fairness() {
let lock = Arc::new(RedisDistributedLock::new("redis://localhost:6379")
.await
.unwrap());
let resource = "fairness_test";
let counter = Arc::new(AtomicU64::new(0));
let mut handles = vec![];
for _ in 0..10 {
let lock = lock.clone();
let counter = counter.clone();
let handle = tokio::spawn(async move {
let guard = lock.acquire(resource, Duration::from_secs(5)).await.unwrap();
let val = counter.fetch_add(1, Ordering::SeqCst);
tokio::time::sleep(Duration::from_millis(50)).await;
drop(guard);
val
});
handles.push(handle);
}
let mut results: Vec<u64> = vec![];
for handle in handles {
results.push(handle.await.unwrap());
}
results.sort();
assert_eq!(results, vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
assert_eq!(counter.load(Ordering::SeqCst), 10);
}
}
mod error_handling {
use super::*;
#[tokio::test]
#[ignore]
async fn test_redis_connection_failure() {
let config = RedisConfig::builder()
.url("redis://invalid-host:6379")
.retries(2, Duration::from_millis(100), Duration::from_secs(1))
.build()
.unwrap();
let result = RedisStateBackend::new(config).await;
assert!(result.is_err());
}
#[tokio::test]
#[ignore]
async fn test_postgres_connection_failure() {
let config = PostgresConfig::new("postgresql://invalid-host:5432/test")
.with_timeout(Duration::from_secs(2));
let result = PostgresStateBackend::new(config).await;
assert!(result.is_err());
}
#[tokio::test]
#[ignore]
async fn test_redis_operation_retry() {
let config = RedisConfig::builder()
.url("redis://localhost:6379")
.key_prefix("test_retry:")
.retries(3, Duration::from_millis(100), Duration::from_secs(1))
.build()
.unwrap();
let backend = RedisStateBackend::new(config).await.unwrap();
backend.clear().await.unwrap();
backend.put(b"key1", b"value1").await.unwrap();
assert_eq!(backend.get(b"key1").await.unwrap(), Some(b"value1".to_vec()));
}
}
mod performance_tests {
use super::*;
#[tokio::test]
#[ignore]
async fn bench_redis_write_throughput() {
let config = RedisConfig::builder()
.url("redis://localhost:6379")
.key_prefix("bench_write:")
.build()
.unwrap();
let backend = RedisStateBackend::new(config).await.unwrap();
backend.clear().await.unwrap();
let count = 10000;
let start = Instant::now();
for i in 0..count {
let key = format!("key{}", i);
backend.put(key.as_bytes(), b"value").await.unwrap();
}
let elapsed = start.elapsed();
let ops_per_sec = count as f64 / elapsed.as_secs_f64();
println!("Redis Write: {:.0} ops/sec", ops_per_sec);
assert!(ops_per_sec > 500.0);
}
#[tokio::test]
#[ignore]
async fn bench_redis_read_throughput() {
let config = RedisConfig::builder()
.url("redis://localhost:6379")
.key_prefix("bench_read:")
.build()
.unwrap();
let backend = RedisStateBackend::new(config).await.unwrap();
backend.clear().await.unwrap();
for i in 0..1000 {
let key = format!("key{}", i);
backend.put(key.as_bytes(), b"value").await.unwrap();
}
let count = 10000;
let start = Instant::now();
for i in 0..count {
let key = format!("key{}", i % 1000);
backend.get(key.as_bytes()).await.unwrap();
}
let elapsed = start.elapsed();
let ops_per_sec = count as f64 / elapsed.as_secs_f64();
println!("Redis Read: {:.0} ops/sec", ops_per_sec);
assert!(ops_per_sec > 500.0);
}
#[tokio::test]
#[ignore]
async fn bench_redis_batch_throughput() {
let config = RedisConfig::builder()
.url("redis://localhost:6379")
.key_prefix("bench_batch:")
.pipeline_batch_size(100)
.build()
.unwrap();
let backend = RedisStateBackend::new(config).await.unwrap();
backend.clear().await.unwrap();
let batch_size = 100;
let num_batches = 100;
let start = Instant::now();
for batch_num in 0..num_batches {
let owned_data: Vec<(Vec<u8>, Vec<u8>)> = (0..batch_size)
.map(|i| {
(
format!("key_{}_{}", batch_num, i).into_bytes(),
b"value".to_vec(),
)
})
.collect();
let refs: Vec<(&[u8], &[u8])> = owned_data
.iter()
.map(|(k, v)| (k.as_slice(), v.as_slice()))
.collect();
backend.batch_put(&refs).await.unwrap();
}
let elapsed = start.elapsed();
let total_ops = batch_size * num_batches;
let ops_per_sec = total_ops as f64 / elapsed.as_secs_f64();
println!("Redis Batch Write: {:.0} ops/sec", ops_per_sec);
assert!(ops_per_sec > 2000.0);
}
#[tokio::test]
#[ignore]
async fn bench_postgres_write_throughput() {
let config = PostgresConfig::new("postgresql://postgres:postgres@localhost:5432/optimizer_test")
.with_pool_size(5, 20);
let backend = PostgresStateBackend::new(config).await.unwrap();
backend.clear().await.unwrap();
let count = 1000;
let start = Instant::now();
for i in 0..count {
let key = format!("key{}", i);
backend.put(key.as_bytes(), b"value").await.unwrap();
}
let elapsed = start.elapsed();
let ops_per_sec = count as f64 / elapsed.as_secs_f64();
println!("PostgreSQL Write: {:.0} ops/sec", ops_per_sec);
assert!(ops_per_sec > 100.0);
}
#[tokio::test]
#[ignore]
async fn bench_latency_percentiles() {
let config = RedisConfig::builder()
.url("redis://localhost:6379")
.key_prefix("bench_latency:")
.build()
.unwrap();
let backend = RedisStateBackend::new(config).await.unwrap();
backend.clear().await.unwrap();
let mut latencies = Vec::new();
for i in 0..1000 {
let key = format!("key{}", i);
let start = Instant::now();
backend.put(key.as_bytes(), b"value").await.unwrap();
latencies.push(start.elapsed().as_micros() as f64);
}
latencies.sort_by(|a, b| a.partial_cmp(b).unwrap());
let p50 = latencies[latencies.len() / 2];
let p95 = latencies[(latencies.len() * 95) / 100];
let p99 = latencies[(latencies.len() * 99) / 100];
println!("Latency p50: {:.2}µs, p95: {:.2}µs, p99: {:.2}µs", p50, p95, p99);
assert!(p50 < 5000.0); assert!(p95 < 20000.0); assert!(p99 < 50000.0); }
}
mod fault_tolerance_tests {
use super::*;
#[tokio::test]
#[ignore]
async fn test_redis_connection_recovery() {
let config = RedisConfig::builder()
.url("redis://localhost:6379")
.key_prefix("test_recovery:")
.retries(5, Duration::from_millis(100), Duration::from_secs(2))
.build()
.unwrap();
let backend = RedisStateBackend::new(config).await.unwrap();
backend.clear().await.unwrap();
backend.put(b"key1", b"value1").await.unwrap();
tokio::time::sleep(Duration::from_millis(100)).await;
assert_eq!(backend.get(b"key1").await.unwrap(), Some(b"value1".to_vec()));
}
#[tokio::test]
#[ignore]
async fn test_postgres_connection_pool_exhaustion() {
let config = PostgresConfig::new("postgresql://postgres:postgres@localhost:5432/optimizer_test")
.with_pool_size(2, 5);
let backend = Arc::new(PostgresStateBackend::new(config).await.unwrap());
backend.clear().await.unwrap();
let mut handles = vec![];
for i in 0..10 {
let backend = backend.clone();
let handle = tokio::spawn(async move {
let key = format!("key{}", i);
backend.put(key.as_bytes(), b"value").await.unwrap();
});
handles.push(handle);
}
for handle in handles {
handle.await.unwrap();
}
assert_eq!(backend.count().await.unwrap(), 10);
}
#[tokio::test]
#[ignore]
async fn test_graceful_degradation() {
let config = RedisConfig::builder()
.url("redis://localhost:6379")
.key_prefix("test_degradation:")
.retries(3, Duration::from_millis(100), Duration::from_secs(1))
.build()
.unwrap();
let backend = RedisStateBackend::new(config).await.unwrap();
backend.put(b"key1", b"value1").await.unwrap();
let stats = backend.stats().await;
println!("Error rate: {:.2}%", stats.error_rate() * 100.0);
}
}
mod consistency_tests {
use super::*;
#[tokio::test]
#[ignore]
async fn test_read_your_writes() {
let config = RedisConfig::builder()
.url("redis://localhost:6379")
.key_prefix("test_consistency:")
.build()
.unwrap();
let backend = RedisStateBackend::new(config).await.unwrap();
backend.clear().await.unwrap();
backend.put(b"key1", b"value1").await.unwrap();
assert_eq!(backend.get(b"key1").await.unwrap(), Some(b"value1".to_vec()));
backend.put(b"key1", b"value2").await.unwrap();
assert_eq!(backend.get(b"key1").await.unwrap(), Some(b"value2".to_vec()));
}
#[tokio::test]
#[ignore]
async fn test_atomic_updates() {
let config = RedisConfig::builder()
.url("redis://localhost:6379")
.key_prefix("test_atomic:")
.build()
.unwrap();
let backend = Arc::new(RedisStateBackend::new(config).await.unwrap());
backend.clear().await.unwrap();
backend.put(b"counter", b"0").await.unwrap();
let barrier = Arc::new(Barrier::new(10));
let mut handles = vec![];
for _ in 0..10 {
let backend = backend.clone();
let barrier = barrier.clone();
let handle = tokio::spawn(async move {
barrier.wait().await;
backend.put(b"counter", b"1").await.unwrap();
});
handles.push(handle);
}
for handle in handles {
handle.await.unwrap();
}
assert_eq!(backend.get(b"counter").await.unwrap(), Some(b"1".to_vec()));
}
#[tokio::test]
#[ignore]
async fn test_distributed_lock_safety() {
let lock = Arc::new(RedisDistributedLock::new("redis://localhost:6379")
.await
.unwrap());
let counter = Arc::new(AtomicU64::new(0));
let mut handles = vec![];
for _ in 0..20 {
let lock = lock.clone();
let counter = counter.clone();
let handle = tokio::spawn(async move {
let guard = lock.acquire("safety_test", Duration::from_secs(5)).await.unwrap();
let current = counter.load(Ordering::SeqCst);
tokio::time::sleep(Duration::from_millis(10)).await;
counter.store(current + 1, Ordering::SeqCst);
drop(guard);
});
handles.push(handle);
}
for handle in handles {
handle.await.unwrap();
}
assert_eq!(counter.load(Ordering::SeqCst), 20);
}
#[tokio::test]
#[ignore]
async fn test_checkpoint_consistency() {
let config = RedisConfig::builder()
.url("redis://localhost:6379")
.key_prefix("test_checkpoint:")
.build()
.unwrap();
let backend = RedisStateBackend::new(config).await.unwrap();
backend.clear().await.unwrap();
for i in 0..100 {
let key = format!("key{}", i);
let value = format!("value{}", i);
backend.put(key.as_bytes(), value.as_bytes()).await.unwrap();
}
let checkpoint = backend.checkpoint().await.unwrap();
assert_eq!(checkpoint.len(), 100);
backend.put(b"key0", b"modified").await.unwrap();
backend.clear().await.unwrap();
backend.restore(checkpoint).await.unwrap();
assert_eq!(backend.get(b"key0").await.unwrap(), Some(b"value0".to_vec()));
}
}
#[allow(dead_code)]
async fn setup_redis() -> RedisStateBackend {
let config = RedisConfig::builder()
.url("redis://localhost:6379")
.key_prefix("test:")
.build()
.unwrap();
RedisStateBackend::new(config).await.unwrap()
}
#[allow(dead_code)]
async fn setup_postgres() -> PostgresStateBackend {
let config = PostgresConfig::new("postgresql://postgres:postgres@localhost:5432/optimizer_test");
PostgresStateBackend::new(config).await.unwrap()
}