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  }