221 lines
8.3 KiB
Rust
221 lines
8.3 KiB
Rust
#[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}));
|
|
}
|
|
}
|
|
}
|