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.
 
 
 

275 lines
7.3 KiB

  1. // Copyright 2013 The Go Authors. All rights reserved.
  2. //
  3. // Use of this source code is governed by a BSD-style
  4. // license that can be found in the LICENSE file or at
  5. // https://developers.google.com/open-source/licenses/bsd.
  6. package database
  7. import (
  8. "math"
  9. "reflect"
  10. "strconv"
  11. "testing"
  12. "time"
  13. "github.com/garyburd/redigo/redis"
  14. "golang.org/x/net/context"
  15. "google.golang.org/appengine/aetest"
  16. "github.com/golang/gddo/doc"
  17. )
  18. func newDB(t *testing.T) *Database {
  19. p := redis.NewPool(func() (redis.Conn, error) {
  20. c, err := redis.DialTimeout("tcp", ":6379", 0, 1*time.Second, 1*time.Second)
  21. if err != nil {
  22. return nil, err
  23. }
  24. _, err = c.Do("SELECT", "9")
  25. if err != nil {
  26. c.Close()
  27. return nil, err
  28. }
  29. return c, nil
  30. }, 1)
  31. c := p.Get()
  32. defer c.Close()
  33. n, err := redis.Int(c.Do("DBSIZE"))
  34. if n != 0 || err != nil {
  35. t.Errorf("DBSIZE returned %d, %v", n, err)
  36. }
  37. return &Database{Pool: p}
  38. }
  39. func closeDB(db *Database) {
  40. c := db.Pool.Get()
  41. c.Do("FLUSHDB")
  42. c.Close()
  43. }
  44. func TestPutGet(t *testing.T) {
  45. var nextCrawl = time.Unix(time.Now().Add(time.Hour).Unix(), 0).UTC()
  46. ctx, done, err := aetest.NewContext()
  47. if err != nil {
  48. t.Fatal(err)
  49. }
  50. defer done()
  51. bgCtx = func() context.Context {
  52. return ctx
  53. }
  54. db := newDB(t)
  55. defer closeDB(db)
  56. pdoc := &doc.Package{
  57. ImportPath: "github.com/user/repo/foo/bar",
  58. Name: "bar",
  59. Synopsis: "hello",
  60. ProjectRoot: "github.com/user/repo",
  61. ProjectName: "foo",
  62. Updated: time.Now().Add(-time.Hour),
  63. Imports: []string{"C", "errors", "github.com/user/repo/foo/bar"}, // self import for testing convenience.
  64. }
  65. if err := db.Put(pdoc, nextCrawl, false); err != nil {
  66. t.Errorf("db.Put() returned error %v", err)
  67. }
  68. if err := db.Put(pdoc, time.Time{}, false); err != nil {
  69. t.Errorf("second db.Put() returned error %v", err)
  70. }
  71. actualPdoc, actualSubdirs, actualCrawl, err := db.Get("github.com/user/repo/foo/bar")
  72. if err != nil {
  73. t.Fatalf("db.Get(.../foo/bar) returned %v", err)
  74. }
  75. if len(actualSubdirs) != 0 {
  76. t.Errorf("db.Get(.../foo/bar) returned subdirs %v, want none", actualSubdirs)
  77. }
  78. if !reflect.DeepEqual(actualPdoc, pdoc) {
  79. t.Errorf("db.Get(.../foo/bar) returned doc %v, want %v", actualPdoc, pdoc)
  80. }
  81. if !nextCrawl.Equal(actualCrawl) {
  82. t.Errorf("db.Get(.../foo/bar) returned crawl %v, want %v", actualCrawl, nextCrawl)
  83. }
  84. before := time.Now().Unix()
  85. if err := db.BumpCrawl(pdoc.ProjectRoot); err != nil {
  86. t.Errorf("db.BumpCrawl() returned %v", err)
  87. }
  88. after := time.Now().Unix()
  89. _, _, actualCrawl, _ = db.Get("github.com/user/repo/foo/bar")
  90. if actualCrawl.Unix() < before || after < actualCrawl.Unix() {
  91. t.Errorf("actualCrawl=%v, expect value between %v and %v", actualCrawl.Unix(), before, after)
  92. }
  93. // Popular
  94. if err := db.IncrementPopularScore(pdoc.ImportPath); err != nil {
  95. t.Errorf("db.IncrementPopularScore() returned %v", err)
  96. }
  97. // Get "-"
  98. actualPdoc, _, _, err = db.Get("-")
  99. if err != nil {
  100. t.Fatalf("db.Get(-) returned %v", err)
  101. }
  102. if !reflect.DeepEqual(actualPdoc, pdoc) {
  103. t.Errorf("db.Get(-) returned doc %v, want %v", actualPdoc, pdoc)
  104. }
  105. actualPdoc, actualSubdirs, _, err = db.Get("github.com/user/repo/foo")
  106. if err != nil {
  107. t.Fatalf("db.Get(.../foo) returned %v", err)
  108. }
  109. if actualPdoc != nil {
  110. t.Errorf("db.Get(.../foo) returned doc %v, want %v", actualPdoc, nil)
  111. }
  112. expectedSubdirs := []Package{{Path: "github.com/user/repo/foo/bar", Synopsis: "hello"}}
  113. if !reflect.DeepEqual(actualSubdirs, expectedSubdirs) {
  114. t.Errorf("db.Get(.../foo) returned subdirs %v, want %v", actualSubdirs, expectedSubdirs)
  115. }
  116. actualImporters, err := db.Importers("github.com/user/repo/foo/bar")
  117. if err != nil {
  118. t.Fatalf("db.Importers() returned error %v", err)
  119. }
  120. expectedImporters := []Package{{Path: "github.com/user/repo/foo/bar", Synopsis: "hello"}}
  121. if !reflect.DeepEqual(actualImporters, expectedImporters) {
  122. t.Errorf("db.Importers() = %v, want %v", actualImporters, expectedImporters)
  123. }
  124. actualImports, err := db.Packages(pdoc.Imports)
  125. if err != nil {
  126. t.Fatalf("db.Imports() returned error %v", err)
  127. }
  128. for i := range actualImports {
  129. if actualImports[i].Path == "C" {
  130. actualImports[i].Synopsis = ""
  131. }
  132. }
  133. expectedImports := []Package{
  134. {Path: "C", Synopsis: ""},
  135. {Path: "errors", Synopsis: ""},
  136. {Path: "github.com/user/repo/foo/bar", Synopsis: "hello"},
  137. }
  138. if !reflect.DeepEqual(actualImports, expectedImports) {
  139. t.Errorf("db.Imports() = %v, want %v", actualImports, expectedImports)
  140. }
  141. importerCount, _ := db.ImporterCount("github.com/user/repo/foo/bar")
  142. if importerCount != 1 {
  143. t.Errorf("db.ImporterCount() = %d, want %d", importerCount, 1)
  144. }
  145. if err := db.Delete("github.com/user/repo/foo/bar"); err != nil {
  146. t.Errorf("db.Delete() returned error %v", err)
  147. }
  148. db.Query("bar")
  149. if err := db.Put(pdoc, time.Time{}, false); err != nil {
  150. t.Errorf("db.Put() returned error %v", err)
  151. }
  152. if err := db.Block("github.com/user/repo"); err != nil {
  153. t.Errorf("db.Block() returned error %v", err)
  154. }
  155. blocked, err := db.IsBlocked("github.com/user/repo/foo/bar")
  156. if !blocked || err != nil {
  157. t.Errorf("db.IsBlocked(github.com/user/repo/foo/bar) returned %v, %v, want true, nil", blocked, err)
  158. }
  159. blocked, err = db.IsBlocked("github.com/foo/bar")
  160. if blocked || err != nil {
  161. t.Errorf("db.IsBlocked(github.com/foo/bar) returned %v, %v, want false, nil", blocked, err)
  162. }
  163. c := db.Pool.Get()
  164. defer c.Close()
  165. c.Send("DEL", "maxQueryId")
  166. c.Send("DEL", "maxPackageId")
  167. c.Send("DEL", "block")
  168. c.Send("DEL", "popular:0")
  169. c.Send("DEL", "newCrawl")
  170. keys, err := redis.Values(c.Do("HKEYS", "ids"))
  171. for _, key := range keys {
  172. t.Errorf("unexpected id %s", key)
  173. }
  174. keys, err = redis.Values(c.Do("KEYS", "*"))
  175. for _, key := range keys {
  176. t.Errorf("unexpected key %s", key)
  177. }
  178. }
  179. const epsilon = 0.000001
  180. func TestPopular(t *testing.T) {
  181. db := newDB(t)
  182. defer closeDB(db)
  183. c := db.Pool.Get()
  184. defer c.Close()
  185. // Add scores for packages. On each iteration, add half-life to time and
  186. // divide the score by two. All packages should have the same score.
  187. now := time.Now()
  188. score := float64(4048)
  189. for id := 12; id >= 0; id-- {
  190. path := "github.com/user/repo/p" + strconv.Itoa(id)
  191. c.Do("HSET", "ids", path, id)
  192. err := db.incrementPopularScoreInternal(path, score, now)
  193. if err != nil {
  194. t.Fatal(err)
  195. }
  196. now = now.Add(popularHalfLife)
  197. score /= 2
  198. }
  199. values, _ := redis.Values(c.Do("ZRANGE", "popular", "0", "100000", "WITHSCORES"))
  200. if len(values) != 26 {
  201. t.Fatalf("Expected 26 values, got %d", len(values))
  202. }
  203. // Check for equal scores.
  204. score, err := redis.Float64(values[1], nil)
  205. if err != nil {
  206. t.Fatal(err)
  207. }
  208. for i := 3; i < len(values); i += 2 {
  209. s, _ := redis.Float64(values[i], nil)
  210. if math.Abs(score-s)/score > epsilon {
  211. t.Errorf("Bad score, score[1]=%g, score[%d]=%g", score, i, s)
  212. }
  213. }
  214. }
  215. func TestCounter(t *testing.T) {
  216. db := newDB(t)
  217. defer closeDB(db)
  218. const key = "127.0.0.1"
  219. now := time.Now()
  220. n, err := db.incrementCounterInternal(key, 1, now)
  221. if err != nil {
  222. t.Fatal(err)
  223. }
  224. if math.Abs(n-1.0) > epsilon {
  225. t.Errorf("1: got n=%g, want 1", n)
  226. }
  227. n, err = db.incrementCounterInternal(key, 1, now)
  228. if err != nil {
  229. t.Fatal(err)
  230. }
  231. if math.Abs(n-2.0)/2.0 > epsilon {
  232. t.Errorf("2: got n=%g, want 2", n)
  233. }
  234. now = now.Add(counterHalflife)
  235. n, err = db.incrementCounterInternal(key, 1, now)
  236. if err != nil {
  237. t.Fatal(err)
  238. }
  239. if math.Abs(n-2.0)/2.0 > epsilon {
  240. t.Errorf("3: got n=%g, want 2", n)
  241. }
  242. }