mirror of
https://github.com/valkey-io/valkey.git
synced 2026-07-30 05:03:58 -04:00
`availability_zone` was added to the HELLO command in #1487, and it was missing the reply schema and the test was wrongly marked with `logreqres:skip`. `availability-zone` was added to CLUSTER SHARDS and CLUSTER SLOTS commands in #3156, and it was missing the reply schema. --------- Signed-off-by: Binbin <[email protected]>
376 lines
12 KiB
Tcl
376 lines
12 KiB
Tcl
start_server {tags {"protocol network"}} {
|
|
test "Handle an empty query" {
|
|
reconnect
|
|
r write "\r\n"
|
|
r flush
|
|
assert_equal "PONG" [r ping]
|
|
}
|
|
|
|
test "Handle an empty query in pipeline" {
|
|
reconnect
|
|
r write "\r\n*1\r\n\$4\r\nping\r\n"
|
|
r flush
|
|
assert_equal PONG [r read]
|
|
}
|
|
|
|
test "Negative multibulk length" {
|
|
reconnect
|
|
r write "*-10\r\n"
|
|
r flush
|
|
assert_equal PONG [r ping]
|
|
}
|
|
|
|
test "Negative multibulk length in pipeline" {
|
|
reconnect
|
|
r write "*-10\r\n*1\r\n\$4\r\nping\r\n"
|
|
r flush
|
|
assert_equal PONG [r read]
|
|
}
|
|
|
|
test "Out of range multibulk length" {
|
|
reconnect
|
|
r write "*3000000000\r\n"
|
|
r flush
|
|
assert_error "*invalid multibulk length*" {r read}
|
|
}
|
|
|
|
test "Wrong multibulk payload header" {
|
|
reconnect
|
|
r write "*3\r\n\$3\r\nSET\r\n\$1\r\nx\r\nfooz\r\n"
|
|
r flush
|
|
assert_error "*expected '$', got 'f'*" {r read}
|
|
}
|
|
|
|
test "Negative multibulk payload length" {
|
|
reconnect
|
|
r write "*3\r\n\$3\r\nSET\r\n\$1\r\nx\r\n\$-10\r\n"
|
|
r flush
|
|
assert_error "*invalid bulk length*" {r read}
|
|
}
|
|
|
|
test "Out of range multibulk payload length" {
|
|
reconnect
|
|
r write "*3\r\n\$3\r\nSET\r\n\$1\r\nx\r\n\$2000000000\r\n"
|
|
r flush
|
|
assert_error "*invalid bulk length*" {r read}
|
|
}
|
|
|
|
test "Non-number multibulk payload length" {
|
|
reconnect
|
|
r write "*3\r\n\$3\r\nSET\r\n\$1\r\nx\r\n\$blabla\r\n"
|
|
r flush
|
|
assert_error "*invalid bulk length*" {r read}
|
|
}
|
|
|
|
test "Multi bulk request not followed by bulk arguments" {
|
|
reconnect
|
|
r write "*1\r\nfoo\r\n"
|
|
r flush
|
|
assert_error "*expected '$', got 'f'*" {r read}
|
|
}
|
|
|
|
test "Generic wrong number of args" {
|
|
reconnect
|
|
assert_error "*wrong*arguments*ping*" {r ping x y z}
|
|
}
|
|
|
|
test "Mixing quoted and unquoted strings" {
|
|
reconnect
|
|
r write "set \"\"\"tes\"t-'k'e\"y\" \"test\"'-'value\r\n"
|
|
r write "get test'-'key\r\n"
|
|
r flush
|
|
assert_equal "OK" [r read]
|
|
assert_equal "test-value" [r read]
|
|
}
|
|
|
|
test "Unbalanced single quotes" {
|
|
reconnect
|
|
r write "set foo 'b'a'r\r\n"
|
|
r write "ping\r\n"
|
|
r flush
|
|
assert_error "*unbalanced*" {r read}
|
|
}
|
|
|
|
test "Unbalanced double quotes" {
|
|
reconnect
|
|
r write "set foo \"b\"a\"r\r\n"
|
|
r write "ping\r\n"
|
|
r flush
|
|
assert_error "*unbalanced*" {r read}
|
|
}
|
|
|
|
test "Check CRLF when parsing the querybuf" {
|
|
# Command) SET key value
|
|
# RESP) *3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n
|
|
# We need to strictly check these \r\n characters.
|
|
set proto "*3\r\n\$3\r\nSET\r\n\$3\r\nkey\r\n\$5\r\nvalue\r\n"
|
|
reconnect; r write $proto; r flush; assert_equal "OK" [r read]
|
|
|
|
# Check if multibulklen `*3\r\n` is followed by `\r\n`
|
|
set proto1 "*3x\n\$3\r\nSET\r\n\$3\r\nkey\r\n\$5\r\nvalue\r\n"
|
|
set proto2 "*3\rx\$3\r\nSET\r\n\$3\r\nkey\r\n\$5\r\nvalue\r\n"
|
|
set proto3 "*3xx\$3\r\nSET\r\n\$3\r\nkey\r\n\$5\r\nvalue\r\n"
|
|
r write $proto1; r flush; assert_error "*invalid multibulk length*" {r read}; reconnect
|
|
r write $proto2; r flush; assert_error "*invalid CRLF in request*" {r read}; reconnect
|
|
r write $proto3; r flush; assert_error "*invalid multibulk length*" {r read}; reconnect
|
|
|
|
# Check if bulklen `$3\r\n` is followed by `\r\n`
|
|
set proto1 "*3\r\n\$3x\nSET\r\n\$3\r\nkey\r\n\$5\r\nvalue\r\n"
|
|
set proto2 "*3\r\n\$3\rxSET\r\n\$3\r\nkey\r\n\$5\r\nvalue\r\n"
|
|
set proto3 "*3\r\n\$3xxSET\r\n\$3\r\nkey\r\n\$5\r\nvalue\r\n"
|
|
r write $proto1; r flush; assert_error "*invalid bulk length*" {r read}; reconnect
|
|
r write $proto2; r flush; assert_error "*invalid CRLF in request*" {r read}; reconnect
|
|
r write $proto3; r flush; assert_error "*invalid bulk length*" {r read}; reconnect
|
|
|
|
# Check if `SET\r\n` is followed by `\r\n`
|
|
set proto1 "*3\r\n\$3\r\nSET\rx\$3\r\nkey\r\n\$5\r\nvalue\r\n"
|
|
set proto2 "*3\r\n\$3\r\nSETx\n\$3\r\nkey\r\n\$5\r\nvalue\r\n"
|
|
set proto3 "*3\r\n\$3\r\nSETxx\$3\r\nkey\r\n\$5\r\nvalue\r\n"
|
|
r write $proto1; r flush; assert_error "*invalid CRLF in request*" {r read}; reconnect
|
|
r write $proto2; r flush; assert_error "*invalid CRLF in request*" {r read}; reconnect
|
|
r write $proto3; r flush; assert_error "*invalid CRLF in request*" {r read}; reconnect
|
|
|
|
# Check if `key\r\n` is followed by `\r\n`
|
|
set proto1 "*3\r\n\$3\r\nSET\r\n\$3\r\nkeyx\n\$5\r\nvalue\r\n"
|
|
set proto2 "*3\r\n\$3\r\nSET\r\n\$3\r\nkey\rx\$5\r\nvalue\r\n"
|
|
set proto3 "*3\r\n\$3\r\nSET\r\n\$3\r\nkeyxx\$5\r\nvalue\r\n"
|
|
r write $proto1; r flush; assert_error "*invalid CRLF in request*" {r read}; reconnect
|
|
r write $proto2; r flush; assert_error "*invalid CRLF in request*" {r read}; reconnect
|
|
r write $proto3; r flush; assert_error "*invalid CRLF in request*" {r read}; reconnect
|
|
|
|
# Check if bulklen `$5\r\n` is followed by `\r\n`
|
|
set proto1 "*3\r\n\$3\r\nSET\r\n\$3\r\nkey\r\n\$5x\nvalue\r\n"
|
|
set proto2 "*3\r\n\$3\r\nSET\r\n\$3\r\nkey\r\n\$5\rxvalue\r\n"
|
|
set proto3 "*3\r\n\$3\r\nSET\r\n\$3\r\nkey\r\n\$5xxvalue\r\n"
|
|
r write $proto1; r flush; assert_error "*invalid bulk length*" {r read}; reconnect
|
|
r write $proto2; r flush; assert_error "*invalid CRLF in request*" {r read}; reconnect
|
|
r write $proto3; r flush; assert_error "*invalid bulk length*" {r read}; reconnect
|
|
|
|
# Check if `value\r\n` is followed by `\r\n`
|
|
set proto1 "*3\r\n\$3\r\nSET\r\n\$3\r\nkey\r\n\$5\r\nvaluex\n"
|
|
set proto2 "*3\r\n\$3\r\nSET\r\n\$3\r\nkey\r\n\$5\r\nvalue\rx"
|
|
set proto3 "*3\r\n\$3\r\nSET\r\n\$3\r\nkey\r\n\$5\r\nvaluexx"
|
|
r write $proto1; r flush; assert_error "*invalid CRLF in request*" {r read}; reconnect
|
|
r write $proto2; r flush; assert_error "*invalid CRLF in request*" {r read}; reconnect
|
|
r write $proto3; r flush; assert_error "*invalid CRLF in request*" {r read}; reconnect
|
|
}
|
|
|
|
set c 0
|
|
foreach seq [list "\x00" "*\x00" "$\x00" "*1\r\n$\x00"] {
|
|
incr c
|
|
test "Protocol desync regression test #$c" {
|
|
if {$::tls} {
|
|
set s [::tls::socket [srv 0 host] [srv 0 port]]
|
|
} else {
|
|
set s [socket [srv 0 host] [srv 0 port]]
|
|
}
|
|
fconfigure $s -translation binary
|
|
puts -nonewline $s $seq
|
|
# PROTO_INLINE_MAX_SIZE is hardcoded in Valkey code to 64K. doing the same here
|
|
# since we would like to validate it is enforced.
|
|
set PROTO_INLINE_MAX_SIZE [expr 1024 * 64]
|
|
set payload [string repeat A 1024]
|
|
set payload_size 0
|
|
while {$payload_size <= $PROTO_INLINE_MAX_SIZE} {
|
|
if {[catch {
|
|
incr payload_size [string length $payload]
|
|
puts -nonewline $s $payload
|
|
flush $s
|
|
}]} {
|
|
assert_morethan $payload_size $PROTO_INLINE_MAX_SIZE
|
|
break
|
|
}
|
|
}
|
|
assert_match {*Protocol error*} [gets $s]]
|
|
close $s
|
|
}
|
|
}
|
|
unset c
|
|
|
|
# recover the broken connection
|
|
reconnect
|
|
r ping
|
|
|
|
# raw RESP response tests
|
|
r readraw 1
|
|
|
|
set nullres {*-1}
|
|
if {$::force_resp3} {
|
|
set nullres {_}
|
|
}
|
|
|
|
test "raw protocol response" {
|
|
r srandmember nonexisting_key
|
|
} "$nullres"
|
|
|
|
r deferred 1
|
|
|
|
test "raw protocol response - deferred" {
|
|
r srandmember nonexisting_key
|
|
r read
|
|
} "$nullres"
|
|
|
|
test "raw protocol response - multiline" {
|
|
r sadd ss a
|
|
assert_equal [r read] {:1}
|
|
r srandmember ss 100
|
|
assert_equal [r read] {*1}
|
|
assert_equal [r read] {$1}
|
|
assert_equal [r read] {a}
|
|
}
|
|
|
|
# restore connection settings
|
|
r readraw 0
|
|
r deferred 0
|
|
|
|
# check the connection still works
|
|
assert_equal [r ping] {PONG}
|
|
|
|
test {RESP3 attributes} {
|
|
r hello 3
|
|
assert_equal {Some real reply following the attribute} [r debug protocol attrib]
|
|
assert_equal {key-popularity {key:123 90}} [r attributes]
|
|
|
|
# make sure attributes are not kept from previous command
|
|
r ping
|
|
assert_error {*attributes* no such element in array} {r attributes}
|
|
|
|
# restore state
|
|
r hello 2
|
|
set _ ""
|
|
} {} {needs:debug resp3}
|
|
|
|
test {RESP3 attributes readraw} {
|
|
r hello 3
|
|
r readraw 1
|
|
r deferred 1
|
|
|
|
r debug protocol attrib
|
|
assert_equal [r read] {|1}
|
|
assert_equal [r read] {$14}
|
|
assert_equal [r read] {key-popularity}
|
|
assert_equal [r read] {*2}
|
|
assert_equal [r read] {$7}
|
|
assert_equal [r read] {key:123}
|
|
assert_equal [r read] {:90}
|
|
assert_equal [r read] {$39}
|
|
assert_equal [r read] {Some real reply following the attribute}
|
|
|
|
# restore state
|
|
r readraw 0
|
|
r deferred 0
|
|
r hello 2
|
|
set _ {}
|
|
} {} {needs:debug resp3}
|
|
|
|
test {RESP3 attributes on RESP2} {
|
|
r hello 2
|
|
set res [r debug protocol attrib]
|
|
set _ $res
|
|
} {Some real reply following the attribute} {needs:debug}
|
|
|
|
test "test big number parsing" {
|
|
r hello 3
|
|
r debug protocol bignum
|
|
} {1234567999999999999999999999999999999} {needs:debug resp3}
|
|
|
|
test "test bool parsing" {
|
|
r hello 3
|
|
assert_equal [r debug protocol true] 1
|
|
assert_equal [r debug protocol false] 0
|
|
r hello 2
|
|
assert_equal [r debug protocol true] 1
|
|
assert_equal [r debug protocol false] 0
|
|
set _ {}
|
|
} {} {needs:debug resp3}
|
|
|
|
test "test verbatim str parsing" {
|
|
r hello 3
|
|
r debug protocol verbatim
|
|
} "This is a verbatim\nstring" {needs:debug resp3}
|
|
|
|
test "test large number of args" {
|
|
r flushdb
|
|
set args [split [string trim [string repeat "k v " 10000]]]
|
|
lappend args "{k}2" v2
|
|
r mset {*}$args
|
|
assert_equal [r get "{k}2"] v2
|
|
}
|
|
|
|
test "test argument rewriting - issue 9598" {
|
|
# INCRBYFLOAT uses argument rewriting for correct float value propagation.
|
|
# We use it to make sure argument rewriting works properly. It's important
|
|
# this test is run under valgrind to verify there are no memory leaks in
|
|
# arg buffer handling.
|
|
r flushdb
|
|
|
|
# Test normal argument handling
|
|
r set k 0
|
|
assert_equal [r incrbyfloat k 1.0] 1
|
|
|
|
# Test argument handing in multi-state buffers
|
|
r multi
|
|
r incrbyfloat k 1.0
|
|
assert_equal [r exec] 2
|
|
}
|
|
|
|
}
|
|
|
|
start_server {tags {"protocol hello"}} {
|
|
test {HELLO without protover} {
|
|
set reply [r HELLO 3]
|
|
assert_equal [dict get $reply proto] 3
|
|
|
|
set reply [r HELLO]
|
|
assert_equal [dict get $reply proto] 3
|
|
|
|
set reply [r HELLO 2]
|
|
assert_equal [dict get $reply proto] [expr $::force_resp3 ? 3 : 2]
|
|
|
|
set reply [r HELLO]
|
|
assert_equal [dict get $reply proto] [expr $::force_resp3 ? 3 : 2]
|
|
}
|
|
|
|
test {HELLO and availability-zone} {
|
|
r CONFIG SET availability-zone myzone
|
|
|
|
set reply [r HELLO 3]
|
|
assert_equal [dict get $reply availability_zone] myzone
|
|
|
|
set reply [r HELLO 2]
|
|
assert_equal [dict get $reply availability_zone] myzone
|
|
|
|
r CONFIG SET availability-zone ""
|
|
|
|
set reply [r HELLO 3]
|
|
assert_equal [dict exists $reply availability_zone] 0
|
|
|
|
set reply [r HELLO 2]
|
|
assert_equal [dict exists $reply availability_zone] 0
|
|
}
|
|
}
|
|
|
|
start_server {tags {"regression"}} {
|
|
test "Regression for a crash on zero-length multibulk" {
|
|
reconnect
|
|
r write "*0\r\nPING\r\n"
|
|
r flush
|
|
assert_equal "PONG" [r ping]
|
|
}
|
|
|
|
test "Regression for a crash with blocking ops and pipelining" {
|
|
set rd [valkey_deferring_client]
|
|
set fd [r channel]
|
|
set proto "*3\r\n\$5\r\nBLPOP\r\n\$6\r\nnolist\r\n\$1\r\n0\r\n"
|
|
puts -nonewline $fd $proto$proto
|
|
flush $fd
|
|
set res {}
|
|
|
|
$rd rpush nolist a
|
|
$rd read
|
|
$rd rpush nolist a
|
|
$rd read
|
|
$rd close
|
|
}
|
|
}
|