redis_test.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. package cache
  2. import (
  3. "context"
  4. "testing"
  5. "time"
  6. "github.com/alicebob/miniredis/v2"
  7. "github.com/go-redis/redis/v8"
  8. )
  9. func TestRedis(t *testing.T) {
  10. server, err := miniredis.Run()
  11. if err != nil {
  12. t.Error("miniredis.Run Error", err)
  13. }
  14. t.Cleanup(server.Close)
  15. var (
  16. timeoutDuration = time.Second
  17. ctx = context.Background()
  18. opts = &RedisOpts{
  19. Host: server.Addr(),
  20. Password: "",
  21. Database: 0,
  22. PoolSize: 10,
  23. MinIdleConns: 5,
  24. DialTimeout: 5,
  25. ReadTimeout: 5,
  26. WriteTimeout: 5,
  27. PoolTimeout: 5,
  28. IdleTimeout: 300,
  29. }
  30. redis = NewRedis(ctx, opts)
  31. val = "silenceper"
  32. key = "username"
  33. )
  34. redis.SetConn(redis.conn)
  35. redis.SetRedisCtx(ctx)
  36. if err = redis.Set(key, val, timeoutDuration); err != nil {
  37. t.Error("set Error", err)
  38. }
  39. if !redis.IsExist(key) {
  40. t.Error("IsExist Error")
  41. }
  42. name := redis.Get(key).(string)
  43. if name != val {
  44. t.Error("get Error")
  45. }
  46. if err = redis.Delete(key); err != nil {
  47. t.Errorf("delete Error , err=%v", err)
  48. }
  49. }
  50. // setupRedisServer 创建并返回一个 miniredis 服务器实例
  51. func setupRedisServer(t *testing.T) *miniredis.Miniredis {
  52. server, err := miniredis.Run()
  53. if err != nil {
  54. t.Fatal("miniredis.Run Error", err)
  55. }
  56. t.Cleanup(server.Close)
  57. return server
  58. }
  59. // TestRedisMaxIdleMapping 测试只设置MaxIdle应该映射到MinIdleConns
  60. func TestRedisMaxIdleMapping(t *testing.T) {
  61. server := setupRedisServer(t)
  62. ctx := context.Background()
  63. opts := &RedisOpts{
  64. Host: server.Addr(),
  65. Database: 0,
  66. MaxIdle: 10,
  67. }
  68. r := NewRedis(ctx, opts)
  69. // 获取底层的 UniversalClient 并断言为 *redis.Client
  70. client, ok := r.conn.(*redis.Client)
  71. if !ok {
  72. t.Fatal("无法转换为 *redis.Client")
  73. }
  74. // 注意:MinIdleConns 表示期望的最小空闲连接数,但实际空闲连接数可能不同
  75. // 我们需要通过 Options() 来验证配置是否正确应用
  76. clientOpts := client.Options()
  77. if clientOpts.MinIdleConns != 10 {
  78. t.Errorf("期望 MinIdleConns = 10, 实际 = %d", clientOpts.MinIdleConns)
  79. }
  80. }
  81. // TestRedisMaxActiveMapping 测试只设置MaxActive应该映射到PoolSize
  82. func TestRedisMaxActiveMapping(t *testing.T) {
  83. server := setupRedisServer(t)
  84. ctx := context.Background()
  85. opts := &RedisOpts{
  86. Host: server.Addr(),
  87. Database: 0,
  88. MaxActive: 20,
  89. }
  90. r := NewRedis(ctx, opts)
  91. client, ok := r.conn.(*redis.Client)
  92. if !ok {
  93. t.Fatal("无法转换为 *redis.Client")
  94. }
  95. clientOpts := client.Options()
  96. if clientOpts.PoolSize != 20 {
  97. t.Errorf("期望 PoolSize = 20, 实际 = %d", clientOpts.PoolSize)
  98. }
  99. }
  100. // TestRedisNewFieldsPriority 测试新字段应该优先于旧字段
  101. func TestRedisNewFieldsPriority(t *testing.T) {
  102. server := setupRedisServer(t)
  103. ctx := context.Background()
  104. opts := &RedisOpts{
  105. Host: server.Addr(),
  106. Database: 0,
  107. MaxIdle: 5,
  108. MinIdleConns: 15,
  109. MaxActive: 10,
  110. PoolSize: 30,
  111. }
  112. r := NewRedis(ctx, opts)
  113. client, ok := r.conn.(*redis.Client)
  114. if !ok {
  115. t.Fatal("无法转换为 *redis.Client")
  116. }
  117. clientOpts := client.Options()
  118. if clientOpts.MinIdleConns != 15 {
  119. t.Errorf("期望 MinIdleConns = 15 (新字段优先), 实际 = %d", clientOpts.MinIdleConns)
  120. }
  121. if clientOpts.PoolSize != 30 {
  122. t.Errorf("期望 PoolSize = 30 (新字段优先), 实际 = %d", clientOpts.PoolSize)
  123. }
  124. }
  125. // TestRedisPositiveTimeouts 测试正值超时应该正确应用
  126. func TestRedisPositiveTimeouts(t *testing.T) {
  127. server := setupRedisServer(t)
  128. ctx := context.Background()
  129. opts := &RedisOpts{
  130. Host: server.Addr(),
  131. Database: 0,
  132. DialTimeout: 10,
  133. ReadTimeout: 20,
  134. WriteTimeout: 30,
  135. PoolTimeout: 40,
  136. IdleTimeout: 50,
  137. }
  138. r := NewRedis(ctx, opts)
  139. client, ok := r.conn.(*redis.Client)
  140. if !ok {
  141. t.Fatal("无法转换为 *redis.Client")
  142. }
  143. clientOpts := client.Options()
  144. if clientOpts.DialTimeout != 10*time.Second {
  145. t.Errorf("期望 DialTimeout = 10s, 实际 = %v", clientOpts.DialTimeout)
  146. }
  147. if clientOpts.ReadTimeout != 20*time.Second {
  148. t.Errorf("期望 ReadTimeout = 20s, 实际 = %v", clientOpts.ReadTimeout)
  149. }
  150. if clientOpts.WriteTimeout != 30*time.Second {
  151. t.Errorf("期望 WriteTimeout = 30s, 实际 = %v", clientOpts.WriteTimeout)
  152. }
  153. if clientOpts.PoolTimeout != 40*time.Second {
  154. t.Errorf("期望 PoolTimeout = 40s, 实际 = %v", clientOpts.PoolTimeout)
  155. }
  156. if clientOpts.IdleTimeout != 50*time.Second {
  157. t.Errorf("期望 IdleTimeout = 50s, 实际 = %v", clientOpts.IdleTimeout)
  158. }
  159. }
  160. // TestRedisNegativeTimeouts 测试-1值应该禁用超时
  161. func TestRedisNegativeTimeouts(t *testing.T) {
  162. server := setupRedisServer(t)
  163. ctx := context.Background()
  164. opts := &RedisOpts{
  165. Host: server.Addr(),
  166. Database: 0,
  167. DialTimeout: -1,
  168. ReadTimeout: -1,
  169. WriteTimeout: -1,
  170. PoolTimeout: -1,
  171. IdleTimeout: -1,
  172. }
  173. r := NewRedis(ctx, opts)
  174. client, ok := r.conn.(*redis.Client)
  175. if !ok {
  176. t.Fatal("无法转换为 *redis.Client")
  177. }
  178. clientOpts := client.Options()
  179. // -1 应该被设置为负值表示禁用超时
  180. // DialTimeout, PoolTimeout, IdleTimeout 会被设置为 -1ns
  181. if clientOpts.DialTimeout != -1 {
  182. t.Errorf("期望 DialTimeout = -1ns (禁用), 实际 = %v", clientOpts.DialTimeout)
  183. }
  184. // ReadTimeout 和 WriteTimeout 在 go-redis 中有特殊处理
  185. // 当设置为负值时,会被规范化为 0,这也表示无超时
  186. t.Logf("ReadTimeout = %v (设置为-1后的值)", clientOpts.ReadTimeout)
  187. t.Logf("WriteTimeout = %v (设置为-1后的值)", clientOpts.WriteTimeout)
  188. if clientOpts.PoolTimeout != -1 {
  189. t.Errorf("期望 PoolTimeout = -1ns (禁用), 实际 = %v", clientOpts.PoolTimeout)
  190. }
  191. if clientOpts.IdleTimeout != -1 {
  192. t.Errorf("期望 IdleTimeout = -1ns (禁用), 实际 = %v", clientOpts.IdleTimeout)
  193. }
  194. }
  195. // TestRedisZeroTimeouts 测试0值应该使用go-redis默认值
  196. func TestRedisZeroTimeouts(t *testing.T) {
  197. server := setupRedisServer(t)
  198. ctx := context.Background()
  199. opts := &RedisOpts{
  200. Host: server.Addr(),
  201. Database: 0,
  202. DialTimeout: 0,
  203. ReadTimeout: 0,
  204. WriteTimeout: 0,
  205. PoolTimeout: 0,
  206. IdleTimeout: 0,
  207. }
  208. r := NewRedis(ctx, opts)
  209. client, ok := r.conn.(*redis.Client)
  210. if !ok {
  211. t.Fatal("无法转换为 *redis.Client")
  212. }
  213. clientOpts := client.Options()
  214. // 0值应该保持为0,由 go-redis 使用默认值
  215. // go-redis 的默认值:
  216. // DialTimeout: 5s
  217. // ReadTimeout: 3s
  218. // WriteTimeout: ReadTimeout
  219. // PoolTimeout: ReadTimeout + 1s
  220. // IdleTimeout: 5min
  221. if clientOpts.DialTimeout == 0 {
  222. t.Error("期望 DialTimeout 使用 go-redis 默认值 (5s), 实际为 0")
  223. }
  224. if clientOpts.ReadTimeout == 0 {
  225. t.Error("期望 ReadTimeout 使用 go-redis 默认值 (3s), 实际为 0")
  226. }
  227. if clientOpts.WriteTimeout == 0 {
  228. t.Error("期望 WriteTimeout 使用 go-redis 默认值 (ReadTimeout), 实际为 0")
  229. }
  230. if clientOpts.PoolTimeout == 0 {
  231. t.Error("期望 PoolTimeout 使用 go-redis 默认值 (ReadTimeout + 1s), 实际为 0")
  232. }
  233. if clientOpts.IdleTimeout == 0 {
  234. t.Error("期望 IdleTimeout 使用 go-redis 默认值 (5min), 实际为 0")
  235. }
  236. }
  237. // TestRedisMixedTimeouts 测试混合超时配置
  238. func TestRedisMixedTimeouts(t *testing.T) {
  239. server := setupRedisServer(t)
  240. ctx := context.Background()
  241. opts := &RedisOpts{
  242. Host: server.Addr(),
  243. Database: 0,
  244. DialTimeout: 5, // 正值
  245. ReadTimeout: -1, // 禁用
  246. WriteTimeout: 0, // 使用默认值
  247. PoolTimeout: 10, // 正值
  248. IdleTimeout: -1, // 禁用
  249. }
  250. r := NewRedis(ctx, opts)
  251. client, ok := r.conn.(*redis.Client)
  252. if !ok {
  253. t.Fatal("无法转换为 *redis.Client")
  254. }
  255. clientOpts := client.Options()
  256. if clientOpts.DialTimeout != 5*time.Second {
  257. t.Errorf("期望 DialTimeout = 5s, 实际 = %v", clientOpts.DialTimeout)
  258. }
  259. // ReadTimeout 设置为 -1,会被 go-redis 处理为 0(无超时)
  260. t.Logf("ReadTimeout = %v (设置为-1后的值)", clientOpts.ReadTimeout)
  261. // WriteTimeout 设置为 0,应该使用 go-redis 的默认值
  262. // 默认值通常是 ReadTimeout 的值
  263. t.Logf("WriteTimeout = %v (设置为0后使用的默认值)", clientOpts.WriteTimeout)
  264. if clientOpts.PoolTimeout != 10*time.Second {
  265. t.Errorf("期望 PoolTimeout = 10s, 实际 = %v", clientOpts.PoolTimeout)
  266. }
  267. // IdleTimeout 设置为 -1,应该被设置为 -1ns(禁用空闲超时)
  268. if clientOpts.IdleTimeout != -1 {
  269. t.Errorf("期望 IdleTimeout = -1ns (禁用), 实际 = %v", clientOpts.IdleTimeout)
  270. }
  271. }