266 lines
9.5 KiB
Go
266 lines
9.5 KiB
Go
package environment
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
nomadApi "github.com/hashicorp/nomad/api"
|
|
"github.com/openHPI/poseidon/internal/config"
|
|
"github.com/openHPI/poseidon/internal/nomad"
|
|
"github.com/openHPI/poseidon/internal/runner"
|
|
"github.com/openHPI/poseidon/pkg/storage"
|
|
"github.com/openHPI/poseidon/tests"
|
|
"github.com/openHPI/poseidon/tests/helpers"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/mock"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func (s *MainTestSuite) TestConfigureNetworkCreatesNewNetworkWhenNoNetworkExists() {
|
|
_, job := helpers.CreateTemplateJob()
|
|
defaultTaskGroup := nomad.FindAndValidateDefaultTaskGroup(job)
|
|
environment := &NomadEnvironment{nil, "", job, nil, context.Background(), nil}
|
|
|
|
if s.Equal(0, len(defaultTaskGroup.Networks)) {
|
|
environment.SetNetworkAccess(true, []uint16{})
|
|
|
|
s.Equal(1, len(defaultTaskGroup.Networks))
|
|
}
|
|
}
|
|
|
|
func (s *MainTestSuite) TestConfigureNetworkDoesNotCreateNewNetworkWhenNetworkExists() {
|
|
_, job := helpers.CreateTemplateJob()
|
|
defaultTaskGroup := nomad.FindAndValidateDefaultTaskGroup(job)
|
|
environment := &NomadEnvironment{nil, "", job, nil, context.Background(), nil}
|
|
|
|
networkResource := config.Config.Nomad.Network
|
|
defaultTaskGroup.Networks = []*nomadApi.NetworkResource{&networkResource}
|
|
|
|
if s.Equal(1, len(defaultTaskGroup.Networks)) {
|
|
environment.SetNetworkAccess(true, []uint16{})
|
|
|
|
s.Equal(1, len(defaultTaskGroup.Networks))
|
|
s.Equal(&networkResource, defaultTaskGroup.Networks[0])
|
|
}
|
|
}
|
|
|
|
func (s *MainTestSuite) TestConfigureNetworkSetsCorrectValues() {
|
|
_, job := helpers.CreateTemplateJob()
|
|
defaultTaskGroup := nomad.FindAndValidateDefaultTaskGroup(job)
|
|
defaultTask := nomad.FindAndValidateDefaultTask(defaultTaskGroup)
|
|
|
|
mode, ok := defaultTask.Config["network_mode"]
|
|
s.True(ok)
|
|
s.Equal("none", mode)
|
|
s.Equal(0, len(defaultTaskGroup.Networks))
|
|
|
|
exposedPortsTests := [][]uint16{{}, {1337}, {42, 1337}}
|
|
s.Run("with no network access", func() {
|
|
for _, ports := range exposedPortsTests {
|
|
_, testJob := helpers.CreateTemplateJob()
|
|
testTaskGroup := nomad.FindAndValidateDefaultTaskGroup(testJob)
|
|
testTask := nomad.FindAndValidateDefaultTask(testTaskGroup)
|
|
testEnvironment := &NomadEnvironment{nil, "", job, nil, context.Background(), nil}
|
|
|
|
testEnvironment.SetNetworkAccess(false, ports)
|
|
mode, ok := testTask.Config["network_mode"]
|
|
s.True(ok)
|
|
s.Equal("none", mode)
|
|
s.Equal(0, len(testTaskGroup.Networks))
|
|
}
|
|
})
|
|
|
|
s.Run("with network access", func() {
|
|
for _, ports := range exposedPortsTests {
|
|
_, testJob := helpers.CreateTemplateJob()
|
|
testTaskGroup := nomad.FindAndValidateDefaultTaskGroup(testJob)
|
|
testTask := nomad.FindAndValidateDefaultTask(testTaskGroup)
|
|
testEnvironment := &NomadEnvironment{nil, "", testJob, nil, context.Background(), nil}
|
|
|
|
testEnvironment.SetNetworkAccess(true, ports)
|
|
s.Require().Equal(1, len(testTaskGroup.Networks))
|
|
|
|
networkResource := testTaskGroup.Networks[0]
|
|
s.Equal(config.Config.Nomad.Network.Mode, networkResource.Mode)
|
|
s.Require().Equal(len(ports), len(networkResource.DynamicPorts))
|
|
|
|
assertExpectedPorts(s.T(), ports, networkResource)
|
|
|
|
mode, ok := testTask.Config["network_mode"]
|
|
s.True(ok)
|
|
s.Equal(mode, "")
|
|
}
|
|
})
|
|
}
|
|
|
|
func assertExpectedPorts(t *testing.T, expectedPorts []uint16, networkResource *nomadApi.NetworkResource) {
|
|
t.Helper()
|
|
for _, expectedPort := range expectedPorts {
|
|
found := false
|
|
for _, actualPort := range networkResource.DynamicPorts {
|
|
if actualPort.To == int(expectedPort) {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
assert.True(t, found, fmt.Sprintf("port list should contain %v", expectedPort))
|
|
}
|
|
}
|
|
|
|
func (s *MainTestSuite) TestRegisterFailsWhenNomadJobRegistrationFails() {
|
|
apiClientMock := &nomad.ExecutorAPIMock{}
|
|
expectedErr := tests.ErrDefault
|
|
|
|
apiClientMock.On("RegisterNomadJob", mock.AnythingOfType("*api.Job")).Return("", expectedErr)
|
|
apiClientMock.On("LoadRunnerIDs", mock.AnythingOfType("string")).Return([]string{}, nil)
|
|
apiClientMock.On("DeleteJob", mock.AnythingOfType("string")).Return(nil)
|
|
|
|
environment := &NomadEnvironment{apiClientMock, "", &nomadApi.Job{},
|
|
storage.NewLocalStorage[runner.Runner](), nil, nil}
|
|
environment.SetID(tests.DefaultEnvironmentIDAsInteger)
|
|
err := environment.Register()
|
|
|
|
s.ErrorIs(err, expectedErr)
|
|
apiClientMock.AssertNotCalled(s.T(), "MonitorEvaluation")
|
|
}
|
|
|
|
func (s *MainTestSuite) TestRegisterTemplateJobSucceedsWhenMonitoringEvaluationSucceeds() {
|
|
apiClientMock := &nomad.ExecutorAPIMock{}
|
|
evaluationID := "id"
|
|
|
|
apiClientMock.On("RegisterNomadJob", mock.AnythingOfType("*api.Job")).Return(evaluationID, nil)
|
|
apiClientMock.On("MonitorEvaluation", mock.AnythingOfType("string"), mock.Anything).Return(nil)
|
|
apiClientMock.On("LoadRunnerIDs", mock.AnythingOfType("string")).Return([]string{}, nil)
|
|
apiClientMock.On("DeleteJob", mock.AnythingOfType("string")).Return(nil)
|
|
|
|
environment := &NomadEnvironment{apiClientMock, "", &nomadApi.Job{},
|
|
storage.NewLocalStorage[runner.Runner](), context.Background(), nil}
|
|
environment.SetID(tests.DefaultEnvironmentIDAsInteger)
|
|
err := environment.Register()
|
|
|
|
s.NoError(err)
|
|
}
|
|
|
|
func (s *MainTestSuite) TestRegisterTemplateJobReturnsErrorWhenMonitoringEvaluationFails() {
|
|
apiClientMock := &nomad.ExecutorAPIMock{}
|
|
evaluationID := "id"
|
|
|
|
apiClientMock.On("RegisterNomadJob", mock.AnythingOfType("*api.Job")).Return(evaluationID, nil)
|
|
apiClientMock.On("MonitorEvaluation", mock.AnythingOfType("string"), mock.Anything).Return(tests.ErrDefault)
|
|
apiClientMock.On("LoadRunnerIDs", mock.AnythingOfType("string")).Return([]string{}, nil)
|
|
apiClientMock.On("DeleteJob", mock.AnythingOfType("string")).Return(nil)
|
|
|
|
environment := &NomadEnvironment{apiClientMock, "", &nomadApi.Job{},
|
|
storage.NewLocalStorage[runner.Runner](), context.Background(), nil}
|
|
environment.SetID(tests.DefaultEnvironmentIDAsInteger)
|
|
err := environment.Register()
|
|
|
|
s.ErrorIs(err, tests.ErrDefault)
|
|
}
|
|
|
|
func (s *MainTestSuite) TestParseJob() {
|
|
apiMock := &nomad.ExecutorAPIMock{}
|
|
apiMock.On("LoadRunnerIDs", mock.AnythingOfType("string")).Return([]string{}, nil)
|
|
apiMock.On("DeleteJob", mock.AnythingOfType("string")).Return(nil)
|
|
s.Run("parses the given default job", func() {
|
|
environment, err := NewNomadEnvironment(tests.DefaultEnvironmentIDAsInteger, apiMock, templateEnvironmentJobHCL)
|
|
s.NoError(err)
|
|
s.NotNil(environment.job)
|
|
s.NoError(environment.Delete(tests.ErrCleanupDestroyReason))
|
|
})
|
|
|
|
s.Run("returns error when given wrong job", func() {
|
|
environment, err := NewNomadEnvironment(tests.DefaultEnvironmentIDAsInteger, nil, "")
|
|
s.Error(err)
|
|
s.Nil(environment)
|
|
})
|
|
}
|
|
|
|
func (s *MainTestSuite) TestTwoSampleAddExactlyTwoRunners() {
|
|
apiMock := &nomad.ExecutorAPIMock{}
|
|
apiMock.On("RegisterRunnerJob", mock.AnythingOfType("*api.Job")).Return(nil)
|
|
|
|
_, job := helpers.CreateTemplateJob()
|
|
environment := &NomadEnvironment{apiMock, templateEnvironmentJobHCL, job,
|
|
storage.NewLocalStorage[runner.Runner](), context.Background(), nil}
|
|
environment.SetPrewarmingPoolSize(2)
|
|
runner1 := &runner.RunnerMock{}
|
|
runner1.On("ID").Return(tests.DefaultRunnerID)
|
|
runner2 := &runner.RunnerMock{}
|
|
runner2.On("ID").Return(tests.AnotherRunnerID)
|
|
|
|
environment.AddRunner(runner1)
|
|
environment.AddRunner(runner2)
|
|
|
|
_, ok := environment.Sample()
|
|
s.Require().True(ok)
|
|
_, ok = environment.Sample()
|
|
s.Require().True(ok)
|
|
|
|
<-time.After(tests.ShortTimeout) // New Runners are requested asynchronously
|
|
apiMock.AssertNumberOfCalls(s.T(), "RegisterRunnerJob", 2)
|
|
}
|
|
|
|
func (s *MainTestSuite) TestSampleDoesNotSetForcePullFlag() {
|
|
apiMock := &nomad.ExecutorAPIMock{}
|
|
call := apiMock.On("RegisterRunnerJob", mock.AnythingOfType("*api.Job"))
|
|
call.Run(func(args mock.Arguments) {
|
|
job, ok := args.Get(0).(*nomadApi.Job)
|
|
s.True(ok)
|
|
|
|
taskGroup := nomad.FindAndValidateDefaultTaskGroup(job)
|
|
task := nomad.FindAndValidateDefaultTask(taskGroup)
|
|
s.False(task.Config["force_pull"].(bool))
|
|
|
|
call.ReturnArguments = mock.Arguments{nil}
|
|
})
|
|
|
|
_, job := helpers.CreateTemplateJob()
|
|
environment := &NomadEnvironment{apiMock, templateEnvironmentJobHCL, job,
|
|
storage.NewLocalStorage[runner.Runner](), s.TestCtx, nil}
|
|
runner1 := &runner.RunnerMock{}
|
|
runner1.On("ID").Return(tests.DefaultRunnerID)
|
|
environment.AddRunner(runner1)
|
|
|
|
_, ok := environment.Sample()
|
|
s.Require().True(ok)
|
|
<-time.After(tests.ShortTimeout) // New Runners are requested asynchronously
|
|
}
|
|
|
|
func (s *MainTestSuite) TestNomadEnvironment_DeleteLocally() {
|
|
apiMock := &nomad.ExecutorAPIMock{}
|
|
environment, err := NewNomadEnvironment(tests.DefaultEnvironmentIDAsInteger, apiMock, templateEnvironmentJobHCL)
|
|
s.Require().NoError(err)
|
|
|
|
err = environment.Delete(runner.ErrLocalDestruction)
|
|
s.NoError(err)
|
|
apiMock.AssertExpectations(s.T())
|
|
}
|
|
|
|
func (s *MainTestSuite) TestNomadEnvironment_AddRunner() {
|
|
s.Run("Destroys runner before replacing it", func() {
|
|
apiMock := &nomad.ExecutorAPIMock{}
|
|
environment, err := NewNomadEnvironment(tests.DefaultEnvironmentIDAsInteger, apiMock, templateEnvironmentJobHCL)
|
|
s.Require().NoError(err)
|
|
r := &runner.RunnerMock{}
|
|
r.On("ID").Return(tests.DefaultRunnerID)
|
|
r.On("Destroy", mock.Anything).Run(func(args mock.Arguments) {
|
|
err, ok := args[0].(error)
|
|
s.Require().True(ok)
|
|
s.ErrorIs(err, runner.ErrLocalDestruction)
|
|
}).Return(nil).Once()
|
|
r2 := &runner.RunnerMock{}
|
|
r2.On("ID").Return(tests.DefaultRunnerID)
|
|
|
|
environment.AddRunner(r)
|
|
environment.AddRunner(r2)
|
|
r.AssertExpectations(s.T())
|
|
|
|
// Teardown test case
|
|
r2.On("Destroy", mock.Anything).Return(nil)
|
|
apiMock.On("LoadRunnerIDs", mock.Anything).Return([]string{}, nil)
|
|
apiMock.On("DeleteJob", mock.Anything).Return(nil)
|
|
s.NoError(environment.Delete(tests.ErrCleanupDestroyReason))
|
|
})
|
|
}
|