conn_test.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682
  1. // Copyright 2012 Gary Burd
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License"): you may
  4. // not use this file except in compliance with the License. You may obtain
  5. // a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  11. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  12. // License for the specific language governing permissions and limitations
  13. // under the License.
  14. package redis_test
  15. import (
  16. "bytes"
  17. "io"
  18. "math"
  19. "net"
  20. "os"
  21. "reflect"
  22. "strings"
  23. "testing"
  24. "time"
  25. "github.com/garyburd/redigo/redis"
  26. )
  27. type testConn struct {
  28. io.Reader
  29. io.Writer
  30. }
  31. func (*testConn) Close() error { return nil }
  32. func (*testConn) LocalAddr() net.Addr { return nil }
  33. func (*testConn) RemoteAddr() net.Addr { return nil }
  34. func (*testConn) SetDeadline(t time.Time) error { return nil }
  35. func (*testConn) SetReadDeadline(t time.Time) error { return nil }
  36. func (*testConn) SetWriteDeadline(t time.Time) error { return nil }
  37. func dialTestConn(r io.Reader, w io.Writer) redis.DialOption {
  38. return redis.DialNetDial(func(net, addr string) (net.Conn, error) {
  39. return &testConn{Reader: r, Writer: w}, nil
  40. })
  41. }
  42. type durationArg struct {
  43. time.Duration
  44. }
  45. func (t durationArg) RedisArg() interface{} {
  46. return t.Seconds()
  47. }
  48. var writeTests = []struct {
  49. args []interface{}
  50. expected string
  51. }{
  52. {
  53. []interface{}{"SET", "key", "value"},
  54. "*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n",
  55. },
  56. {
  57. []interface{}{"SET", "key", "value"},
  58. "*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n",
  59. },
  60. {
  61. []interface{}{"SET", "key", byte(100)},
  62. "*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$3\r\n100\r\n",
  63. },
  64. {
  65. []interface{}{"SET", "key", 100},
  66. "*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$3\r\n100\r\n",
  67. },
  68. {
  69. []interface{}{"SET", "key", int64(math.MinInt64)},
  70. "*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$20\r\n-9223372036854775808\r\n",
  71. },
  72. {
  73. []interface{}{"SET", "key", float64(1349673917.939762)},
  74. "*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$21\r\n1.349673917939762e+09\r\n",
  75. },
  76. {
  77. []interface{}{"SET", "key", ""},
  78. "*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$0\r\n\r\n",
  79. },
  80. {
  81. []interface{}{"SET", "key", nil},
  82. "*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$0\r\n\r\n",
  83. },
  84. {
  85. []interface{}{"SET", "key", durationArg{time.Minute}},
  86. "*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$2\r\n60\r\n",
  87. },
  88. {
  89. []interface{}{"ECHO", true, false},
  90. "*3\r\n$4\r\nECHO\r\n$1\r\n1\r\n$1\r\n0\r\n",
  91. },
  92. }
  93. func TestWrite(t *testing.T) {
  94. for _, tt := range writeTests {
  95. var buf bytes.Buffer
  96. c, _ := redis.Dial("", "", dialTestConn(nil, &buf))
  97. err := c.Send(tt.args[0].(string), tt.args[1:]...)
  98. if err != nil {
  99. t.Errorf("Send(%v) returned error %v", tt.args, err)
  100. continue
  101. }
  102. c.Flush()
  103. actual := buf.String()
  104. if actual != tt.expected {
  105. t.Errorf("Send(%v) = %q, want %q", tt.args, actual, tt.expected)
  106. }
  107. }
  108. }
  109. var errorSentinel = &struct{}{}
  110. var readTests = []struct {
  111. reply string
  112. expected interface{}
  113. }{
  114. {
  115. "+OK\r\n",
  116. "OK",
  117. },
  118. {
  119. "+PONG\r\n",
  120. "PONG",
  121. },
  122. {
  123. "@OK\r\n",
  124. errorSentinel,
  125. },
  126. {
  127. "$6\r\nfoobar\r\n",
  128. []byte("foobar"),
  129. },
  130. {
  131. "$-1\r\n",
  132. nil,
  133. },
  134. {
  135. ":1\r\n",
  136. int64(1),
  137. },
  138. {
  139. ":-2\r\n",
  140. int64(-2),
  141. },
  142. {
  143. "*0\r\n",
  144. []interface{}{},
  145. },
  146. {
  147. "*-1\r\n",
  148. nil,
  149. },
  150. {
  151. "*4\r\n$3\r\nfoo\r\n$3\r\nbar\r\n$5\r\nHello\r\n$5\r\nWorld\r\n",
  152. []interface{}{[]byte("foo"), []byte("bar"), []byte("Hello"), []byte("World")},
  153. },
  154. {
  155. "*3\r\n$3\r\nfoo\r\n$-1\r\n$3\r\nbar\r\n",
  156. []interface{}{[]byte("foo"), nil, []byte("bar")},
  157. },
  158. {
  159. // "x" is not a valid length
  160. "$x\r\nfoobar\r\n",
  161. errorSentinel,
  162. },
  163. {
  164. // -2 is not a valid length
  165. "$-2\r\n",
  166. errorSentinel,
  167. },
  168. {
  169. // "x" is not a valid integer
  170. ":x\r\n",
  171. errorSentinel,
  172. },
  173. {
  174. // missing \r\n following value
  175. "$6\r\nfoobar",
  176. errorSentinel,
  177. },
  178. {
  179. // short value
  180. "$6\r\nxx",
  181. errorSentinel,
  182. },
  183. {
  184. // long value
  185. "$6\r\nfoobarx\r\n",
  186. errorSentinel,
  187. },
  188. }
  189. func TestRead(t *testing.T) {
  190. for _, tt := range readTests {
  191. c, _ := redis.Dial("", "", dialTestConn(strings.NewReader(tt.reply), nil))
  192. actual, err := c.Receive()
  193. if tt.expected == errorSentinel {
  194. if err == nil {
  195. t.Errorf("Receive(%q) did not return expected error", tt.reply)
  196. }
  197. } else {
  198. if err != nil {
  199. t.Errorf("Receive(%q) returned error %v", tt.reply, err)
  200. continue
  201. }
  202. if !reflect.DeepEqual(actual, tt.expected) {
  203. t.Errorf("Receive(%q) = %v, want %v", tt.reply, actual, tt.expected)
  204. }
  205. }
  206. }
  207. }
  208. var testCommands = []struct {
  209. args []interface{}
  210. expected interface{}
  211. }{
  212. {
  213. []interface{}{"PING"},
  214. "PONG",
  215. },
  216. {
  217. []interface{}{"SET", "foo", "bar"},
  218. "OK",
  219. },
  220. {
  221. []interface{}{"GET", "foo"},
  222. []byte("bar"),
  223. },
  224. {
  225. []interface{}{"GET", "nokey"},
  226. nil,
  227. },
  228. {
  229. []interface{}{"MGET", "nokey", "foo"},
  230. []interface{}{nil, []byte("bar")},
  231. },
  232. {
  233. []interface{}{"INCR", "mycounter"},
  234. int64(1),
  235. },
  236. {
  237. []interface{}{"LPUSH", "mylist", "foo"},
  238. int64(1),
  239. },
  240. {
  241. []interface{}{"LPUSH", "mylist", "bar"},
  242. int64(2),
  243. },
  244. {
  245. []interface{}{"LRANGE", "mylist", 0, -1},
  246. []interface{}{[]byte("bar"), []byte("foo")},
  247. },
  248. {
  249. []interface{}{"MULTI"},
  250. "OK",
  251. },
  252. {
  253. []interface{}{"LRANGE", "mylist", 0, -1},
  254. "QUEUED",
  255. },
  256. {
  257. []interface{}{"PING"},
  258. "QUEUED",
  259. },
  260. {
  261. []interface{}{"EXEC"},
  262. []interface{}{
  263. []interface{}{[]byte("bar"), []byte("foo")},
  264. "PONG",
  265. },
  266. },
  267. }
  268. func TestDoCommands(t *testing.T) {
  269. c, err := redis.DialDefaultServer()
  270. if err != nil {
  271. t.Fatalf("error connection to database, %v", err)
  272. }
  273. defer c.Close()
  274. for _, cmd := range testCommands {
  275. actual, err := c.Do(cmd.args[0].(string), cmd.args[1:]...)
  276. if err != nil {
  277. t.Errorf("Do(%v) returned error %v", cmd.args, err)
  278. continue
  279. }
  280. if !reflect.DeepEqual(actual, cmd.expected) {
  281. t.Errorf("Do(%v) = %v, want %v", cmd.args, actual, cmd.expected)
  282. }
  283. }
  284. }
  285. func TestPipelineCommands(t *testing.T) {
  286. c, err := redis.DialDefaultServer()
  287. if err != nil {
  288. t.Fatalf("error connection to database, %v", err)
  289. }
  290. defer c.Close()
  291. for _, cmd := range testCommands {
  292. if err := c.Send(cmd.args[0].(string), cmd.args[1:]...); err != nil {
  293. t.Fatalf("Send(%v) returned error %v", cmd.args, err)
  294. }
  295. }
  296. if err := c.Flush(); err != nil {
  297. t.Errorf("Flush() returned error %v", err)
  298. }
  299. for _, cmd := range testCommands {
  300. actual, err := c.Receive()
  301. if err != nil {
  302. t.Fatalf("Receive(%v) returned error %v", cmd.args, err)
  303. }
  304. if !reflect.DeepEqual(actual, cmd.expected) {
  305. t.Errorf("Receive(%v) = %v, want %v", cmd.args, actual, cmd.expected)
  306. }
  307. }
  308. }
  309. func TestBlankCommmand(t *testing.T) {
  310. c, err := redis.DialDefaultServer()
  311. if err != nil {
  312. t.Fatalf("error connection to database, %v", err)
  313. }
  314. defer c.Close()
  315. for _, cmd := range testCommands {
  316. if err := c.Send(cmd.args[0].(string), cmd.args[1:]...); err != nil {
  317. t.Fatalf("Send(%v) returned error %v", cmd.args, err)
  318. }
  319. }
  320. reply, err := redis.Values(c.Do(""))
  321. if err != nil {
  322. t.Fatalf("Do() returned error %v", err)
  323. }
  324. if len(reply) != len(testCommands) {
  325. t.Fatalf("len(reply)=%d, want %d", len(reply), len(testCommands))
  326. }
  327. for i, cmd := range testCommands {
  328. actual := reply[i]
  329. if !reflect.DeepEqual(actual, cmd.expected) {
  330. t.Errorf("Receive(%v) = %v, want %v", cmd.args, actual, cmd.expected)
  331. }
  332. }
  333. }
  334. func TestRecvBeforeSend(t *testing.T) {
  335. c, err := redis.DialDefaultServer()
  336. if err != nil {
  337. t.Fatalf("error connection to database, %v", err)
  338. }
  339. defer c.Close()
  340. done := make(chan struct{})
  341. go func() {
  342. c.Receive()
  343. close(done)
  344. }()
  345. time.Sleep(time.Millisecond)
  346. c.Send("PING")
  347. c.Flush()
  348. <-done
  349. _, err = c.Do("")
  350. if err != nil {
  351. t.Fatalf("error=%v", err)
  352. }
  353. }
  354. func TestError(t *testing.T) {
  355. c, err := redis.DialDefaultServer()
  356. if err != nil {
  357. t.Fatalf("error connection to database, %v", err)
  358. }
  359. defer c.Close()
  360. c.Do("SET", "key", "val")
  361. _, err = c.Do("HSET", "key", "fld", "val")
  362. if err == nil {
  363. t.Errorf("Expected err for HSET on string key.")
  364. }
  365. if c.Err() != nil {
  366. t.Errorf("Conn has Err()=%v, expect nil", c.Err())
  367. }
  368. _, err = c.Do("SET", "key", "val")
  369. if err != nil {
  370. t.Errorf("Do(SET, key, val) returned error %v, expected nil.", err)
  371. }
  372. }
  373. func TestReadTimeout(t *testing.T) {
  374. l, err := net.Listen("tcp", "127.0.0.1:0")
  375. if err != nil {
  376. t.Fatalf("net.Listen returned %v", err)
  377. }
  378. defer l.Close()
  379. go func() {
  380. for {
  381. c, err := l.Accept()
  382. if err != nil {
  383. return
  384. }
  385. go func() {
  386. time.Sleep(time.Second)
  387. c.Write([]byte("+OK\r\n"))
  388. c.Close()
  389. }()
  390. }
  391. }()
  392. // Do
  393. c1, err := redis.Dial(l.Addr().Network(), l.Addr().String(), redis.DialReadTimeout(time.Millisecond))
  394. if err != nil {
  395. t.Fatalf("redis.Dial returned %v", err)
  396. }
  397. defer c1.Close()
  398. _, err = c1.Do("PING")
  399. if err == nil {
  400. t.Fatalf("c1.Do() returned nil, expect error")
  401. }
  402. if c1.Err() == nil {
  403. t.Fatalf("c1.Err() = nil, expect error")
  404. }
  405. // Send/Flush/Receive
  406. c2, err := redis.Dial(l.Addr().Network(), l.Addr().String(), redis.DialReadTimeout(time.Millisecond))
  407. if err != nil {
  408. t.Fatalf("redis.Dial returned %v", err)
  409. }
  410. defer c2.Close()
  411. c2.Send("PING")
  412. c2.Flush()
  413. _, err = c2.Receive()
  414. if err == nil {
  415. t.Fatalf("c2.Receive() returned nil, expect error")
  416. }
  417. if c2.Err() == nil {
  418. t.Fatalf("c2.Err() = nil, expect error")
  419. }
  420. }
  421. var dialErrors = []struct {
  422. rawurl string
  423. expectedError string
  424. }{
  425. {
  426. "localhost",
  427. "invalid redis URL scheme",
  428. },
  429. // The error message for invalid hosts is different in different
  430. // versions of Go, so just check that there is an error message.
  431. {
  432. "redis://weird url",
  433. "",
  434. },
  435. {
  436. "redis://foo:bar:baz",
  437. "",
  438. },
  439. {
  440. "http://www.google.com",
  441. "invalid redis URL scheme: http",
  442. },
  443. {
  444. "redis://localhost:6379/abc123",
  445. "invalid database: abc123",
  446. },
  447. }
  448. func TestDialURLErrors(t *testing.T) {
  449. for _, d := range dialErrors {
  450. _, err := redis.DialURL(d.rawurl)
  451. if err == nil || !strings.Contains(err.Error(), d.expectedError) {
  452. t.Errorf("DialURL did not return expected error (expected %v to contain %s)", err, d.expectedError)
  453. }
  454. }
  455. }
  456. func TestDialURLPort(t *testing.T) {
  457. checkPort := func(network, address string) (net.Conn, error) {
  458. if address != "localhost:6379" {
  459. t.Errorf("DialURL did not set port to 6379 by default (got %v)", address)
  460. }
  461. return nil, nil
  462. }
  463. _, err := redis.DialURL("redis://localhost", redis.DialNetDial(checkPort))
  464. if err != nil {
  465. t.Error("dial error:", err)
  466. }
  467. }
  468. func TestDialURLHost(t *testing.T) {
  469. checkHost := func(network, address string) (net.Conn, error) {
  470. if address != "localhost:6379" {
  471. t.Errorf("DialURL did not set host to localhost by default (got %v)", address)
  472. }
  473. return nil, nil
  474. }
  475. _, err := redis.DialURL("redis://:6379", redis.DialNetDial(checkHost))
  476. if err != nil {
  477. t.Error("dial error:", err)
  478. }
  479. }
  480. func TestDialURLPassword(t *testing.T) {
  481. var buf bytes.Buffer
  482. _, err := redis.DialURL("redis://x:abc123@localhost", dialTestConn(strings.NewReader("+OK\r\n"), &buf))
  483. if err != nil {
  484. t.Error("dial error:", err)
  485. }
  486. expected := "*2\r\n$4\r\nAUTH\r\n$6\r\nabc123\r\n"
  487. actual := buf.String()
  488. if actual != expected {
  489. t.Errorf("commands = %q, want %q", actual, expected)
  490. }
  491. }
  492. func TestDialURLDatabase(t *testing.T) {
  493. var buf3 bytes.Buffer
  494. _, err3 := redis.DialURL("redis://localhost/3", dialTestConn(strings.NewReader("+OK\r\n"), &buf3))
  495. if err3 != nil {
  496. t.Error("dial error:", err3)
  497. }
  498. expected3 := "*2\r\n$6\r\nSELECT\r\n$1\r\n3\r\n"
  499. actual3 := buf3.String()
  500. if actual3 != expected3 {
  501. t.Errorf("commands = %q, want %q", actual3, expected3)
  502. }
  503. // empty DB means 0
  504. var buf0 bytes.Buffer
  505. _, err0 := redis.DialURL("redis://localhost/", dialTestConn(strings.NewReader("+OK\r\n"), &buf0))
  506. if err0 != nil {
  507. t.Error("dial error:", err0)
  508. }
  509. expected0 := ""
  510. actual0 := buf0.String()
  511. if actual0 != expected0 {
  512. t.Errorf("commands = %q, want %q", actual0, expected0)
  513. }
  514. }
  515. // Connect to local instance of Redis running on the default port.
  516. func ExampleDial() {
  517. c, err := redis.Dial("tcp", ":6379")
  518. if err != nil {
  519. // handle error
  520. }
  521. defer c.Close()
  522. }
  523. // Connect to remote instance of Redis using a URL.
  524. func ExampleDialURL() {
  525. c, err := redis.DialURL(os.Getenv("REDIS_URL"))
  526. if err != nil {
  527. // handle connection error
  528. }
  529. defer c.Close()
  530. }
  531. // TextExecError tests handling of errors in a transaction. See
  532. // http://redis.io/topics/transactions for information on how Redis handles
  533. // errors in a transaction.
  534. func TestExecError(t *testing.T) {
  535. c, err := redis.DialDefaultServer()
  536. if err != nil {
  537. t.Fatalf("error connection to database, %v", err)
  538. }
  539. defer c.Close()
  540. // Execute commands that fail before EXEC is called.
  541. c.Do("DEL", "k0")
  542. c.Do("ZADD", "k0", 0, 0)
  543. c.Send("MULTI")
  544. c.Send("NOTACOMMAND", "k0", 0, 0)
  545. c.Send("ZINCRBY", "k0", 0, 0)
  546. v, err := c.Do("EXEC")
  547. if err == nil {
  548. t.Fatalf("EXEC returned values %v, expected error", v)
  549. }
  550. // Execute commands that fail after EXEC is called. The first command
  551. // returns an error.
  552. c.Do("DEL", "k1")
  553. c.Do("ZADD", "k1", 0, 0)
  554. c.Send("MULTI")
  555. c.Send("HSET", "k1", 0, 0)
  556. c.Send("ZINCRBY", "k1", 0, 0)
  557. v, err = c.Do("EXEC")
  558. if err != nil {
  559. t.Fatalf("EXEC returned error %v", err)
  560. }
  561. vs, err := redis.Values(v, nil)
  562. if err != nil {
  563. t.Fatalf("Values(v) returned error %v", err)
  564. }
  565. if len(vs) != 2 {
  566. t.Fatalf("len(vs) == %d, want 2", len(vs))
  567. }
  568. if _, ok := vs[0].(error); !ok {
  569. t.Fatalf("first result is type %T, expected error", vs[0])
  570. }
  571. if _, ok := vs[1].([]byte); !ok {
  572. t.Fatalf("second result is type %T, expected []byte", vs[1])
  573. }
  574. // Execute commands that fail after EXEC is called. The second command
  575. // returns an error.
  576. c.Do("ZADD", "k2", 0, 0)
  577. c.Send("MULTI")
  578. c.Send("ZINCRBY", "k2", 0, 0)
  579. c.Send("HSET", "k2", 0, 0)
  580. v, err = c.Do("EXEC")
  581. if err != nil {
  582. t.Fatalf("EXEC returned error %v", err)
  583. }
  584. vs, err = redis.Values(v, nil)
  585. if err != nil {
  586. t.Fatalf("Values(v) returned error %v", err)
  587. }
  588. if len(vs) != 2 {
  589. t.Fatalf("len(vs) == %d, want 2", len(vs))
  590. }
  591. if _, ok := vs[0].([]byte); !ok {
  592. t.Fatalf("first result is type %T, expected []byte", vs[0])
  593. }
  594. if _, ok := vs[1].(error); !ok {
  595. t.Fatalf("second result is type %T, expected error", vs[2])
  596. }
  597. }
  598. func BenchmarkDoEmpty(b *testing.B) {
  599. b.StopTimer()
  600. c, err := redis.DialDefaultServer()
  601. if err != nil {
  602. b.Fatal(err)
  603. }
  604. defer c.Close()
  605. b.StartTimer()
  606. for i := 0; i < b.N; i++ {
  607. if _, err := c.Do(""); err != nil {
  608. b.Fatal(err)
  609. }
  610. }
  611. }
  612. func BenchmarkDoPing(b *testing.B) {
  613. b.StopTimer()
  614. c, err := redis.DialDefaultServer()
  615. if err != nil {
  616. b.Fatal(err)
  617. }
  618. defer c.Close()
  619. b.StartTimer()
  620. for i := 0; i < b.N; i++ {
  621. if _, err := c.Do("PING"); err != nil {
  622. b.Fatal(err)
  623. }
  624. }
  625. }