1set defaults { appendonly {yes} appendfilename {appendonly.aof} } 2set server_path [tmpdir server.aof] 3set aof_path "$server_path/appendonly.aof" 4 5proc append_to_aof {str} { 6 upvar fp fp 7 puts -nonewline $fp $str 8} 9 10proc create_aof {code} { 11 upvar fp fp aof_path aof_path 12 set fp [open $aof_path w+] 13 uplevel 1 $code 14 close $fp 15} 16 17proc start_server_aof {overrides code} { 18 upvar defaults defaults srv srv server_path server_path 19 set config [concat $defaults $overrides] 20 set srv [start_server [list overrides $config]] 21 uplevel 1 $code 22 kill_server $srv 23} 24 25tags {"aof"} { 26 ## Test the server doesn't start when the AOF contains an unfinished MULTI 27 create_aof { 28 append_to_aof [formatCommand set foo hello] 29 append_to_aof [formatCommand multi] 30 append_to_aof [formatCommand set bar world] 31 } 32 33 start_server_aof [list dir $server_path] { 34 test "Unfinished MULTI: Server should have logged an error" { 35 set pattern "*Unexpected end of file reading the append only file*" 36 set retry 10 37 while {$retry} { 38 set result [exec tail -n1 < [dict get $srv stdout]] 39 if {[string match $pattern $result]} { 40 break 41 } 42 incr retry -1 43 after 1000 44 } 45 if {$retry == 0} { 46 error "assertion:expected error not found on config file" 47 } 48 } 49 } 50 51 ## Test that the server exits when the AOF contains a short read 52 create_aof { 53 append_to_aof [formatCommand set foo hello] 54 append_to_aof [string range [formatCommand set bar world] 0 end-1] 55 } 56 57 start_server_aof [list dir $server_path] { 58 test "Short read: Server should have logged an error" { 59 set pattern "*Bad file format reading the append only file*" 60 set retry 10 61 while {$retry} { 62 set result [exec tail -n1 < [dict get $srv stdout]] 63 if {[string match $pattern $result]} { 64 break 65 } 66 incr retry -1 67 after 1000 68 } 69 if {$retry == 0} { 70 error "assertion:expected error not found on config file" 71 } 72 } 73 } 74 75 ## Test that redis-check-aof indeed sees this AOF is not valid 76 test "Short read: Utility should confirm the AOF is not valid" { 77 catch { 78 exec src/redis-check-aof $aof_path 79 } result 80 assert_match "*not valid*" $result 81 } 82 83 test "Short read: Utility should be able to fix the AOF" { 84 set result [exec src/redis-check-aof --fix $aof_path << "y\n"] 85 assert_match "*Successfully truncated AOF*" $result 86 } 87 88 ## Test that the server can be started using the truncated AOF 89 start_server_aof [list dir $server_path] { 90 test "Fixed AOF: Server should have been started" { 91 assert_equal 1 [is_alive $srv] 92 } 93 94 test "Fixed AOF: Keyspace should contain values that were parsable" { 95 set client [redis [dict get $srv host] [dict get $srv port]] 96 wait_for_condition 50 100 { 97 [catch {$client ping} e] == 0 98 } else { 99 fail "Loading DB is taking too much time." 100 } 101 assert_equal "hello" [$client get foo] 102 assert_equal "" [$client get bar] 103 } 104 } 105 106 ## Test that SPOP (that modifies the client's argc/argv) is correctly free'd 107 create_aof { 108 append_to_aof [formatCommand sadd set foo] 109 append_to_aof [formatCommand sadd set bar] 110 append_to_aof [formatCommand spop set] 111 } 112 113 start_server_aof [list dir $server_path] { 114 test "AOF+SPOP: Server should have been started" { 115 assert_equal 1 [is_alive $srv] 116 } 117 118 test "AOF+SPOP: Set should have 1 member" { 119 set client [redis [dict get $srv host] [dict get $srv port]] 120 wait_for_condition 50 100 { 121 [catch {$client ping} e] == 0 122 } else { 123 fail "Loading DB is taking too much time." 124 } 125 assert_equal 1 [$client scard set] 126 } 127 } 128 129 ## Test that EXPIREAT is loaded correctly 130 create_aof { 131 append_to_aof [formatCommand rpush list foo] 132 append_to_aof [formatCommand expireat list 1000] 133 append_to_aof [formatCommand rpush list bar] 134 } 135 136 start_server_aof [list dir $server_path] { 137 test "AOF+EXPIRE: Server should have been started" { 138 assert_equal 1 [is_alive $srv] 139 } 140 141 test "AOF+EXPIRE: List should be empty" { 142 set client [redis [dict get $srv host] [dict get $srv port]] 143 wait_for_condition 50 100 { 144 [catch {$client ping} e] == 0 145 } else { 146 fail "Loading DB is taking too much time." 147 } 148 assert_equal 0 [$client llen list] 149 } 150 } 151 152 start_server {overrides {appendonly {yes} appendfilename {appendonly.aof}}} { 153 test {Redis should not try to convert DEL into EXPIREAT for EXPIRE -1} { 154 r set x 10 155 r expire x -1 156 } 157 } 158} 159