You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

685 lines
13 KiB

  1. // Copyright 2011 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. "errors"
  17. "io"
  18. "reflect"
  19. "sync"
  20. "testing"
  21. "time"
  22. "github.com/garyburd/redigo/redis"
  23. )
  24. type poolTestConn struct {
  25. d *poolDialer
  26. err error
  27. redis.Conn
  28. }
  29. func (c *poolTestConn) Close() error {
  30. c.d.mu.Lock()
  31. c.d.open -= 1
  32. c.d.mu.Unlock()
  33. return c.Conn.Close()
  34. }
  35. func (c *poolTestConn) Err() error { return c.err }
  36. func (c *poolTestConn) Do(commandName string, args ...interface{}) (interface{}, error) {
  37. if commandName == "ERR" {
  38. c.err = args[0].(error)
  39. commandName = "PING"
  40. }
  41. if commandName != "" {
  42. c.d.commands = append(c.d.commands, commandName)
  43. }
  44. return c.Conn.Do(commandName, args...)
  45. }
  46. func (c *poolTestConn) Send(commandName string, args ...interface{}) error {
  47. c.d.commands = append(c.d.commands, commandName)
  48. return c.Conn.Send(commandName, args...)
  49. }
  50. type poolDialer struct {
  51. mu sync.Mutex
  52. t *testing.T
  53. dialed int
  54. open int
  55. commands []string
  56. dialErr error
  57. }
  58. func (d *poolDialer) dial() (redis.Conn, error) {
  59. d.mu.Lock()
  60. d.dialed += 1
  61. dialErr := d.dialErr
  62. d.mu.Unlock()
  63. if dialErr != nil {
  64. return nil, d.dialErr
  65. }
  66. c, err := redis.DialDefaultServer()
  67. if err != nil {
  68. return nil, err
  69. }
  70. d.mu.Lock()
  71. d.open += 1
  72. d.mu.Unlock()
  73. return &poolTestConn{d: d, Conn: c}, nil
  74. }
  75. func (d *poolDialer) check(message string, p *redis.Pool, dialed, open int) {
  76. d.mu.Lock()
  77. if d.dialed != dialed {
  78. d.t.Errorf("%s: dialed=%d, want %d", message, d.dialed, dialed)
  79. }
  80. if d.open != open {
  81. d.t.Errorf("%s: open=%d, want %d", message, d.open, open)
  82. }
  83. if active := p.ActiveCount(); active != open {
  84. d.t.Errorf("%s: active=%d, want %d", message, active, open)
  85. }
  86. d.mu.Unlock()
  87. }
  88. func TestPoolReuse(t *testing.T) {
  89. d := poolDialer{t: t}
  90. p := &redis.Pool{
  91. MaxIdle: 2,
  92. Dial: d.dial,
  93. }
  94. for i := 0; i < 10; i++ {
  95. c1 := p.Get()
  96. c1.Do("PING")
  97. c2 := p.Get()
  98. c2.Do("PING")
  99. c1.Close()
  100. c2.Close()
  101. }
  102. d.check("before close", p, 2, 2)
  103. p.Close()
  104. d.check("after close", p, 2, 0)
  105. }
  106. func TestPoolMaxIdle(t *testing.T) {
  107. d := poolDialer{t: t}
  108. p := &redis.Pool{
  109. MaxIdle: 2,
  110. Dial: d.dial,
  111. }
  112. defer p.Close()
  113. for i := 0; i < 10; i++ {
  114. c1 := p.Get()
  115. c1.Do("PING")
  116. c2 := p.Get()
  117. c2.Do("PING")
  118. c3 := p.Get()
  119. c3.Do("PING")
  120. c1.Close()
  121. c2.Close()
  122. c3.Close()
  123. }
  124. d.check("before close", p, 12, 2)
  125. p.Close()
  126. d.check("after close", p, 12, 0)
  127. }
  128. func TestPoolError(t *testing.T) {
  129. d := poolDialer{t: t}
  130. p := &redis.Pool{
  131. MaxIdle: 2,
  132. Dial: d.dial,
  133. }
  134. defer p.Close()
  135. c := p.Get()
  136. c.Do("ERR", io.EOF)
  137. if c.Err() == nil {
  138. t.Errorf("expected c.Err() != nil")
  139. }
  140. c.Close()
  141. c = p.Get()
  142. c.Do("ERR", io.EOF)
  143. c.Close()
  144. d.check(".", p, 2, 0)
  145. }
  146. func TestPoolClose(t *testing.T) {
  147. d := poolDialer{t: t}
  148. p := &redis.Pool{
  149. MaxIdle: 2,
  150. Dial: d.dial,
  151. }
  152. defer p.Close()
  153. c1 := p.Get()
  154. c1.Do("PING")
  155. c2 := p.Get()
  156. c2.Do("PING")
  157. c3 := p.Get()
  158. c3.Do("PING")
  159. c1.Close()
  160. if _, err := c1.Do("PING"); err == nil {
  161. t.Errorf("expected error after connection closed")
  162. }
  163. c2.Close()
  164. c2.Close()
  165. p.Close()
  166. d.check("after pool close", p, 3, 1)
  167. if _, err := c1.Do("PING"); err == nil {
  168. t.Errorf("expected error after connection and pool closed")
  169. }
  170. c3.Close()
  171. d.check("after conn close", p, 3, 0)
  172. c1 = p.Get()
  173. if _, err := c1.Do("PING"); err == nil {
  174. t.Errorf("expected error after pool closed")
  175. }
  176. }
  177. func TestPoolTimeout(t *testing.T) {
  178. d := poolDialer{t: t}
  179. p := &redis.Pool{
  180. MaxIdle: 2,
  181. IdleTimeout: 300 * time.Second,
  182. Dial: d.dial,
  183. }
  184. defer p.Close()
  185. now := time.Now()
  186. redis.SetNowFunc(func() time.Time { return now })
  187. defer redis.SetNowFunc(time.Now)
  188. c := p.Get()
  189. c.Do("PING")
  190. c.Close()
  191. d.check("1", p, 1, 1)
  192. now = now.Add(p.IdleTimeout)
  193. c = p.Get()
  194. c.Do("PING")
  195. c.Close()
  196. d.check("2", p, 2, 1)
  197. }
  198. func TestPoolConcurrenSendReceive(t *testing.T) {
  199. p := &redis.Pool{
  200. Dial: redis.DialDefaultServer,
  201. }
  202. defer p.Close()
  203. c := p.Get()
  204. done := make(chan error, 1)
  205. go func() {
  206. _, err := c.Receive()
  207. done <- err
  208. }()
  209. c.Send("PING")
  210. c.Flush()
  211. err := <-done
  212. if err != nil {
  213. t.Fatalf("Receive() returned error %v", err)
  214. }
  215. _, err = c.Do("")
  216. if err != nil {
  217. t.Fatalf("Do() returned error %v", err)
  218. }
  219. c.Close()
  220. }
  221. func TestPoolBorrowCheck(t *testing.T) {
  222. d := poolDialer{t: t}
  223. p := &redis.Pool{
  224. MaxIdle: 2,
  225. Dial: d.dial,
  226. TestOnBorrow: func(redis.Conn, time.Time) error { return redis.Error("BLAH") },
  227. }
  228. defer p.Close()
  229. for i := 0; i < 10; i++ {
  230. c := p.Get()
  231. c.Do("PING")
  232. c.Close()
  233. }
  234. d.check("1", p, 10, 1)
  235. }
  236. func TestPoolMaxActive(t *testing.T) {
  237. d := poolDialer{t: t}
  238. p := &redis.Pool{
  239. MaxIdle: 2,
  240. MaxActive: 2,
  241. Dial: d.dial,
  242. }
  243. defer p.Close()
  244. c1 := p.Get()
  245. c1.Do("PING")
  246. c2 := p.Get()
  247. c2.Do("PING")
  248. d.check("1", p, 2, 2)
  249. c3 := p.Get()
  250. if _, err := c3.Do("PING"); err != redis.ErrPoolExhausted {
  251. t.Errorf("expected pool exhausted")
  252. }
  253. c3.Close()
  254. d.check("2", p, 2, 2)
  255. c2.Close()
  256. d.check("3", p, 2, 2)
  257. c3 = p.Get()
  258. if _, err := c3.Do("PING"); err != nil {
  259. t.Errorf("expected good channel, err=%v", err)
  260. }
  261. c3.Close()
  262. d.check("4", p, 2, 2)
  263. }
  264. func TestPoolMonitorCleanup(t *testing.T) {
  265. d := poolDialer{t: t}
  266. p := &redis.Pool{
  267. MaxIdle: 2,
  268. MaxActive: 2,
  269. Dial: d.dial,
  270. }
  271. defer p.Close()
  272. c := p.Get()
  273. c.Send("MONITOR")
  274. c.Close()
  275. d.check("", p, 1, 0)
  276. }
  277. func TestPoolPubSubCleanup(t *testing.T) {
  278. d := poolDialer{t: t}
  279. p := &redis.Pool{
  280. MaxIdle: 2,
  281. MaxActive: 2,
  282. Dial: d.dial,
  283. }
  284. defer p.Close()
  285. c := p.Get()
  286. c.Send("SUBSCRIBE", "x")
  287. c.Close()
  288. want := []string{"SUBSCRIBE", "UNSUBSCRIBE", "PUNSUBSCRIBE", "ECHO"}
  289. if !reflect.DeepEqual(d.commands, want) {
  290. t.Errorf("got commands %v, want %v", d.commands, want)
  291. }
  292. d.commands = nil
  293. c = p.Get()
  294. c.Send("PSUBSCRIBE", "x*")
  295. c.Close()
  296. want = []string{"PSUBSCRIBE", "UNSUBSCRIBE", "PUNSUBSCRIBE", "ECHO"}
  297. if !reflect.DeepEqual(d.commands, want) {
  298. t.Errorf("got commands %v, want %v", d.commands, want)
  299. }
  300. d.commands = nil
  301. }
  302. func TestPoolTransactionCleanup(t *testing.T) {
  303. d := poolDialer{t: t}
  304. p := &redis.Pool{
  305. MaxIdle: 2,
  306. MaxActive: 2,
  307. Dial: d.dial,
  308. }
  309. defer p.Close()
  310. c := p.Get()
  311. c.Do("WATCH", "key")
  312. c.Do("PING")
  313. c.Close()
  314. want := []string{"WATCH", "PING", "UNWATCH"}
  315. if !reflect.DeepEqual(d.commands, want) {
  316. t.Errorf("got commands %v, want %v", d.commands, want)
  317. }
  318. d.commands = nil
  319. c = p.Get()
  320. c.Do("WATCH", "key")
  321. c.Do("UNWATCH")
  322. c.Do("PING")
  323. c.Close()
  324. want = []string{"WATCH", "UNWATCH", "PING"}
  325. if !reflect.DeepEqual(d.commands, want) {
  326. t.Errorf("got commands %v, want %v", d.commands, want)
  327. }
  328. d.commands = nil
  329. c = p.Get()
  330. c.Do("WATCH", "key")
  331. c.Do("MULTI")
  332. c.Do("PING")
  333. c.Close()
  334. want = []string{"WATCH", "MULTI", "PING", "DISCARD"}
  335. if !reflect.DeepEqual(d.commands, want) {
  336. t.Errorf("got commands %v, want %v", d.commands, want)
  337. }
  338. d.commands = nil
  339. c = p.Get()
  340. c.Do("WATCH", "key")
  341. c.Do("MULTI")
  342. c.Do("DISCARD")
  343. c.Do("PING")
  344. c.Close()
  345. want = []string{"WATCH", "MULTI", "DISCARD", "PING"}
  346. if !reflect.DeepEqual(d.commands, want) {
  347. t.Errorf("got commands %v, want %v", d.commands, want)
  348. }
  349. d.commands = nil
  350. c = p.Get()
  351. c.Do("WATCH", "key")
  352. c.Do("MULTI")
  353. c.Do("EXEC")
  354. c.Do("PING")
  355. c.Close()
  356. want = []string{"WATCH", "MULTI", "EXEC", "PING"}
  357. if !reflect.DeepEqual(d.commands, want) {
  358. t.Errorf("got commands %v, want %v", d.commands, want)
  359. }
  360. d.commands = nil
  361. }
  362. func startGoroutines(p *redis.Pool, cmd string, args ...interface{}) chan error {
  363. errs := make(chan error, 10)
  364. for i := 0; i < cap(errs); i++ {
  365. go func() {
  366. c := p.Get()
  367. _, err := c.Do(cmd, args...)
  368. errs <- err
  369. c.Close()
  370. }()
  371. }
  372. // Wait for goroutines to block.
  373. time.Sleep(time.Second / 4)
  374. return errs
  375. }
  376. func TestWaitPool(t *testing.T) {
  377. d := poolDialer{t: t}
  378. p := &redis.Pool{
  379. MaxIdle: 1,
  380. MaxActive: 1,
  381. Dial: d.dial,
  382. Wait: true,
  383. }
  384. defer p.Close()
  385. c := p.Get()
  386. errs := startGoroutines(p, "PING")
  387. d.check("before close", p, 1, 1)
  388. c.Close()
  389. timeout := time.After(2 * time.Second)
  390. for i := 0; i < cap(errs); i++ {
  391. select {
  392. case err := <-errs:
  393. if err != nil {
  394. t.Fatal(err)
  395. }
  396. case <-timeout:
  397. t.Fatalf("timeout waiting for blocked goroutine %d", i)
  398. }
  399. }
  400. d.check("done", p, 1, 1)
  401. }
  402. func TestWaitPoolClose(t *testing.T) {
  403. d := poolDialer{t: t}
  404. p := &redis.Pool{
  405. MaxIdle: 1,
  406. MaxActive: 1,
  407. Dial: d.dial,
  408. Wait: true,
  409. }
  410. defer p.Close()
  411. c := p.Get()
  412. if _, err := c.Do("PING"); err != nil {
  413. t.Fatal(err)
  414. }
  415. errs := startGoroutines(p, "PING")
  416. d.check("before close", p, 1, 1)
  417. p.Close()
  418. timeout := time.After(2 * time.Second)
  419. for i := 0; i < cap(errs); i++ {
  420. select {
  421. case err := <-errs:
  422. switch err {
  423. case nil:
  424. t.Fatal("blocked goroutine did not get error")
  425. case redis.ErrPoolExhausted:
  426. t.Fatal("blocked goroutine got pool exhausted error")
  427. }
  428. case <-timeout:
  429. t.Fatal("timeout waiting for blocked goroutine")
  430. }
  431. }
  432. c.Close()
  433. d.check("done", p, 1, 0)
  434. }
  435. func TestWaitPoolCommandError(t *testing.T) {
  436. testErr := errors.New("test")
  437. d := poolDialer{t: t}
  438. p := &redis.Pool{
  439. MaxIdle: 1,
  440. MaxActive: 1,
  441. Dial: d.dial,
  442. Wait: true,
  443. }
  444. defer p.Close()
  445. c := p.Get()
  446. errs := startGoroutines(p, "ERR", testErr)
  447. d.check("before close", p, 1, 1)
  448. c.Close()
  449. timeout := time.After(2 * time.Second)
  450. for i := 0; i < cap(errs); i++ {
  451. select {
  452. case err := <-errs:
  453. if err != nil {
  454. t.Fatal(err)
  455. }
  456. case <-timeout:
  457. t.Fatalf("timeout waiting for blocked goroutine %d", i)
  458. }
  459. }
  460. d.check("done", p, cap(errs), 0)
  461. }
  462. func TestWaitPoolDialError(t *testing.T) {
  463. testErr := errors.New("test")
  464. d := poolDialer{t: t}
  465. p := &redis.Pool{
  466. MaxIdle: 1,
  467. MaxActive: 1,
  468. Dial: d.dial,
  469. Wait: true,
  470. }
  471. defer p.Close()
  472. c := p.Get()
  473. errs := startGoroutines(p, "ERR", testErr)
  474. d.check("before close", p, 1, 1)
  475. d.dialErr = errors.New("dial")
  476. c.Close()
  477. nilCount := 0
  478. errCount := 0
  479. timeout := time.After(2 * time.Second)
  480. for i := 0; i < cap(errs); i++ {
  481. select {
  482. case err := <-errs:
  483. switch err {
  484. case nil:
  485. nilCount++
  486. case d.dialErr:
  487. errCount++
  488. default:
  489. t.Fatalf("expected dial error or nil, got %v", err)
  490. }
  491. case <-timeout:
  492. t.Fatalf("timeout waiting for blocked goroutine %d", i)
  493. }
  494. }
  495. if nilCount != 1 {
  496. t.Errorf("expected one nil error, got %d", nilCount)
  497. }
  498. if errCount != cap(errs)-1 {
  499. t.Errorf("expected %d dial erors, got %d", cap(errs)-1, errCount)
  500. }
  501. d.check("done", p, cap(errs), 0)
  502. }
  503. // Borrowing requires us to iterate over the idle connections, unlock the pool,
  504. // and perform a blocking operation to check the connection still works. If
  505. // TestOnBorrow fails, we must reacquire the lock and continue iteration. This
  506. // test ensures that iteration will work correctly if multiple threads are
  507. // iterating simultaneously.
  508. func TestLocking_TestOnBorrowFails_PoolDoesntCrash(t *testing.T) {
  509. const count = 100
  510. // First we'll Create a pool where the pilfering of idle connections fails.
  511. d := poolDialer{t: t}
  512. p := &redis.Pool{
  513. MaxIdle: count,
  514. MaxActive: count,
  515. Dial: d.dial,
  516. TestOnBorrow: func(c redis.Conn, t time.Time) error {
  517. return errors.New("No way back into the real world.")
  518. },
  519. }
  520. defer p.Close()
  521. // Fill the pool with idle connections.
  522. conns := make([]redis.Conn, count)
  523. for i := range conns {
  524. conns[i] = p.Get()
  525. }
  526. for i := range conns {
  527. conns[i].Close()
  528. }
  529. // Spawn a bunch of goroutines to thrash the pool.
  530. var wg sync.WaitGroup
  531. wg.Add(count)
  532. for i := 0; i < count; i++ {
  533. go func() {
  534. c := p.Get()
  535. if c.Err() != nil {
  536. t.Errorf("pool get failed: %v", c.Err())
  537. }
  538. c.Close()
  539. wg.Done()
  540. }()
  541. }
  542. wg.Wait()
  543. if d.dialed != count*2 {
  544. t.Errorf("Expected %d dials, got %d", count*2, d.dialed)
  545. }
  546. }
  547. func BenchmarkPoolGet(b *testing.B) {
  548. b.StopTimer()
  549. p := redis.Pool{Dial: redis.DialDefaultServer, MaxIdle: 2}
  550. c := p.Get()
  551. if err := c.Err(); err != nil {
  552. b.Fatal(err)
  553. }
  554. c.Close()
  555. defer p.Close()
  556. b.StartTimer()
  557. for i := 0; i < b.N; i++ {
  558. c = p.Get()
  559. c.Close()
  560. }
  561. }
  562. func BenchmarkPoolGetErr(b *testing.B) {
  563. b.StopTimer()
  564. p := redis.Pool{Dial: redis.DialDefaultServer, MaxIdle: 2}
  565. c := p.Get()
  566. if err := c.Err(); err != nil {
  567. b.Fatal(err)
  568. }
  569. c.Close()
  570. defer p.Close()
  571. b.StartTimer()
  572. for i := 0; i < b.N; i++ {
  573. c = p.Get()
  574. if err := c.Err(); err != nil {
  575. b.Fatal(err)
  576. }
  577. c.Close()
  578. }
  579. }
  580. func BenchmarkPoolGetPing(b *testing.B) {
  581. b.StopTimer()
  582. p := redis.Pool{Dial: redis.DialDefaultServer, MaxIdle: 2}
  583. c := p.Get()
  584. if err := c.Err(); err != nil {
  585. b.Fatal(err)
  586. }
  587. c.Close()
  588. defer p.Close()
  589. b.StartTimer()
  590. for i := 0; i < b.N; i++ {
  591. c = p.Get()
  592. if _, err := c.Do("PING"); err != nil {
  593. b.Fatal(err)
  594. }
  595. c.Close()
  596. }
  597. }