cachedcollection_test.go 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. package mongoc
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "io/ioutil"
  6. "log"
  7. "os"
  8. "runtime"
  9. "sync"
  10. "sync/atomic"
  11. "testing"
  12. "time"
  13. "github.com/globalsign/mgo"
  14. "github.com/globalsign/mgo/bson"
  15. "github.com/stretchr/testify/assert"
  16. "github.com/tal-tech/go-zero/core/stat"
  17. "github.com/tal-tech/go-zero/core/stores/cache"
  18. "github.com/tal-tech/go-zero/core/stores/mongo"
  19. "github.com/tal-tech/go-zero/core/stores/redis"
  20. "github.com/tal-tech/go-zero/core/stores/redis/redistest"
  21. )
  22. const dummyCount = 10
  23. func init() {
  24. stat.SetReporter(nil)
  25. }
  26. func TestCollection_Count(t *testing.T) {
  27. resetStats()
  28. r, clean, err := redistest.CreateRedis()
  29. assert.Nil(t, err)
  30. defer clean()
  31. cach := cache.NewCacheNode(r, sharedCalls, stats, mgo.ErrNotFound)
  32. c := newCollection(dummyConn{}, cach)
  33. val, err := c.Count("any")
  34. assert.Nil(t, err)
  35. assert.Equal(t, dummyCount, val)
  36. var value string
  37. assert.Nil(t, r.Set("any", `"foo"`))
  38. assert.Nil(t, c.GetCache("any", &value))
  39. assert.Equal(t, "foo", value)
  40. assert.Nil(t, c.DelCache("any"))
  41. assert.Nil(t, c.SetCache("any", "bar"))
  42. assert.Nil(t, c.FindAllNoCache(&value, "any", func(query mongo.Query) mongo.Query {
  43. return query
  44. }))
  45. assert.Nil(t, c.FindOne(&value, "any", "foo"))
  46. assert.Equal(t, "bar", value)
  47. assert.Nil(t, c.DelCache("any"))
  48. c = newCollection(dummyConn{val: `"bar"`}, cach)
  49. assert.Nil(t, c.FindOne(&value, "any", "foo"))
  50. assert.Equal(t, "bar", value)
  51. assert.Nil(t, c.FindOneNoCache(&value, "foo"))
  52. assert.Equal(t, "bar", value)
  53. assert.Nil(t, c.FindOneId(&value, "anyone", "foo"))
  54. assert.Equal(t, "bar", value)
  55. assert.Nil(t, c.FindOneIdNoCache(&value, "foo"))
  56. assert.Equal(t, "bar", value)
  57. assert.Nil(t, c.Insert("foo"))
  58. assert.Nil(t, c.Pipe("foo"))
  59. assert.Nil(t, c.Remove("any"))
  60. assert.Nil(t, c.RemoveId("any"))
  61. _, err = c.RemoveAll("any")
  62. assert.Nil(t, err)
  63. assert.Nil(t, c.Update("foo", "bar"))
  64. assert.Nil(t, c.UpdateId("foo", "bar"))
  65. _, err = c.Upsert("foo", "bar")
  66. assert.Nil(t, err)
  67. c = newCollection(dummyConn{
  68. val: `"bar"`,
  69. removeErr: errors.New("any"),
  70. }, cach)
  71. assert.NotNil(t, c.Remove("any"))
  72. _, err = c.RemoveAll("any", "bar")
  73. assert.NotNil(t, err)
  74. assert.NotNil(t, c.RemoveId("any"))
  75. c = newCollection(dummyConn{
  76. val: `"bar"`,
  77. updateErr: errors.New("any"),
  78. }, cach)
  79. assert.NotNil(t, c.Update("foo", "bar"))
  80. assert.NotNil(t, c.UpdateId("foo", "bar"))
  81. _, err = c.Upsert("foo", "bar")
  82. assert.NotNil(t, err)
  83. }
  84. func TestStat(t *testing.T) {
  85. resetStats()
  86. r, clean, err := redistest.CreateRedis()
  87. assert.Nil(t, err)
  88. defer clean()
  89. cach := cache.NewCacheNode(r, sharedCalls, stats, mgo.ErrNotFound)
  90. c := newCollection(dummyConn{}, cach)
  91. for i := 0; i < 10; i++ {
  92. var str string
  93. if err = c.cache.Take(&str, "name", func(v interface{}) error {
  94. *v.(*string) = "zero"
  95. return nil
  96. }); err != nil {
  97. t.Error(err)
  98. }
  99. }
  100. assert.Equal(t, uint64(10), atomic.LoadUint64(&stats.Total))
  101. assert.Equal(t, uint64(9), atomic.LoadUint64(&stats.Hit))
  102. }
  103. func TestStatCacheFails(t *testing.T) {
  104. resetStats()
  105. log.SetOutput(ioutil.Discard)
  106. defer log.SetOutput(os.Stdout)
  107. r := redis.NewRedis("localhost:59999", redis.NodeType)
  108. cach := cache.NewCacheNode(r, sharedCalls, stats, mgo.ErrNotFound)
  109. c := newCollection(dummyConn{}, cach)
  110. for i := 0; i < 20; i++ {
  111. var str string
  112. err := c.FindOne(&str, "name", bson.M{})
  113. assert.NotNil(t, err)
  114. }
  115. assert.Equal(t, uint64(20), atomic.LoadUint64(&stats.Total))
  116. assert.Equal(t, uint64(0), atomic.LoadUint64(&stats.Hit))
  117. assert.Equal(t, uint64(20), atomic.LoadUint64(&stats.Miss))
  118. assert.Equal(t, uint64(0), atomic.LoadUint64(&stats.DbFails))
  119. }
  120. func TestStatDbFails(t *testing.T) {
  121. resetStats()
  122. r, clean, err := redistest.CreateRedis()
  123. assert.Nil(t, err)
  124. defer clean()
  125. cach := cache.NewCacheNode(r, sharedCalls, stats, mgo.ErrNotFound)
  126. c := newCollection(dummyConn{}, cach)
  127. for i := 0; i < 20; i++ {
  128. var str string
  129. err := c.cache.Take(&str, "name", func(v interface{}) error {
  130. return errors.New("db failed")
  131. })
  132. assert.NotNil(t, err)
  133. }
  134. assert.Equal(t, uint64(20), atomic.LoadUint64(&stats.Total))
  135. assert.Equal(t, uint64(0), atomic.LoadUint64(&stats.Hit))
  136. assert.Equal(t, uint64(20), atomic.LoadUint64(&stats.DbFails))
  137. }
  138. func TestStatFromMemory(t *testing.T) {
  139. resetStats()
  140. r, clean, err := redistest.CreateRedis()
  141. assert.Nil(t, err)
  142. defer clean()
  143. cach := cache.NewCacheNode(r, sharedCalls, stats, mgo.ErrNotFound)
  144. c := newCollection(dummyConn{}, cach)
  145. var all sync.WaitGroup
  146. var wait sync.WaitGroup
  147. all.Add(10)
  148. wait.Add(4)
  149. go func() {
  150. var str string
  151. if err := c.cache.Take(&str, "name", func(v interface{}) error {
  152. *v.(*string) = "zero"
  153. return nil
  154. }); err != nil {
  155. t.Error(err)
  156. }
  157. wait.Wait()
  158. runtime.Gosched()
  159. all.Done()
  160. }()
  161. for i := 0; i < 4; i++ {
  162. go func() {
  163. var str string
  164. wait.Done()
  165. if err := c.cache.Take(&str, "name", func(v interface{}) error {
  166. *v.(*string) = "zero"
  167. return nil
  168. }); err != nil {
  169. t.Error(err)
  170. }
  171. all.Done()
  172. }()
  173. }
  174. for i := 0; i < 5; i++ {
  175. go func() {
  176. var str string
  177. if err := c.cache.Take(&str, "name", func(v interface{}) error {
  178. *v.(*string) = "zero"
  179. return nil
  180. }); err != nil {
  181. t.Error(err)
  182. }
  183. all.Done()
  184. }()
  185. }
  186. all.Wait()
  187. assert.Equal(t, uint64(10), atomic.LoadUint64(&stats.Total))
  188. assert.Equal(t, uint64(9), atomic.LoadUint64(&stats.Hit))
  189. }
  190. func resetStats() {
  191. atomic.StoreUint64(&stats.Total, 0)
  192. atomic.StoreUint64(&stats.Hit, 0)
  193. atomic.StoreUint64(&stats.Miss, 0)
  194. atomic.StoreUint64(&stats.DbFails, 0)
  195. }
  196. type dummyConn struct {
  197. val string
  198. removeErr error
  199. updateErr error
  200. }
  201. func (c dummyConn) Find(query interface{}) mongo.Query {
  202. return dummyQuery{val: c.val}
  203. }
  204. func (c dummyConn) FindId(id interface{}) mongo.Query {
  205. return dummyQuery{val: c.val}
  206. }
  207. func (c dummyConn) Insert(docs ...interface{}) error {
  208. return nil
  209. }
  210. func (c dummyConn) Remove(selector interface{}) error {
  211. return c.removeErr
  212. }
  213. func (dummyConn) Pipe(pipeline interface{}) mongo.Pipe {
  214. return nil
  215. }
  216. func (c dummyConn) RemoveAll(selector interface{}) (*mgo.ChangeInfo, error) {
  217. return nil, c.removeErr
  218. }
  219. func (c dummyConn) RemoveId(id interface{}) error {
  220. return c.removeErr
  221. }
  222. func (c dummyConn) Update(selector, update interface{}) error {
  223. return c.updateErr
  224. }
  225. func (c dummyConn) UpdateId(id, update interface{}) error {
  226. return c.updateErr
  227. }
  228. func (c dummyConn) Upsert(selector, update interface{}) (*mgo.ChangeInfo, error) {
  229. return nil, c.updateErr
  230. }
  231. type dummyQuery struct {
  232. val string
  233. }
  234. func (d dummyQuery) All(result interface{}) error {
  235. return nil
  236. }
  237. func (d dummyQuery) Apply(change mgo.Change, result interface{}) (*mgo.ChangeInfo, error) {
  238. return nil, nil
  239. }
  240. func (d dummyQuery) Count() (int, error) {
  241. return dummyCount, nil
  242. }
  243. func (d dummyQuery) Distinct(key string, result interface{}) error {
  244. return nil
  245. }
  246. func (d dummyQuery) Explain(result interface{}) error {
  247. return nil
  248. }
  249. func (d dummyQuery) For(result interface{}, f func() error) error {
  250. return nil
  251. }
  252. func (d dummyQuery) MapReduce(job *mgo.MapReduce, result interface{}) (*mgo.MapReduceInfo, error) {
  253. return nil, nil
  254. }
  255. func (d dummyQuery) One(result interface{}) error {
  256. return json.Unmarshal([]byte(d.val), result)
  257. }
  258. func (d dummyQuery) Batch(n int) mongo.Query {
  259. return d
  260. }
  261. func (d dummyQuery) Collation(collation *mgo.Collation) mongo.Query {
  262. return d
  263. }
  264. func (d dummyQuery) Comment(comment string) mongo.Query {
  265. return d
  266. }
  267. func (d dummyQuery) Hint(indexKey ...string) mongo.Query {
  268. return d
  269. }
  270. func (d dummyQuery) Iter() mongo.Iter {
  271. return &mgo.Iter{}
  272. }
  273. func (d dummyQuery) Limit(n int) mongo.Query {
  274. return d
  275. }
  276. func (d dummyQuery) LogReplay() mongo.Query {
  277. return d
  278. }
  279. func (d dummyQuery) Prefetch(p float64) mongo.Query {
  280. return d
  281. }
  282. func (d dummyQuery) Select(selector interface{}) mongo.Query {
  283. return d
  284. }
  285. func (d dummyQuery) SetMaxScan(n int) mongo.Query {
  286. return d
  287. }
  288. func (d dummyQuery) SetMaxTime(duration time.Duration) mongo.Query {
  289. return d
  290. }
  291. func (d dummyQuery) Skip(n int) mongo.Query {
  292. return d
  293. }
  294. func (d dummyQuery) Snapshot() mongo.Query {
  295. return d
  296. }
  297. func (d dummyQuery) Sort(fields ...string) mongo.Query {
  298. return d
  299. }
  300. func (d dummyQuery) Tail(timeout time.Duration) mongo.Iter {
  301. return &mgo.Iter{}
  302. }