@@ -81,7 +81,8 @@ mod integration_tests {
8181 parsed_command,
8282 RedisCommand :: Set {
8383 key: "mykey" . to_string( ) ,
84- value: Bytes :: from_static( b"hello world" )
84+ value: Bytes :: from_static( b"hello world" ) ,
85+ ttl_seconds: None
8586 }
8687 ) ;
8788 }
@@ -220,9 +221,10 @@ mod integration_tests {
220221
221222 match parsed_command {
222223 RedisCommand :: Get { key } => assert_eq ! ( key, "key1" ) ,
223- RedisCommand :: Set { key, value } => {
224+ RedisCommand :: Set { key, value, ttl_seconds } => {
224225 assert_eq ! ( key, "key2" ) ;
225226 assert_eq ! ( value, Bytes :: from_static( b"value" ) ) ;
227+ assert_eq ! ( ttl_seconds, None ) ;
226228 }
227229 RedisCommand :: Del { key } => assert_eq ! ( key, "key3" ) ,
228230 _ => panic ! ( "Unexpected command" ) ,
@@ -241,9 +243,10 @@ mod integration_tests {
241243 let parsed_command = parse_command ( parsed_resp) . unwrap ( ) ;
242244
243245 match parsed_command {
244- RedisCommand :: Set { key, value } => {
246+ RedisCommand :: Set { key, value, ttl_seconds } => {
245247 assert_eq ! ( key, "binary" ) ;
246248 assert_eq ! ( value, Bytes :: copy_from_slice( binary_data) ) ;
249+ assert_eq ! ( ttl_seconds, None ) ;
247250 }
248251 _ => panic ! ( "Expected SET command" ) ,
249252 }
@@ -267,9 +270,10 @@ mod integration_tests {
267270 let parsed_command = parse_command ( parsed_resp) . unwrap ( ) ;
268271
269272 match parsed_command {
270- RedisCommand :: Set { key, value } => {
273+ RedisCommand :: Set { key, value, ttl_seconds } => {
271274 assert_eq ! ( key, large_key) ;
272275 assert_eq ! ( value, Bytes :: from( large_value. into_bytes( ) ) ) ;
276+ assert_eq ! ( ttl_seconds, None ) ;
273277 }
274278 _ => panic ! ( "Expected SET command" ) ,
275279 }
@@ -283,9 +287,10 @@ mod integration_tests {
283287 let parsed_command = parse_command ( parsed_resp) . unwrap ( ) ;
284288
285289 match parsed_command {
286- RedisCommand :: Set { key, value } => {
290+ RedisCommand :: Set { key, value, ttl_seconds } => {
287291 assert_eq ! ( key, "empty" ) ;
288292 assert_eq ! ( value, Bytes :: new( ) ) ;
293+ assert_eq ! ( ttl_seconds, None ) ;
289294 }
290295 _ => panic ! ( "Expected SET command" ) ,
291296 }
@@ -415,6 +420,105 @@ mod integration_tests {
415420 assert ! ( matches!( result, Err ( ParseError :: Invalid ( _) ) ) ) ;
416421 }
417422
423+ #[ tokio:: test]
424+ async fn test_set_with_ttl_integration ( ) {
425+ // Test SET with EX option
426+ let set_ex_command = b"*5\r \n $3\r \n SET\r \n $8\r \n ttl_test\r \n $5\r \n value\r \n $2\r \n EX\r \n $2\r \n 60\r \n " ;
427+ let ( parsed_resp, _) = parse_resp_with_remaining ( set_ex_command) . unwrap ( ) ;
428+ let parsed_command = parse_command ( parsed_resp) . unwrap ( ) ;
429+ match parsed_command {
430+ RedisCommand :: Set { key, value, ttl_seconds } => {
431+ assert_eq ! ( key, "ttl_test" ) ;
432+ assert_eq ! ( value, Bytes :: from_static( b"value" ) ) ;
433+ assert_eq ! ( ttl_seconds, Some ( 60 ) ) ;
434+ }
435+ _ => panic ! ( "Expected SET command with TTL" ) ,
436+ }
437+
438+ // Test SET with PX option
439+ let set_px_command = b"*5\r \n $3\r \n SET\r \n $8\r \n ttl_test\r \n $5\r \n value\r \n $2\r \n PX\r \n $5\r \n 60000\r \n " ;
440+ let ( parsed_resp, _) = parse_resp_with_remaining ( set_px_command) . unwrap ( ) ;
441+ let parsed_command = parse_command ( parsed_resp) . unwrap ( ) ;
442+ match parsed_command {
443+ RedisCommand :: Set { key, value, ttl_seconds } => {
444+ assert_eq ! ( key, "ttl_test" ) ;
445+ assert_eq ! ( value, Bytes :: from_static( b"value" ) ) ;
446+ assert_eq ! ( ttl_seconds, Some ( 60 ) ) ; // 60000ms = 60s
447+ }
448+ _ => panic ! ( "Expected SET command with TTL" ) ,
449+ }
450+ }
451+
452+ #[ tokio:: test]
453+ async fn test_ttl_command_integration ( ) {
454+ let ttl_command = b"*2\r \n $3\r \n TTL\r \n $7\r \n mykey42\r \n " ;
455+ let mock_response = b":-1\r \n " ; // Key exists but no expiration
456+
457+ let port = create_mock_server ( vec ! [ mock_response. to_vec( ) ] ) . await ;
458+ let addr = format ! ( "127.0.0.1:{}" , port) ;
459+
460+ let response = send_command_and_receive ( & addr, ttl_command) . await ;
461+ assert_eq ! ( response, mock_response) ;
462+
463+ // Parse the command to verify our parser works
464+ let ( parsed_resp, _) = parse_resp_with_remaining ( ttl_command) . unwrap ( ) ;
465+ let parsed_command = parse_command ( parsed_resp) . unwrap ( ) ;
466+ assert_eq ! (
467+ parsed_command,
468+ RedisCommand :: Ttl {
469+ key: "mykey42" . to_string( )
470+ }
471+ ) ;
472+ }
473+
474+ #[ tokio:: test]
475+ async fn test_expire_command_integration ( ) {
476+ let expire_command = b"*3\r \n $6\r \n EXPIRE\r \n $7\r \n mykey42\r \n $3\r \n 120\r \n " ;
477+ let mock_response = b":1\r \n " ; // Key exists and expiration was set
478+
479+ let port = create_mock_server ( vec ! [ mock_response. to_vec( ) ] ) . await ;
480+ let addr = format ! ( "127.0.0.1:{}" , port) ;
481+
482+ let response = send_command_and_receive ( & addr, expire_command) . await ;
483+ assert_eq ! ( response, mock_response) ;
484+
485+ // Parse the command to verify our parser works
486+ let ( parsed_resp, _) = parse_resp_with_remaining ( expire_command) . unwrap ( ) ;
487+ let parsed_command = parse_command ( parsed_resp) . unwrap ( ) ;
488+ assert_eq ! (
489+ parsed_command,
490+ RedisCommand :: Expire {
491+ key: "mykey42" . to_string( ) ,
492+ seconds: 120
493+ }
494+ ) ;
495+ }
496+
497+ #[ tokio:: test]
498+ async fn test_ttl_edge_cases ( ) {
499+ // Test TTL for non-existent key
500+ let ttl_command = b"*2\r \n $3\r \n TTL\r \n $11\r \n nonexistent\r \n " ;
501+ let mock_response = b":-2\r \n " ; // Key doesn't exist
502+
503+ let port = create_mock_server ( vec ! [ mock_response. to_vec( ) ] ) . await ;
504+ let addr = format ! ( "127.0.0.1:{}" , port) ;
505+
506+ let response = send_command_and_receive ( & addr, ttl_command) . await ;
507+ assert_eq ! ( response, mock_response) ;
508+ }
509+
510+ #[ tokio:: test]
511+ async fn test_expire_on_nonexistent_key ( ) {
512+ let expire_command = b"*3\r \n $6\r \n EXPIRE\r \n $11\r \n nonexistent\r \n $2\r \n 60\r \n " ;
513+ let mock_response = b":0\r \n " ; // Key doesn't exist
514+
515+ let port = create_mock_server ( vec ! [ mock_response. to_vec( ) ] ) . await ;
516+ let addr = format ! ( "127.0.0.1:{}" , port) ;
517+
518+ let response = send_command_and_receive ( & addr, expire_command) . await ;
519+ assert_eq ! ( response, mock_response) ;
520+ }
521+
418522 #[ tokio:: test]
419523 async fn test_case_insensitive_commands ( ) {
420524 let test_cases = vec ! [
0 commit comments