pool_test.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  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
  15. import (
  16. "io"
  17. "reflect"
  18. "testing"
  19. "time"
  20. )
  21. type poolTestConn struct {
  22. d *poolDialer
  23. err error
  24. }
  25. func (c *poolTestConn) Close() error { c.d.open -= 1; return nil }
  26. func (c *poolTestConn) Err() error { return c.err }
  27. func (c *poolTestConn) Do(commandName string, args ...interface{}) (reply interface{}, err error) {
  28. if commandName == "ERR" {
  29. c.err = args[0].(error)
  30. }
  31. if commandName != "" {
  32. c.d.commands = append(c.d.commands, commandName)
  33. }
  34. return nil, nil
  35. }
  36. func (c *poolTestConn) Send(commandName string, args ...interface{}) error {
  37. c.d.commands = append(c.d.commands, commandName)
  38. return nil
  39. }
  40. func (c *poolTestConn) Flush() error {
  41. return nil
  42. }
  43. func (c *poolTestConn) Receive() (reply interface{}, err error) {
  44. return nil, nil
  45. }
  46. type poolDialer struct {
  47. t *testing.T
  48. dialed, open int
  49. commands []string
  50. }
  51. func (d *poolDialer) dial() (Conn, error) {
  52. d.open += 1
  53. d.dialed += 1
  54. return &poolTestConn{d: d}, nil
  55. }
  56. func (d *poolDialer) check(message string, p *Pool, dialed, open int) {
  57. if d.dialed != dialed {
  58. d.t.Errorf("%s: dialed=%d, want %d", message, d.dialed, dialed)
  59. }
  60. if d.open != open {
  61. d.t.Errorf("%s: open=%d, want %d", message, d.open, open)
  62. }
  63. if active := p.ActiveCount(); active != open {
  64. d.t.Errorf("%s: active=%d, want %d", message, active, open)
  65. }
  66. }
  67. func TestPoolReuse(t *testing.T) {
  68. d := poolDialer{t: t}
  69. p := &Pool{
  70. MaxIdle: 2,
  71. Dial: d.dial,
  72. }
  73. for i := 0; i < 10; i++ {
  74. c1 := p.Get()
  75. c1.Do("PING")
  76. c2 := p.Get()
  77. c2.Do("PING")
  78. c1.Close()
  79. c2.Close()
  80. }
  81. d.check("before close", p, 2, 2)
  82. p.Close()
  83. d.check("after close", p, 2, 0)
  84. }
  85. func TestPoolMaxIdle(t *testing.T) {
  86. d := poolDialer{t: t}
  87. p := &Pool{
  88. MaxIdle: 2,
  89. Dial: d.dial,
  90. }
  91. for i := 0; i < 10; i++ {
  92. c1 := p.Get()
  93. c1.Do("PING")
  94. c2 := p.Get()
  95. c2.Do("PING")
  96. c3 := p.Get()
  97. c3.Do("PING")
  98. c1.Close()
  99. c2.Close()
  100. c3.Close()
  101. }
  102. d.check("before close", p, 12, 2)
  103. p.Close()
  104. d.check("after close", p, 12, 0)
  105. }
  106. func TestPoolError(t *testing.T) {
  107. d := poolDialer{t: t}
  108. p := &Pool{
  109. MaxIdle: 2,
  110. Dial: d.dial,
  111. }
  112. c := p.Get()
  113. c.Do("ERR", io.EOF)
  114. if c.Err() == nil {
  115. t.Errorf("expected c.Err() != nil")
  116. }
  117. c.Close()
  118. c = p.Get()
  119. c.Do("ERR", io.EOF)
  120. c.Close()
  121. d.check(".", p, 2, 0)
  122. }
  123. func TestPoolClose(t *testing.T) {
  124. d := poolDialer{t: t}
  125. p := &Pool{
  126. MaxIdle: 2,
  127. Dial: d.dial,
  128. }
  129. c1 := p.Get()
  130. c1.Do("PING")
  131. c2 := p.Get()
  132. c2.Do("PING")
  133. c3 := p.Get()
  134. c3.Do("PING")
  135. c1.Close()
  136. if _, err := c1.Do("PING"); err == nil {
  137. t.Errorf("expected error after connection closed")
  138. }
  139. c2.Close()
  140. p.Close()
  141. d.check("after pool close", p, 3, 1)
  142. if _, err := c1.Do("PING"); err == nil {
  143. t.Errorf("expected error after connection and pool closed")
  144. }
  145. c3.Close()
  146. d.check("after channel close", p, 3, 0)
  147. c1 = p.Get()
  148. if _, err := c1.Do("PING"); err == nil {
  149. t.Errorf("expected error after pool closed")
  150. }
  151. }
  152. func TestPoolTimeout(t *testing.T) {
  153. d := poolDialer{t: t}
  154. p := &Pool{
  155. MaxIdle: 2,
  156. IdleTimeout: 300 * time.Second,
  157. Dial: d.dial,
  158. }
  159. now := time.Now()
  160. nowFunc = func() time.Time { return now }
  161. defer func() { nowFunc = time.Now }()
  162. c := p.Get()
  163. c.Do("PING")
  164. c.Close()
  165. d.check("1", p, 1, 1)
  166. now = now.Add(p.IdleTimeout)
  167. c = p.Get()
  168. c.Do("PING")
  169. c.Close()
  170. d.check("2", p, 2, 1)
  171. }
  172. func TestBorrowCheck(t *testing.T) {
  173. d := poolDialer{t: t}
  174. p := &Pool{
  175. MaxIdle: 2,
  176. Dial: d.dial,
  177. TestOnBorrow: func(Conn, time.Time) error { return Error("BLAH") },
  178. }
  179. for i := 0; i < 10; i++ {
  180. c := p.Get()
  181. c.Do("PING")
  182. c.Close()
  183. }
  184. d.check("1", p, 10, 1)
  185. }
  186. func TestMaxActive(t *testing.T) {
  187. d := poolDialer{t: t}
  188. p := &Pool{
  189. MaxIdle: 2,
  190. MaxActive: 2,
  191. Dial: d.dial,
  192. }
  193. c1 := p.Get()
  194. c1.Do("PING")
  195. c2 := p.Get()
  196. c2.Do("PING")
  197. d.check("1", p, 2, 2)
  198. c3 := p.Get()
  199. if _, err := c3.Do("PING"); err != ErrPoolExhausted {
  200. t.Errorf("expected pool exhausted")
  201. }
  202. c3.Close()
  203. d.check("2", p, 2, 2)
  204. c2.Close()
  205. d.check("3", p, 2, 2)
  206. c3 = p.Get()
  207. if _, err := c3.Do("PING"); err != nil {
  208. t.Errorf("expected good channel, err=%v", err)
  209. }
  210. c3.Close()
  211. d.check("4", p, 2, 2)
  212. }
  213. func TestPoolPubSubMonitorCleanup(t *testing.T) {
  214. d := poolDialer{t: t}
  215. p := &Pool{
  216. MaxIdle: 2,
  217. MaxActive: 2,
  218. Dial: d.dial,
  219. }
  220. c := p.Get()
  221. c.Send("SUBSCRIBE", "x")
  222. c.Close()
  223. c = p.Get()
  224. c.Send("PSUBSCRIBE", "x")
  225. c.Close()
  226. c = p.Get()
  227. c.Send("MONITOR")
  228. c.Close()
  229. d.check("", p, 3, 0)
  230. }
  231. func TestTransactionCleanup(t *testing.T) {
  232. d := poolDialer{t: t}
  233. p := &Pool{
  234. MaxIdle: 2,
  235. MaxActive: 2,
  236. Dial: d.dial,
  237. }
  238. c := p.Get()
  239. c.Do("WATCH", "key")
  240. c.Do("PING")
  241. c.Close()
  242. want := []string{"WATCH", "PING", "UNWATCH"}
  243. if !reflect.DeepEqual(d.commands, want) {
  244. t.Errorf("got commands %v, want %v", d.commands, want)
  245. }
  246. d.commands = nil
  247. c = p.Get()
  248. c.Do("WATCH", "key")
  249. c.Do("UNWATCH")
  250. c.Do("PING")
  251. c.Close()
  252. want = []string{"WATCH", "UNWATCH", "PING"}
  253. if !reflect.DeepEqual(d.commands, want) {
  254. t.Errorf("got commands %v, want %v", d.commands, want)
  255. }
  256. d.commands = nil
  257. c = p.Get()
  258. c.Do("WATCH", "key")
  259. c.Do("MULTI")
  260. c.Do("PING")
  261. c.Close()
  262. want = []string{"WATCH", "MULTI", "PING", "DISCARD"}
  263. if !reflect.DeepEqual(d.commands, want) {
  264. t.Errorf("got commands %v, want %v", d.commands, want)
  265. }
  266. d.commands = nil
  267. c = p.Get()
  268. c.Do("WATCH", "key")
  269. c.Do("MULTI")
  270. c.Do("DISCARD")
  271. c.Do("PING")
  272. c.Close()
  273. want = []string{"WATCH", "MULTI", "DISCARD", "PING"}
  274. if !reflect.DeepEqual(d.commands, want) {
  275. t.Errorf("got commands %v, want %v", d.commands, want)
  276. }
  277. d.commands = nil
  278. c = p.Get()
  279. c.Do("WATCH", "key")
  280. c.Do("MULTI")
  281. c.Do("EXEC")
  282. c.Do("PING")
  283. c.Close()
  284. want = []string{"WATCH", "MULTI", "EXEC", "PING"}
  285. if !reflect.DeepEqual(d.commands, want) {
  286. t.Errorf("got commands %v, want %v", d.commands, want)
  287. }
  288. d.commands = nil
  289. }