@@ -2,15 +2,19 @@ package redis_test
22
33import (
44 "context"
5+ "crypto/tls"
6+ "errors"
57 "fmt"
68 "net"
79 "strconv"
810 "strings"
911 "sync"
12+ "testing"
1013 "time"
1114
1215 . "github.com/onsi/ginkgo"
1316 . "github.com/onsi/gomega"
17+ "github.com/stretchr/testify/assert"
1418
1519 "github.com/go-redis/redis/v9"
1620 "github.com/go-redis/redis/v9/internal/hashtag"
@@ -1296,3 +1300,138 @@ var _ = Describe("ClusterClient timeout", func() {
12961300 testTimeout ()
12971301 })
12981302})
1303+
1304+ func TestParseClusterURL (t * testing.T ) {
1305+ cases := []struct {
1306+ test string
1307+ url string
1308+ o * redis.ClusterOptions // expected value
1309+ err error
1310+ }{
1311+ {
1312+ test : "ParseRedisURL" ,
1313+ url : "redis://localhost:123" ,
1314+ o : & redis.ClusterOptions {Addrs : []string {"localhost:123" }},
1315+ }, {
1316+ test : "ParseRedissURL" ,
1317+ url : "rediss://localhost:123" ,
1318+ o : & redis.ClusterOptions {Addrs : []string {"localhost:123" }, TLSConfig : & tls.Config {ServerName : "localhost" }},
1319+ }, {
1320+ test : "MissingRedisPort" ,
1321+ url : "redis://localhost" ,
1322+ o : & redis.ClusterOptions {Addrs : []string {"localhost:6379" }},
1323+ }, {
1324+ test : "MissingRedissPort" ,
1325+ url : "rediss://localhost" ,
1326+ o : & redis.ClusterOptions {Addrs : []string {"localhost:6379" }, TLSConfig : & tls.Config {ServerName : "localhost" }},
1327+ }, {
1328+ test : "MultipleRedisURLs" ,
1329+ url : "redis://localhost:123?addr=localhost:1234&addr=localhost:12345" ,
1330+ o : & redis.ClusterOptions {Addrs : []string {"localhost:123" , "localhost:1234" , "localhost:12345" }},
1331+ }, {
1332+ test : "MultipleRedissURLs" ,
1333+ url : "rediss://localhost:123?addr=localhost:1234&addr=localhost:12345" ,
1334+ o : & redis.ClusterOptions {Addrs : []string {"localhost:123" , "localhost:1234" , "localhost:12345" }, TLSConfig : & tls.Config {ServerName : "localhost" }},
1335+ }, {
1336+ test : "OnlyPassword" ,
1337+ url : "redis://:bar@localhost:123" ,
1338+ o : & redis.ClusterOptions {Addrs : []string {"localhost:123" }, Password : "bar" },
1339+ }, {
1340+ test : "OnlyUser" ,
1341+ url : "redis://foo@localhost:123" ,
1342+ o : & redis.ClusterOptions {Addrs : []string {"localhost:123" }, Username : "foo" },
1343+ }, {
1344+ test : "RedisUsernamePassword" ,
1345+ url : "redis://foo:bar@localhost:123" ,
1346+ o : & redis.ClusterOptions {Addrs : []string {"localhost:123" }, Username : "foo" , Password : "bar" },
1347+ }, {
1348+ test : "RedissUsernamePassword" ,
1349+ url : "rediss://foo:bar@localhost:123?addr=localhost:1234" ,
1350+ o : & redis.ClusterOptions {Addrs : []string {"localhost:123" , "localhost:1234" }, Username : "foo" , Password : "bar" , TLSConfig : & tls.Config {ServerName : "localhost" }},
1351+ }, {
1352+ test : "QueryParameters" ,
1353+ url : "redis://localhost:123?read_timeout=2&pool_fifo=true&addr=localhost:1234" ,
1354+ o : & redis.ClusterOptions {Addrs : []string {"localhost:123" , "localhost:1234" }, ReadTimeout : 2 * time .Second , PoolFIFO : true },
1355+ }, {
1356+ test : "DisabledTimeout" ,
1357+ url : "redis://localhost:123?conn_max_idle_time=0" ,
1358+ o : & redis.ClusterOptions {Addrs : []string {"localhost:123" }, ConnMaxIdleTime : - 1 },
1359+ }, {
1360+ test : "DisabledTimeoutNeg" ,
1361+ url : "redis://localhost:123?conn_max_idle_time=-1" ,
1362+ o : & redis.ClusterOptions {Addrs : []string {"localhost:123" }, ConnMaxIdleTime : - 1 },
1363+ }, {
1364+ test : "UseDefault" ,
1365+ url : "redis://localhost:123?conn_max_idle_time=" ,
1366+ o : & redis.ClusterOptions {Addrs : []string {"localhost:123" }, ConnMaxIdleTime : 0 },
1367+ }, {
1368+ test : "UseDefaultMissing=" ,
1369+ url : "redis://localhost:123?conn_max_idle_time" ,
1370+ o : & redis.ClusterOptions {Addrs : []string {"localhost:123" }, ConnMaxIdleTime : 0 },
1371+ }, {
1372+ test : "InvalidQueryAddr" ,
1373+ url : "rediss://foo:bar@localhost:123?addr=rediss://foo:barr@localhost:1234" ,
1374+ err : errors .New (`redis: unable to parse addr param: rediss://foo:barr@localhost:1234` ),
1375+ }, {
1376+ test : "InvalidInt" ,
1377+ url : "redis://localhost?pool_size=five" ,
1378+ err : errors .New (`redis: invalid pool_size number: strconv.Atoi: parsing "five": invalid syntax` ),
1379+ }, {
1380+ test : "InvalidBool" ,
1381+ url : "redis://localhost?pool_fifo=yes" ,
1382+ err : errors .New (`redis: invalid pool_fifo boolean: expected true/false/1/0 or an empty string, got "yes"` ),
1383+ }, {
1384+ test : "UnknownParam" ,
1385+ url : "redis://localhost?abc=123" ,
1386+ err : errors .New ("redis: unexpected option: abc" ),
1387+ }, {
1388+ test : "InvalidScheme" ,
1389+ url : "https://google.com" ,
1390+ err : errors .New ("redis: invalid URL scheme: https" ),
1391+ },
1392+ }
1393+
1394+ for i := range cases {
1395+ tc := cases [i ]
1396+ t .Run (tc .test , func (t * testing.T ) {
1397+ t .Parallel ()
1398+
1399+ actual , err := redis .ParseClusterURL (tc .url )
1400+ if tc .err == nil && err != nil {
1401+ t .Fatalf ("unexpected error: %q" , err )
1402+ return
1403+ }
1404+ if tc .err != nil && err == nil {
1405+ t .Fatalf ("expected error: got %+v" , actual )
1406+ return
1407+ }
1408+ if tc .err != nil && err != nil {
1409+ if tc .err .Error () != err .Error () {
1410+ t .Fatalf ("got %q, expected %q" , err , tc .err )
1411+ }
1412+ return
1413+ }
1414+ comprareOptions (t , actual , tc .o )
1415+ })
1416+ }
1417+ }
1418+
1419+ func comprareOptions (t * testing.T , actual , expected * redis.ClusterOptions ) {
1420+ t .Helper ()
1421+ assert .Equal (t , expected .Addrs , actual .Addrs )
1422+ assert .Equal (t , expected .TLSConfig , actual .TLSConfig )
1423+ assert .Equal (t , expected .Username , actual .Username )
1424+ assert .Equal (t , expected .Password , actual .Password )
1425+ assert .Equal (t , expected .MaxRetries , actual .MaxRetries )
1426+ assert .Equal (t , expected .MinRetryBackoff , actual .MinRetryBackoff )
1427+ assert .Equal (t , expected .MaxRetryBackoff , actual .MaxRetryBackoff )
1428+ assert .Equal (t , expected .DialTimeout , actual .DialTimeout )
1429+ assert .Equal (t , expected .ReadTimeout , actual .ReadTimeout )
1430+ assert .Equal (t , expected .WriteTimeout , actual .WriteTimeout )
1431+ assert .Equal (t , expected .PoolFIFO , actual .PoolFIFO )
1432+ assert .Equal (t , expected .PoolSize , actual .PoolSize )
1433+ assert .Equal (t , expected .MinIdleConns , actual .MinIdleConns )
1434+ assert .Equal (t , expected .ConnMaxLifetime , actual .ConnMaxLifetime )
1435+ assert .Equal (t , expected .ConnMaxIdleTime , actual .ConnMaxIdleTime )
1436+ assert .Equal (t , expected .PoolTimeout , actual .PoolTimeout )
1437+ }
0 commit comments