mirror of
https://github.com/redis/go-redis.git
synced 2026-10-24 07:59:20 +03:00
SetArgs always sent ExpireAt as EXAT with Unix seconds, so any millisecond part was silently dropped. Send PXAT with Unix milliseconds when ExpireAt has millisecond precision, and keep EXAT otherwise.
220 lines
5.6 KiB
Go
220 lines
5.6 KiB
Go
package redis
|
|
|
|
import (
|
|
"context"
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// captureCmdable returns a cmdable that records the Cmder passed to it without
|
|
// dispatching the command. Used to assert that command builders produce the
|
|
// expected argument list.
|
|
func captureCmdable(out *Cmder) cmdable {
|
|
return func(_ context.Context, cmd Cmder) error {
|
|
*out = cmd
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func TestIncrEXInt_Args(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
args IncrEXIntArgs
|
|
want []interface{}
|
|
}{
|
|
{
|
|
name: "default",
|
|
args: IncrEXIntArgs{},
|
|
want: []interface{}{"increx", "key"},
|
|
},
|
|
{
|
|
name: "byint",
|
|
args: IncrEXIntArgs{By: 4, HasBy: true},
|
|
want: []interface{}{"increx", "key", "byint", int64(4)},
|
|
},
|
|
{
|
|
name: "byint_zero_explicit",
|
|
args: IncrEXIntArgs{By: 0, HasBy: true},
|
|
want: []interface{}{"increx", "key", "byint", int64(0)},
|
|
},
|
|
{
|
|
name: "lbound_ubound",
|
|
args: IncrEXIntArgs{
|
|
By: 2, HasBy: true,
|
|
LBound: 0, HasLBound: true,
|
|
UBound: 20, HasUBound: true,
|
|
},
|
|
want: []interface{}{"increx", "key", "byint", int64(2), "lbound", int64(0), "ubound", int64(20)},
|
|
},
|
|
{
|
|
name: "lbound_zero_is_sent",
|
|
args: IncrEXIntArgs{
|
|
LBound: 0, HasLBound: true,
|
|
},
|
|
want: []interface{}{"increx", "key", "lbound", int64(0)},
|
|
},
|
|
{
|
|
name: "ex_and_enx",
|
|
args: IncrEXIntArgs{
|
|
By: 2, HasBy: true,
|
|
Expiration: &ExpirationOption{Mode: EX, Value: 60},
|
|
ENX: true,
|
|
},
|
|
want: []interface{}{"increx", "key", "byint", int64(2), "ex", int64(60), "enx"},
|
|
},
|
|
{
|
|
name: "px",
|
|
args: IncrEXIntArgs{Expiration: &ExpirationOption{Mode: PX, Value: 1500}},
|
|
want: []interface{}{"increx", "key", "px", int64(1500)},
|
|
},
|
|
{
|
|
name: "exat",
|
|
args: IncrEXIntArgs{Expiration: &ExpirationOption{Mode: EXAT, Value: 1753265054}},
|
|
want: []interface{}{"increx", "key", "exat", int64(1753265054)},
|
|
},
|
|
{
|
|
name: "pxat",
|
|
args: IncrEXIntArgs{Expiration: &ExpirationOption{Mode: PXAT, Value: 1753265054014}},
|
|
want: []interface{}{"increx", "key", "pxat", int64(1753265054014)},
|
|
},
|
|
{
|
|
name: "persist",
|
|
args: IncrEXIntArgs{Expiration: &ExpirationOption{Mode: PERSIST}},
|
|
want: []interface{}{"increx", "key", "persist"},
|
|
},
|
|
{
|
|
name: "saturate_with_lbound",
|
|
args: IncrEXIntArgs{
|
|
By: 1, HasBy: true,
|
|
LBound: 10, HasLBound: true,
|
|
Saturate: true,
|
|
},
|
|
want: []interface{}{"increx", "key", "byint", int64(1), "lbound", int64(10), "saturate"},
|
|
},
|
|
{
|
|
name: "saturate_with_ubound",
|
|
args: IncrEXIntArgs{
|
|
By: 5, HasBy: true,
|
|
UBound: 12, HasUBound: true,
|
|
Saturate: true,
|
|
},
|
|
want: []interface{}{"increx", "key", "byint", int64(5), "ubound", int64(12), "saturate"},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
var captured Cmder
|
|
c := captureCmdable(&captured)
|
|
cmd := c.IncrEXInt(context.Background(), "key", tt.args)
|
|
if cmd == nil {
|
|
t.Fatalf("IncrEXInt returned nil")
|
|
}
|
|
if !reflect.DeepEqual(cmd.Args(), tt.want) {
|
|
t.Errorf("args mismatch\n got: %#v\nwant: %#v", cmd.Args(), tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestIncrEXFloat_Args(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
args IncrEXFloatArgs
|
|
want []interface{}
|
|
}{
|
|
{
|
|
name: "default_zero_by",
|
|
args: IncrEXFloatArgs{},
|
|
want: []interface{}{"increx", "key", "byfloat", float64(0)},
|
|
},
|
|
{
|
|
name: "byfloat",
|
|
args: IncrEXFloatArgs{By: 0.25},
|
|
want: []interface{}{"increx", "key", "byfloat", 0.25},
|
|
},
|
|
{
|
|
name: "bounds_and_saturate",
|
|
args: IncrEXFloatArgs{
|
|
By: 0.7,
|
|
UBound: 2, HasUBound: true,
|
|
Saturate: true,
|
|
},
|
|
want: []interface{}{"increx", "key", "byfloat", 0.7, "ubound", float64(2), "saturate"},
|
|
},
|
|
{
|
|
name: "lbound_ubound",
|
|
args: IncrEXFloatArgs{
|
|
By: 0.5,
|
|
LBound: -1.5, HasLBound: true,
|
|
UBound: 1.5, HasUBound: true,
|
|
},
|
|
want: []interface{}{"increx", "key", "byfloat", 0.5, "lbound", -1.5, "ubound", 1.5},
|
|
},
|
|
{
|
|
name: "ex_and_enx",
|
|
args: IncrEXFloatArgs{
|
|
By: 1.5,
|
|
Expiration: &ExpirationOption{Mode: EX, Value: 30},
|
|
ENX: true,
|
|
},
|
|
want: []interface{}{"increx", "key", "byfloat", 1.5, "ex", int64(30), "enx"},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
var captured Cmder
|
|
c := captureCmdable(&captured)
|
|
cmd := c.IncrEXFloat(context.Background(), "key", tt.args)
|
|
if cmd == nil {
|
|
t.Fatalf("IncrEXFloat returned nil")
|
|
}
|
|
if !reflect.DeepEqual(cmd.Args(), tt.want) {
|
|
t.Errorf("args mismatch\n got: %#v\nwant: %#v", cmd.Args(), tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSetArgs_ExpireAt(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
expireAt time.Time
|
|
want []interface{}
|
|
}{
|
|
{
|
|
name: "whole_seconds",
|
|
expireAt: time.Unix(1700000000, 0),
|
|
want: []interface{}{"set", "key", "value", "exat", int64(1700000000)},
|
|
},
|
|
{
|
|
name: "sub_millisecond_is_truncated",
|
|
expireAt: time.Unix(1700000000, 500_000),
|
|
want: []interface{}{"set", "key", "value", "exat", int64(1700000000)},
|
|
},
|
|
{
|
|
name: "milliseconds",
|
|
expireAt: time.UnixMilli(1700000000123),
|
|
want: []interface{}{"set", "key", "value", "pxat", int64(1700000000123)},
|
|
},
|
|
{
|
|
name: "beyond_nanosecond_range",
|
|
expireAt: time.Date(2270, time.January, 2, 3, 4, 5, 123000000, time.UTC),
|
|
want: []interface{}{"set", "key", "value", "pxat", int64(9467204645123)},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
var cmd Cmder
|
|
c := captureCmdable(&cmd)
|
|
c.SetArgs(context.Background(), "key", "value", SetArgs{ExpireAt: tt.expireAt})
|
|
if got := cmd.Args(); !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("args = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|