@@ -2,15 +2,19 @@ package redis_test
2
2
3
3
import (
4
4
"context"
5
+ "crypto/tls"
6
+ "errors"
5
7
"fmt"
6
8
"net"
7
9
"strconv"
8
10
"strings"
9
11
"sync"
12
+ "testing"
10
13
"time"
11
14
12
15
. "github.com/onsi/ginkgo"
13
16
. "github.com/onsi/gomega"
17
+ "github.com/stretchr/testify/assert"
14
18
15
19
"github.com/go-redis/redis/v9"
16
20
"github.com/go-redis/redis/v9/internal/hashtag"
@@ -1296,3 +1300,138 @@ var _ = Describe("ClusterClient timeout", func() {
1296
1300
testTimeout ()
1297
1301
})
1298
1302
})
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