pool_test.go 6.8 KB

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