pipeline_test.go 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. package hercules
  2. import (
  3. "errors"
  4. "io"
  5. "io/ioutil"
  6. "os"
  7. "testing"
  8. "github.com/stretchr/testify/assert"
  9. "gopkg.in/src-d/go-git.v4"
  10. "gopkg.in/src-d/go-git.v4/plumbing"
  11. "gopkg.in/src-d/go-git.v4/plumbing/object"
  12. "gopkg.in/src-d/go-git.v4/storage/memory"
  13. "path"
  14. )
  15. type testPipelineItem struct {
  16. Initialized bool
  17. DepsConsumed bool
  18. CommitMatches bool
  19. IndexMatches bool
  20. TestError bool
  21. }
  22. func (item *testPipelineItem) Name() string {
  23. return "Test"
  24. }
  25. func (item *testPipelineItem) Provides() []string {
  26. arr := [...]string{"test"}
  27. return arr[:]
  28. }
  29. func (item *testPipelineItem) Requires() []string {
  30. return []string{}
  31. }
  32. func (item *testPipelineItem) Construct(facts map[string]interface{}) {
  33. }
  34. func (item *testPipelineItem) Initialize(repository *git.Repository) {
  35. item.Initialized = repository != nil
  36. }
  37. func (item *testPipelineItem) Consume(deps map[string]interface{}) (map[string]interface{}, error) {
  38. if item.TestError {
  39. return nil, errors.New("error")
  40. }
  41. obj, exists := deps["commit"]
  42. item.DepsConsumed = exists
  43. if item.DepsConsumed {
  44. commit := obj.(*object.Commit)
  45. item.CommitMatches = commit.Hash == plumbing.NewHash(
  46. "af9ddc0db70f09f3f27b4b98e415592a7485171c")
  47. obj, item.DepsConsumed = deps["index"]
  48. if item.DepsConsumed {
  49. item.IndexMatches = obj.(int) == 0
  50. }
  51. }
  52. return map[string]interface{}{"test": item}, nil
  53. }
  54. func (item *testPipelineItem) Finalize() interface{} {
  55. return item
  56. }
  57. type dependingTestPipelineItem struct {
  58. DependencySatisfied bool
  59. TestNilConsumeReturn bool
  60. }
  61. func (item *dependingTestPipelineItem) Name() string {
  62. return "Test2"
  63. }
  64. func (item *dependingTestPipelineItem) Provides() []string {
  65. arr := [...]string{"test2"}
  66. return arr[:]
  67. }
  68. func (item *dependingTestPipelineItem) Requires() []string {
  69. arr := [...]string{"test"}
  70. return arr[:]
  71. }
  72. func (item *dependingTestPipelineItem) Construct(facts map[string]interface{}) {
  73. }
  74. func (item *dependingTestPipelineItem) Initialize(repository *git.Repository) {
  75. }
  76. func (item *dependingTestPipelineItem) Consume(deps map[string]interface{}) (map[string]interface{}, error) {
  77. _, exists := deps["test"]
  78. item.DependencySatisfied = exists
  79. if !item.TestNilConsumeReturn {
  80. return map[string]interface{}{"test2": item}, nil
  81. } else {
  82. return nil, nil
  83. }
  84. }
  85. func (item *dependingTestPipelineItem) Finalize() interface{} {
  86. return item.DependencySatisfied
  87. }
  88. func TestPipelineRun(t *testing.T) {
  89. pipeline := NewPipeline(testRepository)
  90. item := &testPipelineItem{}
  91. pipeline.AddItem(item)
  92. pipeline.Initialize(map[string]interface{}{})
  93. assert.True(t, item.Initialized)
  94. commits := make([]*object.Commit, 1)
  95. commits[0], _ = testRepository.CommitObject(plumbing.NewHash(
  96. "af9ddc0db70f09f3f27b4b98e415592a7485171c"))
  97. result, err := pipeline.Run(commits)
  98. assert.Nil(t, err)
  99. assert.Equal(t, item, result[item].(*testPipelineItem))
  100. assert.True(t, item.DepsConsumed)
  101. assert.True(t, item.CommitMatches)
  102. assert.True(t, item.IndexMatches)
  103. pipeline.RemoveItem(item)
  104. result, err = pipeline.Run(commits)
  105. assert.Nil(t, err)
  106. assert.Equal(t, 0, len(result))
  107. }
  108. func TestPipelineOnProgress(t *testing.T) {
  109. pipeline := NewPipeline(testRepository)
  110. var progressOk1, progressOk2 bool
  111. onProgress := func(step int, total int) {
  112. if step == 0 && total == 1 {
  113. progressOk1 = true
  114. }
  115. if step == 1 && total == 1 && progressOk1 {
  116. progressOk2 = true
  117. }
  118. }
  119. pipeline.OnProgress = onProgress
  120. commits := make([]*object.Commit, 1)
  121. commits[0], _ = testRepository.CommitObject(plumbing.NewHash(
  122. "af9ddc0db70f09f3f27b4b98e415592a7485171c"))
  123. result, err := pipeline.Run(commits)
  124. assert.Nil(t, err)
  125. assert.Equal(t, 0, len(result))
  126. assert.True(t, progressOk1)
  127. assert.True(t, progressOk2)
  128. }
  129. func TestPipelineCommits(t *testing.T) {
  130. pipeline := NewPipeline(testRepository)
  131. commits := pipeline.Commits()
  132. assert.True(t, len(commits) >= 90)
  133. assert.Equal(t, commits[0].Hash, plumbing.NewHash(
  134. "cce947b98a050c6d356bc6ba95030254914027b1"))
  135. assert.Equal(t, commits[89].Hash, plumbing.NewHash(
  136. "6db8065cdb9bb0758f36a7e75fc72ab95f9e8145"))
  137. assert.NotEqual(t, commits[len(commits)-1], commits[len(commits)-2])
  138. }
  139. func TestLoadCommitsFromFile(t *testing.T) {
  140. tmp, err := ioutil.TempFile("", "hercules-test-")
  141. assert.Nil(t, err)
  142. tmp.WriteString("cce947b98a050c6d356bc6ba95030254914027b1\n6db8065cdb9bb0758f36a7e75fc72ab95f9e8145")
  143. tmp.Close()
  144. defer os.Remove(tmp.Name())
  145. commits, err := LoadCommitsFromFile(tmp.Name(), testRepository)
  146. assert.Nil(t, err)
  147. assert.Equal(t, len(commits), 2)
  148. assert.Equal(t, commits[0].Hash, plumbing.NewHash(
  149. "cce947b98a050c6d356bc6ba95030254914027b1"))
  150. assert.Equal(t, commits[1].Hash, plumbing.NewHash(
  151. "6db8065cdb9bb0758f36a7e75fc72ab95f9e8145"))
  152. commits, err = LoadCommitsFromFile("/WAT?xxx!", testRepository)
  153. assert.Nil(t, commits)
  154. assert.NotNil(t, err)
  155. tmp, err = ioutil.TempFile("", "hercules-test-")
  156. assert.Nil(t, err)
  157. tmp.WriteString("WAT")
  158. tmp.Close()
  159. defer os.Remove(tmp.Name())
  160. commits, err = LoadCommitsFromFile(tmp.Name(), testRepository)
  161. assert.Nil(t, commits)
  162. assert.NotNil(t, err)
  163. tmp, err = ioutil.TempFile("", "hercules-test-")
  164. assert.Nil(t, err)
  165. tmp.WriteString("ffffffffffffffffffffffffffffffffffffffff")
  166. tmp.Close()
  167. defer os.Remove(tmp.Name())
  168. commits, err = LoadCommitsFromFile(tmp.Name(), testRepository)
  169. assert.Nil(t, commits)
  170. assert.NotNil(t, err)
  171. }
  172. func TestPipelineDeps(t *testing.T) {
  173. pipeline := NewPipeline(testRepository)
  174. item1 := &dependingTestPipelineItem{}
  175. item2 := &testPipelineItem{}
  176. pipeline.AddItem(item1)
  177. pipeline.AddItem(item2)
  178. pipeline.Initialize(map[string]interface{}{})
  179. commits := make([]*object.Commit, 1)
  180. commits[0], _ = testRepository.CommitObject(plumbing.NewHash(
  181. "af9ddc0db70f09f3f27b4b98e415592a7485171c"))
  182. result, err := pipeline.Run(commits)
  183. assert.Nil(t, err)
  184. assert.True(t, result[item1].(bool))
  185. item1.TestNilConsumeReturn = true
  186. assert.Panics(t, func() { pipeline.Run(commits) })
  187. }
  188. func TestPipelineError(t *testing.T) {
  189. pipeline := NewPipeline(testRepository)
  190. item := &testPipelineItem{}
  191. item.TestError = true
  192. pipeline.AddItem(item)
  193. pipeline.Initialize(map[string]interface{}{})
  194. commits := make([]*object.Commit, 1)
  195. commits[0], _ = testRepository.CommitObject(plumbing.NewHash(
  196. "af9ddc0db70f09f3f27b4b98e415592a7485171c"))
  197. result, err := pipeline.Run(commits)
  198. assert.Nil(t, result)
  199. assert.NotNil(t, err)
  200. }
  201. func TestPipelineSerialize(t *testing.T) {
  202. pipeline := NewPipeline(testRepository)
  203. pipeline.DeployItem(&BurndownAnalysis{})
  204. facts := map[string]interface{}{}
  205. facts["Pipeline.DryRun"] = true
  206. tmpdir, _ := ioutil.TempDir("", "hercules-")
  207. defer os.RemoveAll(tmpdir)
  208. dotpath := path.Join(tmpdir, "graph.dot")
  209. facts["Pipeline.DumpPath"] = dotpath
  210. pipeline.Initialize(facts)
  211. bdot, _ := ioutil.ReadFile(dotpath)
  212. dot := string(bdot)
  213. assert.Equal(t, `digraph Hercules {
  214. "6 BlobCache" -> "7 [blob_cache]"
  215. "0 DaysSinceStart" -> "3 [day]"
  216. "10 FileDiff" -> "12 [file_diff]"
  217. "15 FileDiffRefiner" -> "16 Burndown"
  218. "1 IdentityDetector" -> "4 [author]"
  219. "8 RenameAnalysis" -> "16 Burndown"
  220. "8 RenameAnalysis" -> "10 FileDiff"
  221. "8 RenameAnalysis" -> "9 UAST"
  222. "8 RenameAnalysis" -> "13 UASTChanges"
  223. "2 TreeDiff" -> "5 [changes]"
  224. "9 UAST" -> "11 [uasts]"
  225. "13 UASTChanges" -> "14 [changed_uasts]"
  226. "4 [author]" -> "16 Burndown"
  227. "7 [blob_cache]" -> "16 Burndown"
  228. "7 [blob_cache]" -> "10 FileDiff"
  229. "7 [blob_cache]" -> "8 RenameAnalysis"
  230. "7 [blob_cache]" -> "9 UAST"
  231. "14 [changed_uasts]" -> "15 FileDiffRefiner"
  232. "5 [changes]" -> "6 BlobCache"
  233. "5 [changes]" -> "8 RenameAnalysis"
  234. "3 [day]" -> "16 Burndown"
  235. "12 [file_diff]" -> "15 FileDiffRefiner"
  236. "11 [uasts]" -> "13 UASTChanges"
  237. }`, dot)
  238. }
  239. func init() {
  240. cwd, err := os.Getwd()
  241. if err == nil {
  242. testRepository, err = git.PlainOpen(cwd)
  243. if err == nil {
  244. iter, err := testRepository.CommitObjects()
  245. if err == nil {
  246. commits := -1
  247. for ; err != io.EOF; _, err = iter.Next() {
  248. if err != nil {
  249. panic(err)
  250. }
  251. commits++
  252. if commits >= 100 {
  253. return
  254. }
  255. }
  256. }
  257. }
  258. }
  259. testRepository, _ = git.Clone(memory.NewStorage(), nil, &git.CloneOptions{
  260. URL: "https://github.com/src-d/hercules",
  261. })
  262. }