...
This commit is contained in:
@@ -74,6 +74,12 @@ impl Cmd {
|
||||
return Err(DBError(format!("unsupported cmd {:?}", cmd)));
|
||||
}
|
||||
}
|
||||
"setex" => {
|
||||
if cmd.len() != 4 {
|
||||
return Err(DBError(format!("wrong number of arguments for SETEX command")));
|
||||
}
|
||||
Cmd::SetEx(cmd[1].clone(), cmd[3].clone(), cmd[2].parse().unwrap())
|
||||
}
|
||||
"config" => {
|
||||
if cmd.len() != 3 || cmd[1].to_lowercase() != "get" {
|
||||
return Err(DBError(format!("unsupported cmd {:?}", cmd)));
|
||||
|
@@ -11,7 +11,7 @@ fn test_protocol_parsing() {
|
||||
Ok((protocol, _)) => {
|
||||
println!("Protocol parsed successfully: {:?}", protocol);
|
||||
match Cmd::from(type_cmd) {
|
||||
Ok((cmd, _)) => println!("Command parsed successfully: {:?}", cmd),
|
||||
Ok((cmd, _, _)) => println!("Command parsed successfully: {:?}", cmd),
|
||||
Err(e) => println!("Command parsing failed: {:?}", e),
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ fn test_protocol_parsing() {
|
||||
Ok((protocol, _)) => {
|
||||
println!("Protocol parsed successfully: {:?}", protocol);
|
||||
match Cmd::from(hexists_cmd) {
|
||||
Ok((cmd, _)) => println!("Command parsed successfully: {:?}", cmd),
|
||||
Ok((cmd, _, _)) => println!("Command parsed successfully: {:?}", cmd),
|
||||
Err(e) => println!("Command parsing failed: {:?}", e),
|
||||
}
|
||||
}
|
||||
|
@@ -1,30 +0,0 @@
|
||||
mod test_utils;
|
||||
use test_utils::run_inst_redis;
|
||||
|
||||
#[test]
|
||||
fn test_cmd_client_getname_setname() {
|
||||
let instructions = r#"
|
||||
[
|
||||
{
|
||||
"command": "start-server",
|
||||
"port": 6380,
|
||||
"args": ["--debug"]
|
||||
},
|
||||
{
|
||||
"command": "send-redis-raw",
|
||||
"port": 6380,
|
||||
"payload": "*3\r\n$6\r\nCLIENT\r\n$7\r\nSETNAME\r\n$5\r\nmyapp\r\n",
|
||||
"assert": "simple-string",
|
||||
"value": "OK"
|
||||
},
|
||||
{
|
||||
"command": "send-redis-raw",
|
||||
"port": 6380,
|
||||
"payload": "*2\r\n$6\r\nCLIENT\r\n$7\r\nGETNAME\r\n",
|
||||
"assert": "bulk-string",
|
||||
"value": "myapp"
|
||||
}
|
||||
]
|
||||
"#;
|
||||
run_inst_redis(instructions);
|
||||
}
|
@@ -87,6 +87,9 @@ fn setup_server() -> (ServerProcessGuard, u16) {
|
||||
test_dir,
|
||||
};
|
||||
|
||||
// Give the server a moment to start
|
||||
std::thread::sleep(Duration::from_millis(100));
|
||||
|
||||
(guard, port)
|
||||
}
|
||||
|
||||
@@ -96,20 +99,44 @@ async fn all_tests() {
|
||||
let mut conn = get_redis_connection(port);
|
||||
|
||||
// Run all tests using the same connection
|
||||
cleanup_keys(&mut conn).await;
|
||||
test_basic_ping(&mut conn).await;
|
||||
cleanup_keys(&mut conn).await;
|
||||
test_string_operations(&mut conn).await;
|
||||
cleanup_keys(&mut conn).await;
|
||||
test_incr_operations(&mut conn).await;
|
||||
test_hash_operations(&mut conn).await;
|
||||
// cleanup_keys(&mut conn).await;
|
||||
// test_hash_operations(&mut conn).await;
|
||||
cleanup_keys(&mut conn).await;
|
||||
test_expiration(&mut conn).await;
|
||||
cleanup_keys(&mut conn).await;
|
||||
test_scan_operations(&mut conn).await;
|
||||
cleanup_keys(&mut conn).await;
|
||||
test_scan_with_count(&mut conn).await;
|
||||
cleanup_keys(&mut conn).await;
|
||||
test_hscan_operations(&mut conn).await;
|
||||
cleanup_keys(&mut conn).await;
|
||||
test_transaction_operations(&mut conn).await;
|
||||
cleanup_keys(&mut conn).await;
|
||||
test_discard_transaction(&mut conn).await;
|
||||
cleanup_keys(&mut conn).await;
|
||||
test_type_command(&mut conn).await;
|
||||
cleanup_keys(&mut conn).await;
|
||||
test_config_commands(&mut conn).await;
|
||||
cleanup_keys(&mut conn).await;
|
||||
test_info_command(&mut conn).await;
|
||||
cleanup_keys(&mut conn).await;
|
||||
test_error_handling(&mut conn).await;
|
||||
|
||||
// Clean up keys after all tests
|
||||
cleanup_keys(&mut conn).await;
|
||||
}
|
||||
|
||||
async fn cleanup_keys(conn: &mut Connection) {
|
||||
let keys: Vec<String> = redis::cmd("KEYS").arg("*").query(conn).unwrap();
|
||||
if !keys.is_empty() {
|
||||
let _: () = redis::cmd("DEL").arg(keys).query(conn).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
async fn test_basic_ping(conn: &mut Connection) {
|
||||
@@ -141,16 +168,16 @@ async fn test_string_operations(conn: &mut Connection) {
|
||||
|
||||
async fn test_incr_operations(conn: &mut Connection) {
|
||||
// Test INCR on non-existent key
|
||||
let result: i32 = conn.incr("counter", 1).unwrap();
|
||||
let result: i32 = redis::cmd("INCR").arg("counter").query(conn).unwrap();
|
||||
assert_eq!(result, 1);
|
||||
|
||||
// Test INCR on existing key
|
||||
let result: i32 = conn.incr("counter", 1).unwrap();
|
||||
let result: i32 = redis::cmd("INCR").arg("counter").query(conn).unwrap();
|
||||
assert_eq!(result, 2);
|
||||
|
||||
// Test INCR on string value (should fail)
|
||||
let _: () = conn.set("string", "hello").unwrap();
|
||||
let result: Result<i32, _> = conn.incr("string", 1);
|
||||
let result: Result<i32, _> = redis::cmd("INCR").arg("string").query(conn);
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
|
@@ -544,3 +544,66 @@ async fn test_error_handling() {
|
||||
let response = send_command(&mut stream, "*1\r\n$7\r\nDISCARD\r\n").await;
|
||||
assert!(response.contains("ERR"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_list_operations() {
|
||||
let (mut server, port) = start_test_server("list").await;
|
||||
|
||||
tokio::spawn(async move {
|
||||
let listener = tokio::net::TcpListener::bind(format!("127.0.0.1:{}", port))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
loop {
|
||||
if let Ok((stream, _)) = listener.accept().await {
|
||||
let _ = server.handle(stream).await;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
sleep(Duration::from_millis(100)).await;
|
||||
|
||||
let mut stream = connect_to_server(port).await;
|
||||
|
||||
// Test LPUSH
|
||||
let response = send_command(&mut stream, "*4\r\n$5\r\nLPUSH\r\n$4\r\nlist\r\n$1\r\na\r\n$1\r\nb\r\n").await;
|
||||
assert!(response.contains("2")); // 2 elements
|
||||
|
||||
// Test RPUSH
|
||||
let response = send_command(&mut stream, "*4\r\n$5\r\nRPUSH\r\n$4\r\nlist\r\n$1\r\nc\r\n$1\r\nd\r\n").await;
|
||||
assert!(response.contains("4")); // 4 elements
|
||||
|
||||
// Test LLEN
|
||||
let response = send_command(&mut stream, "*2\r\n$4\r\nLLEN\r\n$4\r\nlist\r\n").await;
|
||||
assert!(response.contains("4"));
|
||||
|
||||
// Test LRANGE
|
||||
let response = send_command(&mut stream, "*4\r\n$6\r\nLRANGE\r\n$4\r\nlist\r\n$1\r\n0\r\n$2\r\n-1\r\n").await;
|
||||
assert!(response.contains("b"));
|
||||
assert!(response.contains("a"));
|
||||
assert!(response.contains("c"));
|
||||
assert!(response.contains("d"));
|
||||
|
||||
// Test LINDEX
|
||||
let response = send_command(&mut stream, "*3\r\n$6\r\nLINDEX\r\n$4\r\nlist\r\n$1\r\n0\r\n").await;
|
||||
assert!(response.contains("b"));
|
||||
|
||||
// Test LPOP
|
||||
let response = send_command(&mut stream, "*2\r\n$4\r\nLPOP\r\n$4\r\nlist\r\n").await;
|
||||
assert!(response.contains("b"));
|
||||
|
||||
// Test RPOP
|
||||
let response = send_command(&mut stream, "*2\r\n$4\r\nRPOP\r\n$4\r\nlist\r\n").await;
|
||||
assert!(response.contains("d"));
|
||||
|
||||
// Test LREM
|
||||
send_command(&mut stream, "*3\r\n$5\r\nLPUSH\r\n$4\r\nlist\r\n$1\r\na\r\n").await; // list is now a, c, a
|
||||
let response = send_command(&mut stream, "*4\r\n$4\r\nLREM\r\n$4\r\nlist\r\n$1\r\n1\r\n$1\r\na\r\n").await;
|
||||
assert!(response.contains("1"));
|
||||
|
||||
// Test LTRIM
|
||||
let response = send_command(&mut stream, "*4\r\n$5\r\nLTRIM\r\n$4\r\nlist\r\n$1\r\n0\r\n$1\r\n0\r\n").await;
|
||||
assert!(response.contains("OK"));
|
||||
let response = send_command(&mut stream, "*2\r\n$4\r\nLLEN\r\n$4\r\nlist\r\n").await;
|
||||
assert!(response.contains("1"));
|
||||
}
|
@@ -21,6 +21,7 @@ async fn start_test_server(test_name: &str) -> (Server, u16) {
|
||||
let option = DBOption {
|
||||
dir: test_dir,
|
||||
port,
|
||||
debug: true,
|
||||
};
|
||||
|
||||
let server = Server::new(option).await;
|
||||
|
Reference in New Issue
Block a user