diff --git a/runner/constants_test.go b/runner/constants_test.go new file mode 100644 index 0000000..3e38cb0 --- /dev/null +++ b/runner/constants_test.go @@ -0,0 +1,16 @@ +package runner + +const ( + defaultRunnerId = "s0m3-r4nd0m-1d" + anotherRunnerId = "4n0th3r-runn3r-1d" + defaultEnvironmentId = EnvironmentId(0) + anotherEnvironmentId = EnvironmentId(42) + defaultJobId = "s0m3-j0b-1d" + anotherJobId = "4n0th3r-j0b-1d" +) + +type DummyEntity struct{} + +func (DummyEntity) Id() string { + return "" +} diff --git a/runner/job_store_test.go b/runner/job_store_test.go new file mode 100644 index 0000000..4bd478f --- /dev/null +++ b/runner/job_store_test.go @@ -0,0 +1,101 @@ +package runner + +import ( + "github.com/sirupsen/logrus" + "github.com/sirupsen/logrus/hooks/test" + "github.com/stretchr/testify/suite" + "testing" +) + +func TestJobStoreTestSuite(t *testing.T) { + suite.Run(t, new(JobStoreTestSuite)) +} + +type JobStoreTestSuite struct { + suite.Suite + jobStore *nomadJobStore + job *NomadJob +} + +func (suite *JobStoreTestSuite) SetupTest() { + suite.jobStore = NewNomadJobStore() + suite.job = &NomadJob{environmentId: defaultEnvironmentId, jobId: defaultJobId} +} + +func (suite *JobStoreTestSuite) TestAddInvalidEntityTypeThrowsFatal() { + var hook *test.Hook + logger, hook := test.NewNullLogger() + // don't terminate program on fatal log entry + logger.ExitFunc = func(int) {} + log = logger.WithField("pkg", "environment") + + dummyEntity := DummyEntity{} + suite.jobStore.Add(dummyEntity) + suite.Equal(logrus.FatalLevel, hook.LastEntry().Level) + suite.Equal(dummyEntity, hook.LastEntry().Data["entity"]) +} + +func (suite *JobStoreTestSuite) TestAddValidEntityDoesNotThrowFatal() { + var hook *test.Hook + logger, hook := test.NewNullLogger() + log = logger.WithField("pkg", "environment") + + suite.jobStore.Add(suite.job) + // currently, the Add method does not log anything else. adjust if necessary + suite.Nil(hook.LastEntry()) +} + +func (suite *JobStoreTestSuite) TestAddedJobCanBeRetrieved() { + suite.jobStore.Add(suite.job) + retrievedJob, ok := suite.jobStore.Get(suite.job.Id()) + suite.True(ok, "A saved runner should be retrievable") + suite.Equal(suite.job, retrievedJob) +} + +func (suite *JobStoreTestSuite) TestJobWithSameIdOverwritesOldOne() { + otherJobWithSameId := &NomadJob{environmentId: defaultEnvironmentId} + // assure runner is actually different + otherJobWithSameId.jobId = anotherJobId + suite.NotEqual(suite.job, otherJobWithSameId) + + suite.jobStore.Add(suite.job) + suite.jobStore.Add(otherJobWithSameId) + retrievedJob, _ := suite.jobStore.Get(suite.job.Id()) + suite.NotEqual(suite.job, retrievedJob) + suite.Equal(otherJobWithSameId, retrievedJob) +} + +func (suite *JobStoreTestSuite) TestDeletedJobIsNotAccessible() { + suite.jobStore.Add(suite.job) + suite.jobStore.Delete(suite.job.Id()) + retrievedRunner, ok := suite.jobStore.Get(suite.job.Id()) + suite.Nil(retrievedRunner) + suite.False(ok, "A deleted runner should not be accessible") +} + +func (suite *JobStoreTestSuite) TestLenOfEmptyPoolIsZero() { + suite.Equal(0, suite.jobStore.Len()) +} + +func (suite *JobStoreTestSuite) TestLenChangesOnStoreContentChange() { + suite.Run("len increases when job is added", func() { + suite.jobStore.Add(suite.job) + suite.Equal(1, suite.jobStore.Len()) + }) + + suite.Run("len does not increase when job with same id is added", func() { + suite.jobStore.Add(suite.job) + suite.Equal(1, suite.jobStore.Len()) + }) + + suite.Run("len increases again when different job is added", func() { + anotherJob := &NomadJob{environmentId: anotherEnvironmentId} + suite.jobStore.Add(anotherJob) + suite.Equal(2, suite.jobStore.Len()) + }) + + suite.Run("len decreases when job is deleted", func() { + suite.jobStore.Delete(suite.job.Id()) + suite.Equal(1, suite.jobStore.Len()) + }) +} diff --git a/runner/manager_test.go b/runner/manager_test.go index 69160b3..553d20b 100644 --- a/runner/manager_test.go +++ b/runner/manager_test.go @@ -10,12 +10,7 @@ import ( ) const ( - anotherRunnerId = "4n0th3r-runn3r-1d" - defaultEnvironmentId = EnvironmentId(0) - otherEnvironmentId = EnvironmentId(42) defaultDesiredRunnersCount = 5 - jobId = "4n0th3r-j0b-1d" - waitTime = 100 * time.Millisecond ) func TestGetNextRunnerTestSuite(t *testing.T) { @@ -32,7 +27,7 @@ type ManagerTestSuite struct { func (suite *ManagerTestSuite) SetupTest() { suite.apiMock = &nomad.ExecutorApiMock{} suite.nomadRunnerManager = NewNomadRunnerManager(suite.apiMock) - suite.exerciseRunner = CreateTestRunner() + suite.exerciseRunner = NewRunner(defaultRunnerId) suite.mockRunnerQueries([]string{}) suite.registerDefaultEnvironment() } @@ -40,13 +35,13 @@ func (suite *ManagerTestSuite) SetupTest() { func (suite *ManagerTestSuite) mockRunnerQueries(returnedRunnerIds []string) { // reset expected calls to allow new mocked return values suite.apiMock.ExpectedCalls = []*mock.Call{} - suite.apiMock.On("LoadRunners", jobId).Return(returnedRunnerIds, nil) - suite.apiMock.On("JobScale", jobId).Return(len(returnedRunnerIds), nil) - suite.apiMock.On("SetJobScale", jobId, mock.AnythingOfType("int"), "Runner Requested").Return(nil) + suite.apiMock.On("LoadRunners", defaultJobId).Return(returnedRunnerIds, nil) + suite.apiMock.On("JobScale", defaultJobId).Return(len(returnedRunnerIds), nil) + suite.apiMock.On("SetJobScale", defaultJobId, mock.AnythingOfType("int"), "Runner Requested").Return(nil) } func (suite *ManagerTestSuite) registerDefaultEnvironment() { - suite.nomadRunnerManager.RegisterEnvironment(defaultEnvironmentId, jobId, defaultDesiredRunnersCount) + suite.nomadRunnerManager.RegisterEnvironment(defaultEnvironmentId, defaultJobId, defaultDesiredRunnersCount) } func (suite *ManagerTestSuite) AddIdleRunnerForDefaultEnvironment(r Runner) { @@ -55,11 +50,11 @@ func (suite *ManagerTestSuite) AddIdleRunnerForDefaultEnvironment(r Runner) { } func (suite *ManagerTestSuite) waitForRunnerRefresh() { - time.Sleep(waitTime) + time.Sleep(100 * time.Millisecond) } func (suite *ManagerTestSuite) TestRegisterEnvironmentAddsNewJob() { - suite.nomadRunnerManager.RegisterEnvironment(otherEnvironmentId, jobId, defaultDesiredRunnersCount) + suite.nomadRunnerManager.RegisterEnvironment(anotherEnvironmentId, defaultJobId, defaultDesiredRunnersCount) jobEntity, ok := suite.nomadRunnerManager.jobs.Get(defaultEnvironmentId.toString()) suite.True(ok) suite.NotNil(jobEntity) @@ -87,7 +82,7 @@ func (suite *ManagerTestSuite) TestClaimReturnsErrorIfNoRunnerAvailable() { func (suite *ManagerTestSuite) TestClaimReturnsNoRunnerOfDifferentEnvironment() { suite.AddIdleRunnerForDefaultEnvironment(suite.exerciseRunner) - receivedRunner, err := suite.nomadRunnerManager.Claim(otherEnvironmentId) + receivedRunner, err := suite.nomadRunnerManager.Claim(anotherEnvironmentId) suite.Nil(receivedRunner) suite.Error(err) } @@ -108,7 +103,7 @@ func (suite *ManagerTestSuite) TestClaimThrowsAnErrorIfNoRunnersAvailable() { } func (suite *ManagerTestSuite) TestClaimAddsRunnerToUsedRunners() { - suite.mockRunnerQueries([]string{RunnerId}) + suite.mockRunnerQueries([]string{defaultRunnerId}) suite.waitForRunnerRefresh() receivedRunner, _ := suite.nomadRunnerManager.Claim(defaultEnvironmentId) savedRunner, ok := suite.nomadRunnerManager.usedRunners.Get(receivedRunner.Id()) @@ -124,7 +119,7 @@ func (suite *ManagerTestSuite) TestGetReturnsRunnerIfRunnerIsUsed() { } func (suite *ManagerTestSuite) TestGetReturnsErrorIfRunnerNotFound() { - savedRunner, err := suite.nomadRunnerManager.Get(RunnerId) + savedRunner, err := suite.nomadRunnerManager.Get(defaultRunnerId) suite.Nil(savedRunner) suite.Error(err) } @@ -152,32 +147,33 @@ func (suite *ManagerTestSuite) TestReturnReturnsErrorWhenApiCallFailed() { } func (suite *ManagerTestSuite) TestRefreshFetchesRunners() { - suite.mockRunnerQueries([]string{RunnerId}) + suite.mockRunnerQueries([]string{defaultRunnerId}) suite.waitForRunnerRefresh() - suite.apiMock.AssertCalled(suite.T(), "LoadRunners", jobId) + suite.apiMock.AssertCalled(suite.T(), "LoadRunners", defaultJobId) } -func (suite *ManagerTestSuite) TestNewRunnersFoundInRefreshAreAddedToUnusedRunners() { - suite.mockRunnerQueries([]string{RunnerId}) +func (suite *ManagerTestSuite) TestNewRunnersFoundInRefreshAreAddedToIdleRunners() { + suite.mockRunnerQueries([]string{defaultRunnerId}) suite.waitForRunnerRefresh() - availableRunner, _ := suite.nomadRunnerManager.Claim(defaultEnvironmentId) - suite.Equal(availableRunner.Id(), RunnerId) + jobEntity, _ := suite.nomadRunnerManager.jobs.Get(defaultEnvironmentId.toString()) + _, ok := jobEntity.(*NomadJob).idleRunners.Get(defaultRunnerId) + suite.True(ok) } func (suite *ManagerTestSuite) TestRefreshScalesJob() { - suite.mockRunnerQueries([]string{RunnerId}) + suite.mockRunnerQueries([]string{defaultRunnerId}) suite.waitForRunnerRefresh() // use one runner to necessitate rescaling _, _ = suite.nomadRunnerManager.Claim(defaultEnvironmentId) suite.waitForRunnerRefresh() - suite.apiMock.AssertCalled(suite.T(), "SetJobScale", jobId, defaultDesiredRunnersCount+1, "Runner Requested") + suite.apiMock.AssertCalled(suite.T(), "SetJobScale", defaultJobId, defaultDesiredRunnersCount+1, "Runner Requested") } func (suite *ManagerTestSuite) TestRefreshAddsRunnerToPool() { - suite.mockRunnerQueries([]string{RunnerId}) + suite.mockRunnerQueries([]string{defaultRunnerId}) suite.waitForRunnerRefresh() jobEntity, _ := suite.nomadRunnerManager.jobs.Get(defaultEnvironmentId.toString()) - poolRunner, ok := jobEntity.(*NomadJob).idleRunners.Get(RunnerId) + poolRunner, ok := jobEntity.(*NomadJob).idleRunners.Get(defaultRunnerId) suite.True(ok) - suite.Equal(RunnerId, poolRunner.Id()) + suite.Equal(defaultRunnerId, poolRunner.Id()) } diff --git a/runner/pool_test.go b/runner/pool_test.go index 9b2f2f2..2d9f28a 100644 --- a/runner/pool_test.go +++ b/runner/pool_test.go @@ -7,12 +7,6 @@ import ( "testing" ) -type DummyEntity struct{} - -func (DummyEntity) Id() string { - return "" -} - func TestRunnerPoolTestSuite(t *testing.T) { suite.Run(t, new(RunnerPoolTestSuite)) } @@ -25,7 +19,7 @@ type RunnerPoolTestSuite struct { func (suite *RunnerPoolTestSuite) SetupTest() { suite.runnerPool = NewLocalRunnerPool() - suite.runner = CreateTestRunner() + suite.runner = NewRunner(defaultRunnerId) } func (suite *RunnerPoolTestSuite) TestAddInvalidEntityTypeThrowsFatal() { @@ -41,7 +35,7 @@ func (suite *RunnerPoolTestSuite) TestAddInvalidEntityTypeThrowsFatal() { suite.Equal(dummyEntity, hook.LastEntry().Data["entity"]) } -func (suite *RunnerPoolTestSuite) TestAddValidEntityThrowsFatal() { +func (suite *RunnerPoolTestSuite) TestAddValidEntityDoesNotThrowFatal() { var hook *test.Hook logger, hook := test.NewNullLogger() log = logger.WithField("pkg", "environment") @@ -77,3 +71,55 @@ func (suite *RunnerPoolTestSuite) TestDeletedRunnersAreNotAccessible() { suite.Nil(retrievedRunner) suite.False(ok, "A deleted runner should not be accessible") } + +func (suite *RunnerPoolTestSuite) TestSampleReturnsRunnerWhenOneIsAvailable() { + suite.runnerPool.Add(suite.runner) + sampledRunner, ok := suite.runnerPool.Sample() + suite.NotNil(sampledRunner) + suite.True(ok) +} + +func (suite *RunnerPoolTestSuite) TestSampleReturnsFalseWhenNoneIsAvailable() { + sampledRunner, ok := suite.runnerPool.Sample() + suite.Nil(sampledRunner) + suite.False(ok) +} + +func (suite *RunnerPoolTestSuite) TestSampleRemovesRunnerFromPool() { + suite.runnerPool.Add(suite.runner) + sampledRunner, _ := suite.runnerPool.Sample() + _, ok := suite.runnerPool.Get(sampledRunner.Id()) + suite.False(ok) +} + +func (suite *RunnerPoolTestSuite) TestLenOfEmptyPoolIsZero() { + suite.Equal(0, suite.runnerPool.Len()) +} + +func (suite *RunnerPoolTestSuite) TestLenChangesOnStoreContentChange() { + suite.Run("len increases when runner is added", func() { + suite.runnerPool.Add(suite.runner) + suite.Equal(1, suite.runnerPool.Len()) + }) + + suite.Run("len does not increase when runner with same id is added", func() { + suite.runnerPool.Add(suite.runner) + suite.Equal(1, suite.runnerPool.Len()) + }) + + suite.Run("len increases again when different runner is added", func() { + anotherRunner := NewRunner(anotherRunnerId) + suite.runnerPool.Add(anotherRunner) + suite.Equal(2, suite.runnerPool.Len()) + }) + + suite.Run("len decreases when runner is deleted", func() { + suite.runnerPool.Delete(suite.runner.Id()) + suite.Equal(1, suite.runnerPool.Len()) + }) + + suite.Run("len decreases when runner is sampled", func() { + _, _ = suite.runnerPool.Sample() + suite.Equal(0, suite.runnerPool.Len()) + }) +} diff --git a/runner/test_constants.go b/runner/test_constants.go deleted file mode 100644 index 48798ee..0000000 --- a/runner/test_constants.go +++ /dev/null @@ -1,7 +0,0 @@ -package runner - -const RunnerId = "s0m3-r4nd0m-1d" - -func CreateTestRunner() Runner { - return NewRunner(RunnerId) -}