...
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); | ||||
| } | ||||
| @@ -86,6 +86,9 @@ fn setup_server() -> (ServerProcessGuard, u16) { | ||||
|         process: child, | ||||
|         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()); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -543,4 +543,67 @@ async fn test_error_handling() { | ||||
|     // Test DISCARD without MULTI | ||||
|     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