mirror of https://github.com/redis/redis.git
				
				
				
			
		
			
				
	
	
		
			365 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Tcl
		
	
	
	
			
		
		
	
	
			365 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Tcl
		
	
	
	
| start_server {tags {"pause network"}} {
 | |
|     test "Test read commands are not blocked by client pause" {
 | |
|         r client PAUSE 100000 WRITE
 | |
|         set rd [redis_deferring_client]
 | |
|         $rd GET FOO
 | |
|         $rd PING
 | |
|         $rd INFO
 | |
|         assert_equal [s 0 blocked_clients] 0
 | |
|         r client unpause
 | |
|         $rd close
 | |
|     }
 | |
| 
 | |
|     test "Test old pause-all takes precedence over new pause-write (less restrictive)" {
 | |
|         # Scenario:
 | |
|         # 1. Run 'PAUSE ALL' for 200msec
 | |
|         # 2. Run 'PAUSE WRITE' for 10 msec
 | |
|         # 3. Wait 50msec
 | |
|         # 4. 'GET FOO'.
 | |
|         # Expected that:
 | |
|         # - While the time of the second 'PAUSE' is shorter than first 'PAUSE',
 | |
|         #   pause-client feature will stick to the longer one, i.e, will be paused
 | |
|         #   up to 200msec.
 | |
|         # - The GET command will be postponed ~200msec, even though last command
 | |
|         #   paused only WRITE. This is because the first 'PAUSE ALL' command is
 | |
|         #   more restrictive than the second 'PAUSE WRITE' and pause-client feature
 | |
|         #   preserve most restrictive configuration among multiple settings.
 | |
|         set rd [redis_deferring_client]
 | |
|         $rd SET FOO BAR
 | |
| 
 | |
|         set test_start_time [clock milliseconds]
 | |
|         r client PAUSE 200 ALL
 | |
|         r client PAUSE 20 WRITE
 | |
|         after 50
 | |
|         $rd get FOO
 | |
|         set elapsed [expr {[clock milliseconds]-$test_start_time}]
 | |
|         assert_lessthan 200 $elapsed
 | |
|     }
 | |
| 
 | |
|     test "Test new pause time is smaller than old one, then old time preserved" {
 | |
|         r client PAUSE 60000 WRITE
 | |
|         r client PAUSE 10 WRITE
 | |
|         after 100
 | |
|         set rd [redis_deferring_client]
 | |
|         $rd SET FOO BAR
 | |
|         wait_for_blocked_clients_count 1 100 10
 | |
| 
 | |
|         r client unpause
 | |
|         assert_match "OK" [$rd read]
 | |
|         $rd close
 | |
|     }
 | |
| 
 | |
|     test "Test write commands are paused by RO" {
 | |
|         r client PAUSE 60000 WRITE
 | |
| 
 | |
|         set rd [redis_deferring_client]
 | |
|         $rd SET FOO BAR
 | |
|         wait_for_blocked_clients_count 1 50 100
 | |
| 
 | |
|         r client unpause
 | |
|         assert_match "OK" [$rd read]
 | |
|         $rd close
 | |
|     }
 | |
| 
 | |
|     test "Test special commands are paused by RO" {
 | |
|         r PFADD pause-hll test
 | |
|         r client PAUSE 100000 WRITE
 | |
| 
 | |
|         # Test that pfcount, which can replicate, is also blocked
 | |
|         set rd [redis_deferring_client]
 | |
|         $rd PFCOUNT pause-hll
 | |
|         wait_for_blocked_clients_count 1 50 100
 | |
| 
 | |
|         # Test that publish, which adds the message to the replication
 | |
|         # stream is blocked.
 | |
|         set rd2 [redis_deferring_client]
 | |
|         $rd2 publish foo bar
 | |
|         wait_for_blocked_clients_count 2 50 100
 | |
| 
 | |
|         r client unpause 
 | |
|         assert_match "1" [$rd read]
 | |
|         assert_match "0" [$rd2 read]
 | |
|         $rd close
 | |
|         $rd2 close
 | |
|     }
 | |
| 
 | |
|     test "Test read/admin multi-execs are not blocked by pause RO" {
 | |
|         r SET FOO BAR
 | |
|         r client PAUSE 100000 WRITE
 | |
|         set rr [redis_client]
 | |
|         assert_equal [$rr MULTI] "OK"
 | |
|         assert_equal [$rr PING] "QUEUED"
 | |
|         assert_equal [$rr GET FOO] "QUEUED"
 | |
|         assert_match "PONG BAR" [$rr EXEC]
 | |
|         assert_equal [s 0 blocked_clients] 0
 | |
|         r client unpause 
 | |
|         $rr close
 | |
|     }
 | |
| 
 | |
|     test "Test write multi-execs are blocked by pause RO" {
 | |
|         set rd [redis_deferring_client]
 | |
|         $rd MULTI
 | |
|         assert_equal [$rd read] "OK"
 | |
|         $rd SET FOO BAR
 | |
|         assert_equal [$rd read] "QUEUED"
 | |
|         r client PAUSE 60000 WRITE
 | |
|         $rd EXEC
 | |
|         wait_for_blocked_clients_count 1 50 100
 | |
|         r client unpause 
 | |
|         assert_match "OK" [$rd read]
 | |
|         $rd close
 | |
|     }
 | |
| 
 | |
|     test "Test scripts are blocked by pause RO" {
 | |
|         r client PAUSE 60000 WRITE
 | |
|         set rd [redis_deferring_client]
 | |
|         set rd2 [redis_deferring_client]
 | |
|         $rd EVAL "return 1" 0
 | |
| 
 | |
|         # test a script with a shebang and no flags for coverage
 | |
|         $rd2 EVAL {#!lua
 | |
|             return 1
 | |
|         } 0
 | |
| 
 | |
|         wait_for_blocked_clients_count 2 50 100
 | |
|         r client unpause 
 | |
|         assert_match "1" [$rd read]
 | |
|         assert_match "1" [$rd2 read]
 | |
|         $rd close
 | |
|         $rd2 close
 | |
|     }
 | |
| 
 | |
|     test "Test RO scripts are not blocked by pause RO" {
 | |
|         r set x y
 | |
|         # create a function for later
 | |
|         r FUNCTION load replace {#!lua name=f1
 | |
|             redis.register_function{
 | |
|                 function_name='f1',
 | |
|                 callback=function() return "hello" end,
 | |
|                 flags={'no-writes'}
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         r client PAUSE 6000000 WRITE
 | |
|         set rr [redis_client]
 | |
| 
 | |
|         # test an eval that's for sure not in the script cache
 | |
|         assert_equal [$rr EVAL {#!lua flags=no-writes
 | |
|                 return 'unique script'
 | |
|             } 0
 | |
|         ] "unique script"
 | |
| 
 | |
|         # for sanity, repeat that EVAL on a script that's already cached
 | |
|         assert_equal [$rr EVAL {#!lua flags=no-writes
 | |
|                 return 'unique script'
 | |
|             } 0
 | |
|         ] "unique script"
 | |
| 
 | |
|         # test EVAL_RO on a unique script that's for sure not in the cache
 | |
|         assert_equal [$rr EVAL_RO {
 | |
|             return redis.call('GeT', 'x')..' unique script'
 | |
|             } 1 x
 | |
|         ] "y unique script"
 | |
| 
 | |
|         # test with evalsha
 | |
|         set sha [$rr script load {#!lua flags=no-writes
 | |
|                 return 2
 | |
|             }]
 | |
|         assert_equal [$rr EVALSHA $sha 0] 2
 | |
| 
 | |
|         # test with function
 | |
|         assert_equal [$rr fcall f1 0] hello
 | |
| 
 | |
|         r client unpause
 | |
|         $rr close
 | |
|     }
 | |
| 
 | |
|     test "Test read-only scripts in multi-exec are not blocked by pause RO" {
 | |
|         r SET FOO BAR
 | |
|         r client PAUSE 100000 WRITE
 | |
|         set rr [redis_client]
 | |
|         assert_equal [$rr MULTI] "OK"
 | |
|         assert_equal [$rr EVAL {#!lua flags=no-writes
 | |
|                 return 12
 | |
|             } 0
 | |
|         ] QUEUED
 | |
|         assert_equal [$rr EVAL {#!lua flags=no-writes
 | |
|                 return 13
 | |
|             } 0
 | |
|         ] QUEUED
 | |
|         assert_match "12 13" [$rr EXEC]
 | |
|         assert_equal [s 0 blocked_clients] 0
 | |
|         r client unpause
 | |
|         $rr close
 | |
|     }
 | |
| 
 | |
|     test "Test write scripts in multi-exec are blocked by pause RO" {
 | |
|         set rd [redis_deferring_client]
 | |
|         set rd2 [redis_deferring_client]
 | |
| 
 | |
|         # one with a shebang
 | |
|         $rd MULTI
 | |
|         assert_equal [$rd read] "OK"
 | |
|         $rd EVAL {#!lua
 | |
|                 return 12
 | |
|             } 0
 | |
|         assert_equal [$rd read] "QUEUED"
 | |
| 
 | |
|         # one without a shebang
 | |
|         $rd2 MULTI
 | |
|         assert_equal [$rd2 read] "OK"
 | |
|         $rd2 EVAL {#!lua
 | |
|                 return 13
 | |
|             } 0
 | |
|         assert_equal [$rd2 read] "QUEUED"
 | |
| 
 | |
|         r client PAUSE 60000 WRITE
 | |
|         $rd EXEC
 | |
|         $rd2 EXEC
 | |
|         wait_for_blocked_clients_count 2 50 100
 | |
|         r client unpause
 | |
|         assert_match "12" [$rd read]
 | |
|         assert_match "13" [$rd2 read]
 | |
|         $rd close
 | |
|         $rd2 close
 | |
|     }
 | |
| 
 | |
|     test "Test may-replicate commands are rejected in RO scripts" {
 | |
|         # that's specifically important for CLIENT PAUSE WRITE
 | |
|         assert_error {ERR Write commands are not allowed from read-only scripts. script:*} {
 | |
|             r EVAL_RO "return redis.call('publish','ch','msg')" 0
 | |
|         }
 | |
|         assert_error {ERR Write commands are not allowed from read-only scripts. script:*} {
 | |
|             r EVAL {#!lua flags=no-writes
 | |
|                 return redis.call('publish','ch','msg')
 | |
|             } 0
 | |
|         }
 | |
|         # make sure that publish isn't blocked from a non-RO script
 | |
|         assert_equal [r EVAL "return redis.call('publish','ch','msg')" 0] 0
 | |
|     }
 | |
| 
 | |
|     test "Test multiple clients can be queued up and unblocked" {
 | |
|         r client PAUSE 60000 WRITE
 | |
|         set clients [list [redis_deferring_client] [redis_deferring_client] [redis_deferring_client]]
 | |
|         foreach client $clients {
 | |
|             $client SET FOO BAR
 | |
|         }
 | |
| 
 | |
|         wait_for_blocked_clients_count 3 50 100
 | |
|         r client unpause
 | |
|         foreach client $clients {
 | |
|             assert_match "OK" [$client read]
 | |
|             $client close
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     test "Test clients with syntax errors will get responses immediately" {
 | |
|         r client PAUSE 100000 WRITE
 | |
|         catch {r set FOO} err
 | |
|         assert_match "ERR wrong number of arguments for 'set' command" $err
 | |
|         r client unpause
 | |
|     }
 | |
| 
 | |
|     test "Test both active and passive expires are skipped during client pause" {
 | |
|         set expired_keys [s 0 expired_keys]
 | |
|         r multi
 | |
|         r set foo{t} bar{t} PX 10
 | |
|         r set bar{t} foo{t} PX 10
 | |
|         r client PAUSE 50000 WRITE
 | |
|         r exec
 | |
| 
 | |
|         wait_for_condition 10 100 {
 | |
|             [r get foo{t}] == {} && [r get bar{t}] == {}
 | |
|         } else {
 | |
|             fail "Keys were never logically expired"
 | |
|         }
 | |
| 
 | |
|         # No keys should actually have been expired
 | |
|         assert_match $expired_keys [s 0 expired_keys]
 | |
| 
 | |
|         r client unpause
 | |
| 
 | |
|         # Force the keys to expire
 | |
|         r get foo{t}
 | |
|         r get bar{t}
 | |
| 
 | |
|         # Now that clients have been unpaused, expires should go through
 | |
|         assert_match [expr $expired_keys + 2] [s 0 expired_keys]   
 | |
|     }
 | |
| 
 | |
|     test "Test that client pause starts at the end of a transaction" {
 | |
|         r MULTI
 | |
|         r SET FOO1{t} BAR
 | |
|         r client PAUSE 60000 WRITE
 | |
|         r SET FOO2{t} BAR
 | |
|         r exec
 | |
| 
 | |
|         set rd [redis_deferring_client]
 | |
|         $rd SET FOO3{t} BAR
 | |
| 
 | |
|         wait_for_blocked_clients_count 1 50 100
 | |
| 
 | |
|         assert_match "BAR" [r GET FOO1{t}]
 | |
|         assert_match "BAR" [r GET FOO2{t}]
 | |
|         assert_match "" [r GET FOO3{t}]
 | |
| 
 | |
|         r client unpause 
 | |
|         assert_match "OK" [$rd read]
 | |
|         $rd close
 | |
|     }
 | |
| 
 | |
|     start_server {tags {needs:repl external:skip}} {
 | |
|         set master [srv -1 client]
 | |
|         set master_host [srv -1 host]
 | |
|         set master_port [srv -1 port]
 | |
| 
 | |
|         # Avoid PINGs
 | |
|         $master config set repl-ping-replica-period 3600
 | |
|         r replicaof $master_host $master_port
 | |
| 
 | |
|         wait_for_condition 50 100 {
 | |
|             [s master_link_status] eq {up}
 | |
|         } else {
 | |
|             fail "Replication not started."
 | |
|         }
 | |
| 
 | |
|         test "Test when replica paused, offset would not grow" {
 | |
|             $master set foo bar
 | |
|             set old_master_offset [status $master master_repl_offset]
 | |
| 
 | |
|             wait_for_condition 50 100 {
 | |
|                 [s slave_repl_offset] == [status $master master_repl_offset]
 | |
|             } else {
 | |
|                 fail "Replication offset not matched."
 | |
|             }
 | |
| 
 | |
|             r client pause 100000 write
 | |
|             $master set foo2 bar2
 | |
| 
 | |
|             # Make sure replica received data from master
 | |
|             wait_for_condition 50 100 {
 | |
|                 [s slave_read_repl_offset] == [status $master master_repl_offset]
 | |
|             } else {
 | |
|                 fail "Replication not work."
 | |
|             }
 | |
| 
 | |
|             # Replica would not apply the write command
 | |
|             assert {[s slave_repl_offset] == $old_master_offset}
 | |
|             r get foo2
 | |
|         } {}
 | |
| 
 | |
|         test "Test replica offset would grow after unpause" {
 | |
|             r client unpause
 | |
|             wait_for_condition 50 100 {
 | |
|                 [s slave_repl_offset] == [status $master master_repl_offset]
 | |
|             } else {
 | |
|                 fail "Replication not continue."
 | |
|             }
 | |
|             r get foo2
 | |
|         } {bar2}
 | |
|     }
 | |
| 
 | |
|     # Make sure we unpause at the end
 | |
|     r client unpause
 | |
| }
 |