diff --git a/tests/cfg test mod regression.rs b/tests/cfg test mod regression.rs new file mode 100644 index 0000000..bbc2205 --- /dev/null +++ b/tests/cfg test mod regression.rs @@ -0,0 +1,220 @@ +#[cfg(test)] +mod regression_tests { + use super::*; + use serde_json::json; + use std::sync::Arc; + use parking_lot::RwLock; + use std::collections::HashMap; + use std::time::{SystemTime, UNIX_EPOCH}; + + #[test] + fn test_insert_get_flow() { + let db = Arc::new(RwLock::new(HashMap::new())); + let server = FutriixServer { + db: db.clone(), + time_series_db: Arc::new(RwLock::new(HashMap::new())), + command_queue: Arc::new(SegQueue::new()), + transactions: Arc::new(RwLock::new(HashMap::new())), + indexes: Arc::new(RwLock::new(HashMap::new())), + replication_enabled: false, + peer_nodes: Vec::new(), + sync_interval: 1000, + last_sync_timestamp: Arc::new(RwLock::new(0)), + command_history: Arc::new(RwLock::new(Vec::new())), + next_tx_id: Arc::new(RwLock::new(1)), + }; + + // Тест базовой вставки и получения + let insert_cmd = Command::Insert { + key: "test_key".to_string(), + value: json!({"field": "value"}), + }; + let response = server.process_command_internal(insert_cmd); + assert!(matches!(response, Response::Success(None))); + + let get_cmd = Command::Get { + key: "test_key".to_string(), + version: None, + }; + let response = server.process_command_internal(get_cmd); + assert!(matches!(response, Response::Success(Some(_)))); + + if let Response::Success(Some(value)) = response { + assert_eq!(value, json!({"field": "value"})); + } + + // Тест обновления + let update_cmd = Command::Update { + key: "test_key".to_string(), + value: json!({"field": "new_value"}), + }; + let response = server.process_command_internal(update_cmd); + assert!(matches!(response, Response::Success(None))); + + // Тест получения конкретной версии + let get_cmd = Command::Get { + key: "test_key".to_string(), + version: Some(0), + }; + let response = server.process_command_internal(get_cmd); + assert!(matches!(response, Response::Success(Some(_)))); + + if let Response::Success(Some(value)) = response { + assert_eq!(value, json!({"field": "value"})); + } + + // Тест удаления + let delete_cmd = Command::Delete { + key: "test_key".to_string(), + }; + let response = server.process_command_internal(delete_cmd); + assert!(matches!(response, Response::Success(None))); + + // Проверка что данные действительно удалены + let get_cmd = Command::Get { + key: "test_key".to_string(), + version: None, + }; + let response = server.process_command_internal(get_cmd); + assert!(matches!(response, Response::Error(_))); + } + + #[test] + fn test_transaction_flow() { + let db = Arc::new(RwLock::new(HashMap::new())); + let server = FutriixServer { + db: db.clone(), + time_series_db: Arc::new(RwLock::new(HashMap::new())), + command_queue: Arc::new(SegQueue::new()), + transactions: Arc::new(RwLock::new(HashMap::new())), + indexes: Arc::new(RwLock::new(HashMap::new())), + replication_enabled: false, + peer_nodes: Vec::new(), + sync_interval: 1000, + last_sync_timestamp: Arc::new(RwLock::new(0)), + command_history: Arc::new(RwLock::new(Vec::new())), + next_tx_id: Arc::new(RwLock::new(1)), + }; + + // Начало транзакции + let begin_cmd = Command::BeginTransaction; + let response = server.process_command_internal(begin_cmd); + let tx_id = if let Response::Success(Some(id)) = response { + id.as_u64().unwrap() + } else { + panic!("Transaction begin failed"); + }; + + // Вставка в транзакции + let insert_cmd = Command::Insert { + key: "tx_key".to_string(), + value: json!({"tx": "data"}), + }; + let response = server.process_command_internal(insert_cmd); + assert!(matches!(response, Response::Success(None))); + + // Проверка что данные не видны вне транзакции + let get_cmd = Command::Get { + key: "tx_key".to_string(), + version: None, + }; + let response = server.process_command_internal(get_cmd); + assert!(matches!(response, Response::Error(_))); + + // Коммит транзакции + let commit_cmd = Command::CommitTransaction(tx_id); + let response = server.process_command_internal(commit_cmd); + assert!(matches!(response, Response::Success(None))); + + // Проверка что данные теперь видны + let get_cmd = Command::Get { + key: "tx_key".to_string(), + version: None, + }; + let response = server.process_command_internal(get_cmd); + assert!(matches!(response, Response::Success(Some(_)))); + + // Тест отката транзакции + let begin_cmd = Command::BeginTransaction; + let response = server.process_command_internal(begin_cmd); + let tx_id = if let Response::Success(Some(id)) = response { + id.as_u64().unwrap() + } else { + panic!("Transaction begin failed"); + }; + + let insert_cmd = Command::Insert { + key: "rollback_key".to_string(), + value: json!({"should": "not_exist"}), + }; + let response = server.process_command_internal(insert_cmd); + assert!(matches!(response, Response::Success(None))); + + let rollback_cmd = Command::RollbackTransaction(tx_id); + let response = server.process_command_internal(rollback_cmd); + assert!(matches!(response, Response::Success(None))); + + // Проверка что данные не сохранились + let get_cmd = Command::Get { + key: "rollback_key".to_string(), + version: None, + }; + let response = server.process_command_internal(get_cmd); + assert!(matches!(response, Response::Error(_))); + } + + #[test] + fn test_time_series_operations() { + let db = Arc::new(RwLock::new(HashMap::new())); + let server = FutriixServer { + db: db.clone(), + time_series_db: Arc::new(RwLock::new(HashMap::new())), + command_queue: Arc::new(SegQueue::new()), + transactions: Arc::new(RwLock::new(HashMap::new())), + indexes: Arc::new(RwLock::new(HashMap::new())), + replication_enabled: false, + peer_nodes: Vec::new(), + sync_interval: 1000, + last_sync_timestamp: Arc::new(RwLock::new(0)), + command_history: Arc::new(RwLock::new(Vec::new())), + next_tx_id: Arc::new(RwLock::new(1)), + }; + + let now = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_millis(); + + // Вставка временных рядов + let ts_insert = Command::TimeSeriesInsert { + key: "ts_data".to_string(), + value: json!({"temp": 25}), + timestamp: Some(now), + }; + let response = server.process_command_internal(ts_insert); + assert!(matches!(response, Response::Success(None))); + + // Вставка без явного timestamp + let ts_insert = Command::TimeSeriesInsert { + key: "ts_data".to_string(), + value: json!({"temp": 26}), + timestamp: None, + }; + let response = server.process_command_internal(ts_insert); + assert!(matches!(response, Response::Success(None))); + + // Запрос временных рядов + let ts_query = Command::TimeSeriesQuery { + key: "ts_data".to_string(), + start: now - 1000, + end: now + 1000, + }; + let response = server.process_command_internal(ts_query); + assert!(matches!(response, Response::TimeSeriesData(_))); + + if let Response::TimeSeriesData(data) = response { + assert!(data.len() >= 1); + assert_eq!(data[0].1, json!({"temp": 25})); + } + } +}