github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/builds/tracker_test.go (about) 1 package builds_test 2 3 import ( 4 "context" 5 "io/ioutil" 6 "testing" 7 "time" 8 9 "github.com/pf-qiu/concourse/v6/atc/builds" 10 "github.com/pf-qiu/concourse/v6/atc/component" 11 "github.com/pf-qiu/concourse/v6/atc/db" 12 "github.com/pf-qiu/concourse/v6/atc/db/dbfakes" 13 "github.com/pf-qiu/concourse/v6/atc/engine" 14 "github.com/pf-qiu/concourse/v6/atc/engine/enginefakes" 15 "github.com/pf-qiu/concourse/v6/atc/util" 16 "github.com/stretchr/testify/require" 17 "github.com/stretchr/testify/suite" 18 ) 19 20 func init() { 21 util.PanicSink = ioutil.Discard 22 } 23 24 type TrackerSuite struct { 25 suite.Suite 26 *require.Assertions 27 28 fakeBuildFactory *dbfakes.FakeBuildFactory 29 fakeEngine *enginefakes.FakeEngine 30 31 tracker *builds.Tracker 32 } 33 34 func TestTracker(t *testing.T) { 35 suite.Run(t, &TrackerSuite{ 36 Assertions: require.New(t), 37 }) 38 } 39 40 func (s *TrackerSuite) SetupTest() { 41 s.fakeBuildFactory = new(dbfakes.FakeBuildFactory) 42 s.fakeEngine = new(enginefakes.FakeEngine) 43 44 s.tracker = builds.NewTracker( 45 s.fakeBuildFactory, 46 s.fakeEngine, 47 ) 48 } 49 50 func (s *TrackerSuite) TestTrackRunsStartedBuilds() { 51 startedBuilds := []db.Build{} 52 for i := 0; i < 3; i++ { 53 fakeBuild := new(dbfakes.FakeBuild) 54 fakeBuild.IDReturns(i + 1) 55 startedBuilds = append(startedBuilds, fakeBuild) 56 } 57 58 s.fakeBuildFactory.GetAllStartedBuildsReturns(startedBuilds, nil) 59 60 running := make(chan db.Build, 3) 61 s.fakeEngine.NewBuildStub = func(build db.Build) engine.Runnable { 62 engineBuild := new(enginefakes.FakeRunnable) 63 engineBuild.RunStub = func(context.Context) { 64 running <- build 65 } 66 67 return engineBuild 68 } 69 70 err := s.tracker.Run(context.TODO()) 71 s.NoError(err) 72 73 s.ElementsMatch([]int{ 74 startedBuilds[0].ID(), 75 startedBuilds[1].ID(), 76 startedBuilds[2].ID(), 77 }, []int{ 78 (<-running).ID(), 79 (<-running).ID(), 80 (<-running).ID(), 81 }) 82 } 83 84 func (s *TrackerSuite) TestTrackerDoesntCrashWhenOneBuildPanic() { 85 startedBuilds := []db.Build{} 86 fakeBuild1 := new(dbfakes.FakeBuild) 87 fakeBuild1.IDReturns(1) 88 startedBuilds = append(startedBuilds, fakeBuild1) 89 90 // build 2 and 3 are normal running build 91 for i := 1; i < 3; i++ { 92 fakeBuild := new(dbfakes.FakeBuild) 93 fakeBuild.IDReturns(i + 1) 94 startedBuilds = append(startedBuilds, fakeBuild) 95 } 96 97 s.fakeBuildFactory.GetAllStartedBuildsReturns(startedBuilds, nil) 98 99 running := make(chan db.Build, 3) 100 s.fakeEngine.NewBuildStub = func(build db.Build) engine.Runnable { 101 fakeEngineBuild := new(enginefakes.FakeRunnable) 102 fakeEngineBuild.RunStub = func(context.Context) { 103 if build.ID() == 1 { 104 panic("something went wrong") 105 } else { 106 running <- build 107 } 108 } 109 110 return fakeEngineBuild 111 } 112 113 err := s.tracker.Run(context.TODO()) 114 s.NoError(err) 115 116 s.ElementsMatch([]int{ 117 startedBuilds[1].ID(), 118 startedBuilds[2].ID(), 119 }, []int{ 120 (<-running).ID(), 121 (<-running).ID(), 122 }) 123 124 s.Eventually(func() bool { 125 return fakeBuild1.FinishCallCount() == 1 126 }, time.Second, 10*time.Millisecond) 127 128 s.Eventually(func() bool { 129 return fakeBuild1.FinishArgsForCall(0) == db.BuildStatusErrored 130 }, time.Second, 10*time.Millisecond) 131 } 132 133 func (s *TrackerSuite) TestTrackDoesntTrackAlreadyRunningBuilds() { 134 fakeBuild := new(dbfakes.FakeBuild) 135 fakeBuild.IDReturns(1) 136 s.fakeBuildFactory.GetAllStartedBuildsReturns([]db.Build{fakeBuild}, nil) 137 138 wait := make(chan struct{}) 139 defer close(wait) 140 141 running := make(chan db.Build, 3) 142 s.fakeEngine.NewBuildStub = func(build db.Build) engine.Runnable { 143 engineBuild := new(enginefakes.FakeRunnable) 144 engineBuild.RunStub = func(context.Context) { 145 running <- build 146 <-wait 147 } 148 149 return engineBuild 150 } 151 152 err := s.tracker.Run(context.TODO()) 153 s.NoError(err) 154 155 <-running 156 157 err = s.tracker.Run(context.TODO()) 158 s.NoError(err) 159 160 select { 161 case <-running: 162 s.Fail("another build was started!") 163 case <-time.After(100 * time.Millisecond): 164 } 165 } 166 167 func (s *TrackerSuite) TestTrackerDrainsEngine() { 168 var _ component.Drainable = s.tracker 169 170 ctx := context.TODO() 171 s.tracker.Drain(ctx) 172 s.Equal(1, s.fakeEngine.DrainCallCount()) 173 s.Equal(ctx, s.fakeEngine.DrainArgsForCall(0)) 174 }