pipeline_test.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663
  1. package core
  2. import (
  3. "errors"
  4. "fmt"
  5. "io"
  6. "io/ioutil"
  7. "os"
  8. "testing"
  9. "time"
  10. "github.com/stretchr/testify/assert"
  11. "gopkg.in/src-d/go-git.v4"
  12. "gopkg.in/src-d/go-git.v4/plumbing"
  13. "gopkg.in/src-d/go-git.v4/plumbing/object"
  14. "gopkg.in/src-d/hercules.v4/internal/pb"
  15. "gopkg.in/src-d/hercules.v4/internal/test"
  16. )
  17. type testPipelineItem struct {
  18. Initialized bool
  19. DepsConsumed bool
  20. Forked bool
  21. Merged *bool
  22. CommitMatches bool
  23. IndexMatches bool
  24. TestError bool
  25. }
  26. func (item *testPipelineItem) Name() string {
  27. return "Test"
  28. }
  29. func (item *testPipelineItem) Provides() []string {
  30. arr := [...]string{"test"}
  31. return arr[:]
  32. }
  33. func (item *testPipelineItem) Requires() []string {
  34. return []string{}
  35. }
  36. func (item *testPipelineItem) Configure(facts map[string]interface{}) {
  37. }
  38. func (item *testPipelineItem) ListConfigurationOptions() []ConfigurationOption {
  39. options := [...]ConfigurationOption{{
  40. Name: "TestOption",
  41. Description: "The option description.",
  42. Flag: "test-option",
  43. Type: IntConfigurationOption,
  44. Default: 10,
  45. }}
  46. return options[:]
  47. }
  48. func (item *testPipelineItem) Flag() string {
  49. return "mytest"
  50. }
  51. func (item *testPipelineItem) Features() []string {
  52. f := [...]string{"power"}
  53. return f[:]
  54. }
  55. func (item *testPipelineItem) Initialize(repository *git.Repository) {
  56. item.Initialized = repository != nil
  57. }
  58. func (item *testPipelineItem) Consume(deps map[string]interface{}) (map[string]interface{}, error) {
  59. if item.TestError {
  60. return nil, errors.New("error")
  61. }
  62. obj, exists := deps[DependencyCommit]
  63. item.DepsConsumed = exists
  64. if item.DepsConsumed {
  65. commit := obj.(*object.Commit)
  66. item.CommitMatches = commit.Hash == plumbing.NewHash(
  67. "af9ddc0db70f09f3f27b4b98e415592a7485171c")
  68. obj, item.DepsConsumed = deps[DependencyIndex]
  69. if item.DepsConsumed {
  70. item.IndexMatches = obj.(int) == 0
  71. }
  72. }
  73. return map[string]interface{}{"test": item}, nil
  74. }
  75. func (item *testPipelineItem) Fork(n int) []PipelineItem {
  76. result := make([]PipelineItem, n)
  77. for i := 0; i < n; i++ {
  78. result[i] = &testPipelineItem{Merged: item.Merged}
  79. }
  80. item.Forked = true
  81. return result
  82. }
  83. func (item *testPipelineItem) Merge(branches []PipelineItem) {
  84. *item.Merged = true
  85. }
  86. func (item *testPipelineItem) Finalize() interface{} {
  87. return item
  88. }
  89. func (item *testPipelineItem) Serialize(result interface{}, binary bool, writer io.Writer) error {
  90. return nil
  91. }
  92. type dependingTestPipelineItem struct {
  93. DependencySatisfied bool
  94. TestNilConsumeReturn bool
  95. }
  96. func (item *dependingTestPipelineItem) Name() string {
  97. return "Test2"
  98. }
  99. func (item *dependingTestPipelineItem) Provides() []string {
  100. arr := [...]string{"test2"}
  101. return arr[:]
  102. }
  103. func (item *dependingTestPipelineItem) Requires() []string {
  104. arr := [...]string{"test"}
  105. return arr[:]
  106. }
  107. func (item *dependingTestPipelineItem) ListConfigurationOptions() []ConfigurationOption {
  108. options := [...]ConfigurationOption{{
  109. Name: "TestOption2",
  110. Description: "The option description.",
  111. Flag: "test-option2",
  112. Type: IntConfigurationOption,
  113. Default: 10,
  114. }}
  115. return options[:]
  116. }
  117. func (item *dependingTestPipelineItem) Configure(facts map[string]interface{}) {
  118. }
  119. func (item *dependingTestPipelineItem) Initialize(repository *git.Repository) {
  120. }
  121. func (item *dependingTestPipelineItem) Flag() string {
  122. return "depflag"
  123. }
  124. func (item *dependingTestPipelineItem) Consume(deps map[string]interface{}) (map[string]interface{}, error) {
  125. _, exists := deps["test"]
  126. item.DependencySatisfied = exists
  127. if !item.TestNilConsumeReturn {
  128. return map[string]interface{}{"test2": item}, nil
  129. }
  130. return nil, nil
  131. }
  132. func (item *dependingTestPipelineItem) Fork(n int) []PipelineItem {
  133. return make([]PipelineItem, n)
  134. }
  135. func (item *dependingTestPipelineItem) Merge(branches []PipelineItem) {
  136. }
  137. func (item *dependingTestPipelineItem) Finalize() interface{} {
  138. return true
  139. }
  140. func (item *dependingTestPipelineItem) Serialize(result interface{}, binary bool, writer io.Writer) error {
  141. return nil
  142. }
  143. func TestPipelineFacts(t *testing.T) {
  144. pipeline := NewPipeline(test.Repository)
  145. pipeline.SetFact("fact", "value")
  146. assert.Equal(t, pipeline.GetFact("fact"), "value")
  147. }
  148. func TestPipelineFeatures(t *testing.T) {
  149. pipeline := NewPipeline(test.Repository)
  150. pipeline.SetFeature("feat")
  151. val, _ := pipeline.GetFeature("feat")
  152. assert.True(t, val)
  153. _, exists := pipeline.GetFeature("!")
  154. assert.False(t, exists)
  155. Registry.featureFlags.Set("777")
  156. defer func() {
  157. Registry.featureFlags = arrayFeatureFlags{Flags: []string{}, Choices: map[string]bool{}}
  158. }()
  159. pipeline.SetFeaturesFromFlags()
  160. _, exists = pipeline.GetFeature("777")
  161. assert.False(t, exists)
  162. assert.Panics(t, func() {
  163. pipeline.SetFeaturesFromFlags(
  164. &PipelineItemRegistry{}, &PipelineItemRegistry{})
  165. })
  166. }
  167. func TestPipelineRun(t *testing.T) {
  168. pipeline := NewPipeline(test.Repository)
  169. item := &testPipelineItem{Merged: new(bool)}
  170. pipeline.AddItem(item)
  171. pipeline.Initialize(map[string]interface{}{})
  172. assert.True(t, item.Initialized)
  173. commits := make([]*object.Commit, 1)
  174. commits[0], _ = test.Repository.CommitObject(plumbing.NewHash(
  175. "af9ddc0db70f09f3f27b4b98e415592a7485171c"))
  176. result, err := pipeline.Run(commits)
  177. assert.Nil(t, err)
  178. assert.Equal(t, 2, len(result))
  179. assert.Equal(t, item, result[item].(*testPipelineItem))
  180. common := result[nil].(*CommonAnalysisResult)
  181. assert.Equal(t, common.BeginTime, int64(1481719198))
  182. assert.Equal(t, common.EndTime, int64(1481719198))
  183. assert.Equal(t, common.CommitsNumber, 1)
  184. assert.True(t, common.RunTime.Nanoseconds()/1e6 < 100)
  185. assert.True(t, item.DepsConsumed)
  186. assert.True(t, item.CommitMatches)
  187. assert.True(t, item.IndexMatches)
  188. assert.True(t, item.Forked)
  189. assert.False(t, *item.Merged)
  190. pipeline.RemoveItem(item)
  191. result, err = pipeline.Run(commits)
  192. assert.Nil(t, err)
  193. assert.Equal(t, 1, len(result))
  194. }
  195. func TestPipelineRunBranches(t *testing.T) {
  196. pipeline := NewPipeline(test.Repository)
  197. item := &testPipelineItem{Merged: new(bool)}
  198. pipeline.AddItem(item)
  199. pipeline.Initialize(map[string]interface{}{})
  200. assert.True(t, item.Initialized)
  201. commits := make([]*object.Commit, 5)
  202. hashes := []string {
  203. "6db8065cdb9bb0758f36a7e75fc72ab95f9e8145",
  204. "f30daba81ff2bf0b3ba02a1e1441e74f8a4f6fee",
  205. "8a03b5620b1caa72ec9cb847ea88332621e2950a",
  206. "dd9dd084d5851d7dc4399fc7dbf3d8292831ebc5",
  207. "f4ed0405b14f006c0744029d87ddb3245607587a",
  208. }
  209. for i, h := range hashes {
  210. var err error
  211. commits[i], err = test.Repository.CommitObject(plumbing.NewHash(h))
  212. if err != nil {
  213. t.Fatal(err)
  214. }
  215. }
  216. result, err := pipeline.Run(commits)
  217. assert.Nil(t, err)
  218. assert.True(t, item.Forked)
  219. assert.True(t, *item.Merged)
  220. assert.Equal(t, 2, len(result))
  221. assert.Equal(t, item, result[item].(*testPipelineItem))
  222. common := result[nil].(*CommonAnalysisResult)
  223. assert.Equal(t, common.CommitsNumber, 5)
  224. }
  225. func TestPipelineOnProgress(t *testing.T) {
  226. pipeline := NewPipeline(test.Repository)
  227. progressOk := 0
  228. onProgress := func(step int, total int) {
  229. if step == 1 && total == 4 {
  230. progressOk++
  231. }
  232. if step == 2 && total == 4 {
  233. progressOk++
  234. }
  235. if step == 3 && total == 4 {
  236. progressOk++
  237. }
  238. if step == 4 && total == 4 {
  239. progressOk++
  240. }
  241. }
  242. pipeline.OnProgress = onProgress
  243. commits := make([]*object.Commit, 1)
  244. commits[0], _ = test.Repository.CommitObject(plumbing.NewHash(
  245. "af9ddc0db70f09f3f27b4b98e415592a7485171c"))
  246. result, err := pipeline.Run(commits)
  247. assert.Nil(t, err)
  248. assert.Equal(t, 1, len(result))
  249. assert.Equal(t, 4, progressOk)
  250. }
  251. func TestPipelineCommitsFull(t *testing.T) {
  252. pipeline := NewPipeline(test.Repository)
  253. commits, err := pipeline.Commits(false)
  254. assert.Nil(t, err)
  255. assert.True(t, len(commits) >= 100)
  256. hashMap := map[plumbing.Hash]bool{}
  257. for _, c := range commits {
  258. hashMap[c.Hash] = true
  259. }
  260. assert.Equal(t, len(commits), len(hashMap))
  261. assert.Contains(t, hashMap, plumbing.NewHash(
  262. "cce947b98a050c6d356bc6ba95030254914027b1"))
  263. assert.Contains(t, hashMap, plumbing.NewHash(
  264. "a3ee37f91f0d705ec9c41ae88426f0ae44b2fbc3"))
  265. }
  266. func TestPipelineCommitsFirstParent(t *testing.T) {
  267. pipeline := NewPipeline(test.Repository)
  268. commits, err := pipeline.Commits(true)
  269. assert.Nil(t, err)
  270. assert.True(t, len(commits) >= 100)
  271. hashMap := map[plumbing.Hash]bool{}
  272. for _, c := range commits {
  273. hashMap[c.Hash] = true
  274. }
  275. assert.Equal(t, len(commits), len(hashMap))
  276. assert.Contains(t, hashMap, plumbing.NewHash(
  277. "cce947b98a050c6d356bc6ba95030254914027b1"))
  278. assert.NotContains(t, hashMap, plumbing.NewHash(
  279. "a3ee37f91f0d705ec9c41ae88426f0ae44b2fbc3"))
  280. }
  281. func TestLoadCommitsFromFile(t *testing.T) {
  282. tmp, err := ioutil.TempFile("", "hercules-test-")
  283. assert.Nil(t, err)
  284. tmp.WriteString("cce947b98a050c6d356bc6ba95030254914027b1\n6db8065cdb9bb0758f36a7e75fc72ab95f9e8145")
  285. tmp.Close()
  286. defer os.Remove(tmp.Name())
  287. commits, err := LoadCommitsFromFile(tmp.Name(), test.Repository)
  288. assert.Nil(t, err)
  289. assert.Equal(t, len(commits), 2)
  290. assert.Equal(t, commits[0].Hash, plumbing.NewHash(
  291. "cce947b98a050c6d356bc6ba95030254914027b1"))
  292. assert.Equal(t, commits[1].Hash, plumbing.NewHash(
  293. "6db8065cdb9bb0758f36a7e75fc72ab95f9e8145"))
  294. commits, err = LoadCommitsFromFile("/WAT?xxx!", test.Repository)
  295. assert.Nil(t, commits)
  296. assert.NotNil(t, err)
  297. tmp, err = ioutil.TempFile("", "hercules-test-")
  298. assert.Nil(t, err)
  299. tmp.WriteString("WAT")
  300. tmp.Close()
  301. defer os.Remove(tmp.Name())
  302. commits, err = LoadCommitsFromFile(tmp.Name(), test.Repository)
  303. assert.Nil(t, commits)
  304. assert.NotNil(t, err)
  305. tmp, err = ioutil.TempFile("", "hercules-test-")
  306. assert.Nil(t, err)
  307. tmp.WriteString("ffffffffffffffffffffffffffffffffffffffff")
  308. tmp.Close()
  309. defer os.Remove(tmp.Name())
  310. commits, err = LoadCommitsFromFile(tmp.Name(), test.Repository)
  311. assert.Nil(t, commits)
  312. assert.NotNil(t, err)
  313. }
  314. func TestPipelineDeps(t *testing.T) {
  315. pipeline := NewPipeline(test.Repository)
  316. item1 := &dependingTestPipelineItem{}
  317. item2 := &testPipelineItem{}
  318. pipeline.AddItem(item1)
  319. pipeline.AddItem(item2)
  320. assert.Equal(t, pipeline.Len(), 2)
  321. pipeline.Initialize(map[string]interface{}{})
  322. commits := make([]*object.Commit, 1)
  323. commits[0], _ = test.Repository.CommitObject(plumbing.NewHash(
  324. "af9ddc0db70f09f3f27b4b98e415592a7485171c"))
  325. result, err := pipeline.Run(commits)
  326. assert.Nil(t, err)
  327. assert.True(t, result[item1].(bool))
  328. assert.Equal(t, result[item2], item2)
  329. item1.TestNilConsumeReturn = true
  330. assert.Panics(t, func() { pipeline.Run(commits) })
  331. }
  332. func TestPipelineDeployFeatures(t *testing.T) {
  333. pipeline := NewPipeline(test.Repository)
  334. pipeline.DeployItem(&testPipelineItem{})
  335. f, _ := pipeline.GetFeature("power")
  336. assert.True(t, f)
  337. }
  338. func TestPipelineError(t *testing.T) {
  339. pipeline := NewPipeline(test.Repository)
  340. item := &testPipelineItem{}
  341. item.TestError = true
  342. pipeline.AddItem(item)
  343. pipeline.Initialize(map[string]interface{}{})
  344. commits := make([]*object.Commit, 1)
  345. commits[0], _ = test.Repository.CommitObject(plumbing.NewHash(
  346. "af9ddc0db70f09f3f27b4b98e415592a7485171c"))
  347. result, err := pipeline.Run(commits)
  348. assert.Nil(t, result)
  349. assert.NotNil(t, err)
  350. }
  351. func TestCommonAnalysisResultMerge(t *testing.T) {
  352. c1 := CommonAnalysisResult{
  353. BeginTime: 1513620635, EndTime: 1513720635, CommitsNumber: 1, RunTime: 100}
  354. assert.Equal(t, c1.BeginTimeAsTime().Unix(), int64(1513620635))
  355. assert.Equal(t, c1.EndTimeAsTime().Unix(), int64(1513720635))
  356. c2 := CommonAnalysisResult{
  357. BeginTime: 1513620535, EndTime: 1513730635, CommitsNumber: 2, RunTime: 200}
  358. c1.Merge(&c2)
  359. assert.Equal(t, c1.BeginTime, int64(1513620535))
  360. assert.Equal(t, c1.EndTime, int64(1513730635))
  361. assert.Equal(t, c1.CommitsNumber, 3)
  362. assert.Equal(t, c1.RunTime.Nanoseconds(), int64(300))
  363. }
  364. func TestCommonAnalysisResultMetadata(t *testing.T) {
  365. c1 := &CommonAnalysisResult{
  366. BeginTime: 1513620635, EndTime: 1513720635, CommitsNumber: 1, RunTime: 100 * 1e6}
  367. meta := &pb.Metadata{}
  368. c1 = MetadataToCommonAnalysisResult(c1.FillMetadata(meta))
  369. assert.Equal(t, c1.BeginTimeAsTime().Unix(), int64(1513620635))
  370. assert.Equal(t, c1.EndTimeAsTime().Unix(), int64(1513720635))
  371. assert.Equal(t, c1.CommitsNumber, 1)
  372. assert.Equal(t, c1.RunTime.Nanoseconds(), int64(100*1e6))
  373. }
  374. func TestConfigurationOptionTypeString(t *testing.T) {
  375. opt := ConfigurationOptionType(0)
  376. assert.Equal(t, opt.String(), "")
  377. opt = ConfigurationOptionType(1)
  378. assert.Equal(t, opt.String(), "int")
  379. opt = ConfigurationOptionType(2)
  380. assert.Equal(t, opt.String(), "string")
  381. opt = ConfigurationOptionType(3)
  382. assert.Equal(t, opt.String(), "float")
  383. opt = ConfigurationOptionType(4)
  384. assert.Equal(t, opt.String(), "string")
  385. opt = ConfigurationOptionType(5)
  386. assert.Panics(t, func() { _ = opt.String() })
  387. }
  388. func TestConfigurationOptionFormatDefault(t *testing.T) {
  389. opt := ConfigurationOption{Type: StringConfigurationOption, Default: "ololo"}
  390. assert.Equal(t, opt.FormatDefault(), "\"ololo\"")
  391. opt = ConfigurationOption{Type: IntConfigurationOption, Default: 7}
  392. assert.Equal(t, opt.FormatDefault(), "7")
  393. opt = ConfigurationOption{Type: BoolConfigurationOption, Default: false}
  394. assert.Equal(t, opt.FormatDefault(), "false")
  395. opt = ConfigurationOption{Type: FloatConfigurationOption, Default: 0.5}
  396. assert.Equal(t, opt.FormatDefault(), "0.5")
  397. }
  398. func TestPrepareRunPlanTiny(t *testing.T) {
  399. rootCommit, err := test.Repository.CommitObject(plumbing.NewHash(
  400. "cce947b98a050c6d356bc6ba95030254914027b1"))
  401. if err != nil {
  402. t.Fatal(err)
  403. }
  404. plan := prepareRunPlan([]*object.Commit{rootCommit})
  405. assert.Len(t, plan, 2)
  406. assert.Equal(t, runActionEmerge, plan[0].Action)
  407. assert.Equal(t, 0, plan[0].Items[0])
  408. assert.Equal(t, "cce947b98a050c6d356bc6ba95030254914027b1", plan[0].Commit.Hash.String())
  409. assert.Equal(t, runActionCommit, plan[1].Action)
  410. assert.Equal(t, 0, plan[1].Items[0])
  411. assert.Equal(t, "cce947b98a050c6d356bc6ba95030254914027b1", plan[1].Commit.Hash.String())
  412. }
  413. func TestPrepareRunPlanSmall(t *testing.T) {
  414. cit, err := test.Repository.Log(&git.LogOptions{From: plumbing.ZeroHash})
  415. if err != nil {
  416. panic(err)
  417. }
  418. defer cit.Close()
  419. var commits []*object.Commit
  420. timeCutoff := time.Date(2016, 12, 15, 0, 0, 0, 0, time.FixedZone("CET", 7200))
  421. cit.ForEach(func(commit *object.Commit) error {
  422. reliableTime := time.Date(commit.Author.When.Year(), commit.Author.When.Month(),
  423. commit.Author.When.Day(), commit.Author.When.Hour(), commit.Author.When.Minute(),
  424. commit.Author.When.Second(), 0, time.FixedZone("CET", 7200))
  425. if reliableTime.Before(timeCutoff) {
  426. commits = append(commits, commit)
  427. }
  428. return nil
  429. })
  430. plan := prepareRunPlan(commits)
  431. /*for _, p := range plan {
  432. if p.Commit != nil {
  433. fmt.Println(p.Action, p.Commit.Hash.String(), p.Items)
  434. } else {
  435. fmt.Println(p.Action, strings.Repeat(" ", 40), p.Items)
  436. }
  437. }*/
  438. // fork, merge and one artificial commit per branch
  439. assert.Len(t, plan, len(commits) + 1)
  440. assert.Equal(t, runActionEmerge, plan[0].Action)
  441. assert.Equal(t, "cce947b98a050c6d356bc6ba95030254914027b1", plan[0].Commit.Hash.String())
  442. assert.Equal(t, 0, plan[0].Items[0])
  443. assert.Equal(t, runActionCommit, plan[1].Action)
  444. assert.Equal(t, 0, plan[1].Items[0])
  445. assert.Equal(t, "cce947b98a050c6d356bc6ba95030254914027b1", plan[1].Commit.Hash.String())
  446. assert.Equal(t, runActionCommit, plan[2].Action)
  447. assert.Equal(t, 0, plan[2].Items[0])
  448. assert.Equal(t, "a3ee37f91f0d705ec9c41ae88426f0ae44b2fbc3", plan[2].Commit.Hash.String())
  449. assert.Equal(t, runActionCommit, plan[10].Action)
  450. assert.Equal(t, 0, plan[10].Items[0])
  451. assert.Equal(t, "a28e9064c70618dc9d68e1401b889975e0680d11", plan[10].Commit.Hash.String())
  452. }
  453. func TestMergeDag(t *testing.T) {
  454. cit, err := test.Repository.Log(&git.LogOptions{From: plumbing.ZeroHash})
  455. if err != nil {
  456. panic(err)
  457. }
  458. defer cit.Close()
  459. var commits []*object.Commit
  460. timeCutoff := time.Date(2017, 8, 12, 0, 0, 0, 0, time.FixedZone("CET", 7200))
  461. cit.ForEach(func(commit *object.Commit) error {
  462. reliableTime := time.Date(commit.Author.When.Year(), commit.Author.When.Month(),
  463. commit.Author.When.Day(), commit.Author.When.Hour(), commit.Author.When.Minute(),
  464. commit.Author.When.Second(), 0, time.FixedZone("CET", 7200))
  465. if reliableTime.Before(timeCutoff) {
  466. commits = append(commits, commit)
  467. }
  468. return nil
  469. })
  470. hashes, dag := buildDag(commits)
  471. leaveRootComponent(hashes, dag)
  472. mergedDag, _ := mergeDag(hashes, dag)
  473. for key, vals := range mergedDag {
  474. if key != plumbing.NewHash("a28e9064c70618dc9d68e1401b889975e0680d11") &&
  475. key != plumbing.NewHash("db325a212d0bc99b470e000641d814745024bbd5") {
  476. assert.Len(t, vals, len(dag[key]), key.String())
  477. } else {
  478. mvals := map[string]bool{}
  479. for _, val := range vals {
  480. mvals[val.Hash.String()] = true
  481. }
  482. if key == plumbing.NewHash("a28e9064c70618dc9d68e1401b889975e0680d11") {
  483. assert.Contains(t, mvals, "db325a212d0bc99b470e000641d814745024bbd5")
  484. assert.Contains(t, mvals, "be9b61e09b08b98e64ed461a4004c9e2412f78ee")
  485. }
  486. if key == plumbing.NewHash("db325a212d0bc99b470e000641d814745024bbd5") {
  487. assert.Contains(t, mvals, "f30daba81ff2bf0b3ba02a1e1441e74f8a4f6fee")
  488. assert.Contains(t, mvals, "8a03b5620b1caa72ec9cb847ea88332621e2950a")
  489. }
  490. }
  491. }
  492. assert.Len(t, mergedDag, 8)
  493. assert.Contains(t, mergedDag, plumbing.NewHash("cce947b98a050c6d356bc6ba95030254914027b1"))
  494. assert.Contains(t, mergedDag, plumbing.NewHash("a3ee37f91f0d705ec9c41ae88426f0ae44b2fbc3"))
  495. assert.Contains(t, mergedDag, plumbing.NewHash("a28e9064c70618dc9d68e1401b889975e0680d11"))
  496. assert.Contains(t, mergedDag, plumbing.NewHash("be9b61e09b08b98e64ed461a4004c9e2412f78ee"))
  497. assert.Contains(t, mergedDag, plumbing.NewHash("db325a212d0bc99b470e000641d814745024bbd5"))
  498. assert.Contains(t, mergedDag, plumbing.NewHash("f30daba81ff2bf0b3ba02a1e1441e74f8a4f6fee"))
  499. assert.Contains(t, mergedDag, plumbing.NewHash("8a03b5620b1caa72ec9cb847ea88332621e2950a"))
  500. assert.Contains(t, mergedDag, plumbing.NewHash("dd9dd084d5851d7dc4399fc7dbf3d8292831ebc5"))
  501. queue := []plumbing.Hash{plumbing.NewHash("cce947b98a050c6d356bc6ba95030254914027b1")}
  502. visited := map[plumbing.Hash]bool{}
  503. for len(queue) > 0 {
  504. head := queue[len(queue)-1]
  505. queue = queue[:len(queue)-1]
  506. if visited[head] {
  507. continue
  508. }
  509. visited[head] = true
  510. for _, child := range mergedDag[head] {
  511. queue = append(queue, child.Hash)
  512. }
  513. }
  514. assert.Len(t, visited, 8)
  515. }
  516. func TestPrepareRunPlanBig(t *testing.T) {
  517. cases := [][7]int {
  518. {2017, 8, 9, 0, 0, 0, 0},
  519. {2017, 8, 10, 0, 0, 0, 0},
  520. {2017, 8, 24, 1, 1, 1, 1},
  521. {2017, 9, 19, 1-2, 1, 1, 1},
  522. {2017, 9, 23, 1-2, 1, 1, 1},
  523. {2017, 12, 8, 1, 1, 1, 1},
  524. {2017, 12, 9, 1, 1, 1, 1},
  525. {2017, 12, 10, 1, 1, 1, 1},
  526. {2017, 12, 11, 2, 2, 2, 2},
  527. {2017, 12, 19, 3, 3, 3, 3},
  528. {2017, 12, 27, 3, 3, 3, 3},
  529. {2018, 1, 10, 3, 3, 3, 3},
  530. {2018, 1, 16, 3, 3, 3, 3},
  531. {2018, 1, 18, 4, 5, 4, 4},
  532. {2018, 1, 23, 5, 5, 5, 5},
  533. {2018, 3, 12, 6, 6, 6, 6},
  534. {2018, 5, 13, 6, 6, 6, 6},
  535. {2018, 5, 16, 7, 7, 7, 7},
  536. }
  537. for _, testCase := range cases {
  538. func() {
  539. cit, err := test.Repository.Log(&git.LogOptions{From: plumbing.ZeroHash})
  540. if err != nil {
  541. panic(err)
  542. }
  543. defer cit.Close()
  544. var commits []*object.Commit
  545. timeCutoff := time.Date(
  546. testCase[0], time.Month(testCase[1]), testCase[2], 0, 0, 0, 0, time.FixedZone("CET", 7200))
  547. cit.ForEach(func(commit *object.Commit) error {
  548. reliableTime := time.Date(commit.Author.When.Year(), commit.Author.When.Month(),
  549. commit.Author.When.Day(), commit.Author.When.Hour(), commit.Author.When.Minute(),
  550. commit.Author.When.Second(), 0, time.FixedZone("CET", 7200))
  551. if reliableTime.Before(timeCutoff) {
  552. commits = append(commits, commit)
  553. }
  554. return nil
  555. })
  556. plan := prepareRunPlan(commits)
  557. /*for _, p := range plan {
  558. if p.Commit != nil {
  559. fmt.Println(p.Action, p.Commit.Hash.String(), p.Items)
  560. } else {
  561. fmt.Println(p.Action, strings.Repeat(" ", 40), p.Items)
  562. }
  563. }*/
  564. numCommits := 0
  565. numForks := 0
  566. numMerges := 0
  567. numDeletes := 0
  568. numEmerges := 0
  569. processed := map[plumbing.Hash]map[int]int{}
  570. for _, p := range plan {
  571. switch p.Action {
  572. case runActionCommit:
  573. branches := processed[p.Commit.Hash]
  574. if branches == nil {
  575. branches = map[int]int{}
  576. processed[p.Commit.Hash] = branches
  577. }
  578. branches[p.Items[0]]++
  579. for _, parent := range p.Commit.ParentHashes {
  580. assert.Contains(t, processed, parent)
  581. }
  582. numCommits++
  583. case runActionFork:
  584. numForks++
  585. case runActionMerge:
  586. counts := map[int]int{}
  587. for _, i := range p.Items {
  588. counts[i]++
  589. }
  590. for x, v := range counts {
  591. assert.Equal(t, 1, v, x)
  592. }
  593. numMerges++
  594. case runActionDelete:
  595. numDeletes++
  596. case runActionEmerge:
  597. numEmerges++
  598. }
  599. }
  600. for c, branches := range processed {
  601. for b, v := range branches {
  602. assert.Equal(t, 1, v, fmt.Sprint(c.String(), b))
  603. }
  604. }
  605. assert.Equal(t, numCommits, len(commits)+testCase[3], fmt.Sprintf("commits %v", testCase))
  606. assert.Equal(t, numForks, testCase[4], fmt.Sprintf("forks %v", testCase))
  607. assert.Equal(t, numMerges, testCase[5], fmt.Sprintf("merges %v", testCase))
  608. assert.Equal(t, numDeletes, testCase[6], fmt.Sprintf("deletes %v", testCase))
  609. assert.Equal(t, numEmerges, 1, fmt.Sprintf("emerges %v", testCase))
  610. }()
  611. }
  612. }