]> git.saurik.com Git - redis.git/commitdiff
initial tests for AOF (and small changes to server.tcl to support these)
authorPieter Noordhuis <pcnoordhuis@gmail.com>
Wed, 19 May 2010 12:33:39 +0000 (14:33 +0200)
committerPieter Noordhuis <pcnoordhuis@gmail.com>
Wed, 19 May 2010 12:54:20 +0000 (14:54 +0200)
tests/integration/aof.tcl [new file with mode: 0644]
tests/support/server.tcl
tests/support/util.tcl
tests/test_helper.tcl

diff --git a/tests/integration/aof.tcl b/tests/integration/aof.tcl
new file mode 100644 (file)
index 0000000..0d93344
--- /dev/null
@@ -0,0 +1,80 @@
+set defaults [list [list appendonly yes] [list appendfilename appendonly.aof]]
+set server_path [tmpdir server.aof]
+set aof_path "$server_path/appendonly.aof"
+
+proc append_to_aof {str} {
+    upvar fp fp
+    puts -nonewline $fp $str
+}
+
+proc create_aof {code} {
+    upvar fp fp aof_path aof_path
+    set fp [open $aof_path w+]
+    uplevel 1 $code
+    close $fp
+}
+
+proc start_server_aof {overrides code} {
+    upvar defaults defaults srv srv server_path server_path
+    set _defaults $defaults
+    set srv [start_server default.conf [lappend _defaults $overrides]]
+    uplevel 1 $code
+    kill_server $srv
+}
+
+## Test the server doesn't start when the AOF contains an unfinished MULTI
+create_aof {
+    append_to_aof [formatCommand set foo hello]
+    append_to_aof [formatCommand multi]
+    append_to_aof [formatCommand set bar world]
+}
+
+start_server_aof [list dir $server_path] {
+    test {Unfinished MULTI: Server should not have been started} {
+        is_alive $srv
+    } {0}
+
+    test {Unfinished MULTI: Server should have logged an error} {
+        exec cat [dict get $srv stdout] | tail -n1
+    } {*Unexpected end of file reading the append only file*}
+}
+
+## Test that the server exits when the AOF contains a short read
+create_aof {
+    append_to_aof [formatCommand set foo hello]
+    append_to_aof [string range [formatCommand set bar world] 0 end-1]
+}
+
+start_server_aof [list dir $server_path] {
+    test {Short read: Server should not have been started} {
+        is_alive $srv
+    } {0}
+
+    test {Short read: Server should have logged an error} {
+        exec cat [dict get $srv stdout] | tail -n1
+    } {*Bad file format reading the append only file*}
+}
+
+## Test that redis-check-aof indeed sees this AOF is not valid
+test {Short read: Utility should confirm the AOF is not valid} {
+    catch {
+        exec ./redis-check-aof $aof_path
+    } str
+    set _ $str
+} {*not valid*}
+
+test {Short read: Utility should be able to fix the AOF} {
+    exec echo y | ./redis-check-aof --fix $aof_path
+} {*Successfully truncated AOF*}
+
+## Test that the server can be started using the truncated AOF
+start_server_aof [list dir $server_path] {
+    test {Fixed AOF: Server should have been started} {
+        is_alive $srv
+    } {1}
+
+    test {Fixed AOF: Keyspace should contain values that were parsable} {
+        set client [redis [dict get $srv host] [dict get $srv port]]
+        list [$client get foo] [$client get bar]
+    } {hello {}}
+}
index 40f21925a3b645c4d1b2ebd8c106be009a06a45b..8664b9a4305b272f8c4c67b4b4e7d043bdad6155 100644 (file)
@@ -8,6 +8,8 @@ proc error_and_quit {config_file error} {
 }
 
 proc kill_server config {
+    # nevermind if its already dead
+    if {![is_alive $config]} { return }
     set pid [dict get $config pid]
 
     # check for leaks
@@ -20,16 +22,24 @@ proc kill_server config {
     }
 
     # kill server and wait for the process to be totally exited
-    exec kill $pid
-    while 1 {
-        # with a non-zero exit status, the process is gone
-        if {[catch {exec ps -p $pid | grep redis-server} result]} {
-            break
+    while {[is_alive $config]} {
+        if {[incr wait 10] % 1000 == 0} {
+            puts "Waiting for process $pid to exit..."
         }
+        exec kill $pid
         after 10
     }
 }
 
+proc is_alive config {
+    set pid [dict get $config pid]
+    if {[catch {exec ps -p $pid} err]} {
+        return 0
+    } else {
+        return 1
+    }
+}
+
 proc start_server {filename overrides {code undefined}} {
     set data [split [exec cat "tests/assets/$filename"] "\n"]
     set config {}
@@ -74,33 +84,14 @@ proc start_server {filename overrides {code undefined}} {
         error_and_quit $config_file [exec cat $stderr]
     }
     
-    set line [exec head -n1 $stdout]
-    if {[string match {*already in use*} $line]} {
-        error_and_quit $config_file $line
-    }
-
-    while 1 {
-        # check that the server actually started and is ready for connections
-        if {[exec cat $stdout | grep "ready to accept" | wc -l] > 0} {
-            break
-        }
-        after 10
-    }
-
     # find out the pid
     regexp {^\[(\d+)\]} [exec head -n1 $stdout] _ pid
 
-    # create the client object
+    # setup properties to be able to initialize a client object
     set host $::host
     set port $::port
     if {[dict exists $config bind]} { set host [dict get $config bind] }
     if {[dict exists $config port]} { set port [dict get $config port] }
-    set client [redis $host $port]
-
-    # select the right db when we don't have to authenticate
-    if {![dict exists $config requirepass]} {
-        $client select 9
-    }
 
     # setup config dict
     dict set srv "config" $config_file
@@ -109,9 +100,31 @@ proc start_server {filename overrides {code undefined}} {
     dict set srv "port" $port
     dict set srv "stdout" $stdout
     dict set srv "stderr" $stderr
-    dict set srv "client" $client
 
+    # if a block of code is supplied, we wait for the server to become
+    # available, create a client object and kill the server afterwards
     if {$code ne "undefined"} {
+        set line [exec head -n1 $stdout]
+        if {[string match {*already in use*} $line]} {
+            error_and_quit $config_file $line
+        }
+
+        while 1 {
+            # check that the server actually started and is ready for connections
+            if {[exec cat $stdout | grep "ready to accept" | wc -l] > 0} {
+                break
+            }
+            after 10
+        }
+
+        set client [redis $host $port]
+        dict set srv "client" $client
+
+        # select the right db when we don't have to authenticate
+        if {![dict exists $config requirepass]} {
+            $client select 9
+        }
+
         # append the server to the stack
         lappend ::servers $srv
         
index 09a5804c17ea91ca32fbc8c38867987dbd3ea387..36bc90d98b42e04be6b0371f8886a8e4c91fbf0e 100644 (file)
@@ -188,3 +188,11 @@ proc createComplexDataset {r ops} {
         }
     }
 }
+
+proc formatCommand {args} {
+    set cmd "*[llength $args]\r\n"
+    foreach a $args {
+        append cmd "$[string length $a]\r\n$a\r\n"
+    }
+    set _ $cmd
+}
index f9830e853fdff66d494ca430664afd0fb601ae9c..e5f2ed77cc3b1953f3cf9de1024d7f33022e61fd 100644 (file)
@@ -61,6 +61,7 @@ proc main {} {
     execute_tests "unit/expire"
     execute_tests "unit/other"
     execute_tests "integration/replication"
+    execute_tests "integration/aof"
     
     puts "\n[expr $::passed+$::failed] tests, $::passed passed, $::failed failed"
     if {$::failed > 0} {