
* #9 Implement routes to list, get and delete execution environments. A refactoring was required to introduce the ExecutionEnvironment interface. * Fix MR comments, linting issues and bug that lead to e2e test failure * Add e2e tests * Add unit tests
193 lines
6.4 KiB
Go
193 lines
6.4 KiB
Go
package environment
|
|
|
|
import (
|
|
"fmt"
|
|
nomadApi "github.com/hashicorp/nomad/api"
|
|
"github.com/openHPI/poseidon/internal/nomad"
|
|
"github.com/openHPI/poseidon/internal/runner"
|
|
"github.com/openHPI/poseidon/tests"
|
|
"github.com/openHPI/poseidon/tests/helpers"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/mock"
|
|
"github.com/stretchr/testify/require"
|
|
"testing"
|
|
)
|
|
|
|
func TestConfigureNetworkCreatesNewNetworkWhenNoNetworkExists(t *testing.T) {
|
|
_, job := helpers.CreateTemplateJob()
|
|
defaultTaskGroup := nomad.FindOrCreateDefaultTaskGroup(job)
|
|
environment := &NomadEnvironment{"", job, nil}
|
|
|
|
if assert.Equal(t, 0, len(defaultTaskGroup.Networks)) {
|
|
environment.SetNetworkAccess(true, []uint16{})
|
|
|
|
assert.Equal(t, 1, len(defaultTaskGroup.Networks))
|
|
}
|
|
}
|
|
|
|
func TestConfigureNetworkDoesNotCreateNewNetworkWhenNetworkExists(t *testing.T) {
|
|
_, job := helpers.CreateTemplateJob()
|
|
defaultTaskGroup := nomad.FindOrCreateDefaultTaskGroup(job)
|
|
environment := &NomadEnvironment{"", job, nil}
|
|
|
|
networkResource := &nomadApi.NetworkResource{Mode: "bridge"}
|
|
defaultTaskGroup.Networks = []*nomadApi.NetworkResource{networkResource}
|
|
|
|
if assert.Equal(t, 1, len(defaultTaskGroup.Networks)) {
|
|
environment.SetNetworkAccess(true, []uint16{})
|
|
|
|
assert.Equal(t, 1, len(defaultTaskGroup.Networks))
|
|
assert.Equal(t, networkResource, defaultTaskGroup.Networks[0])
|
|
}
|
|
}
|
|
|
|
func TestConfigureNetworkSetsCorrectValues(t *testing.T) {
|
|
_, job := helpers.CreateTemplateJob()
|
|
defaultTaskGroup := nomad.FindOrCreateDefaultTaskGroup(job)
|
|
defaultTask := nomad.FindOrCreateDefaultTask(defaultTaskGroup)
|
|
|
|
mode, ok := defaultTask.Config["network_mode"]
|
|
assert.True(t, ok)
|
|
assert.Equal(t, "none", mode)
|
|
assert.Equal(t, 0, len(defaultTaskGroup.Networks))
|
|
|
|
exposedPortsTests := [][]uint16{{}, {1337}, {42, 1337}}
|
|
t.Run("with no network access", func(t *testing.T) {
|
|
for _, ports := range exposedPortsTests {
|
|
_, testJob := helpers.CreateTemplateJob()
|
|
testTaskGroup := nomad.FindOrCreateDefaultTaskGroup(testJob)
|
|
testTask := nomad.FindOrCreateDefaultTask(testTaskGroup)
|
|
testEnvironment := &NomadEnvironment{"", job, nil}
|
|
|
|
testEnvironment.SetNetworkAccess(false, ports)
|
|
mode, ok := testTask.Config["network_mode"]
|
|
assert.True(t, ok)
|
|
assert.Equal(t, "none", mode)
|
|
assert.Equal(t, 0, len(testTaskGroup.Networks))
|
|
}
|
|
})
|
|
|
|
t.Run("with network access", func(t *testing.T) {
|
|
for _, ports := range exposedPortsTests {
|
|
_, testJob := helpers.CreateTemplateJob()
|
|
testTaskGroup := nomad.FindOrCreateDefaultTaskGroup(testJob)
|
|
testTask := nomad.FindOrCreateDefaultTask(testTaskGroup)
|
|
testEnvironment := &NomadEnvironment{"", testJob, nil}
|
|
|
|
testEnvironment.SetNetworkAccess(true, ports)
|
|
require.Equal(t, 1, len(testTaskGroup.Networks))
|
|
|
|
networkResource := testTaskGroup.Networks[0]
|
|
assert.Equal(t, "bridge", networkResource.Mode)
|
|
require.Equal(t, len(ports), len(networkResource.DynamicPorts))
|
|
|
|
assertExpectedPorts(t, ports, networkResource)
|
|
|
|
mode, ok := testTask.Config["network_mode"]
|
|
assert.True(t, ok)
|
|
assert.Equal(t, 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 TestRegisterFailsWhenNomadJobRegistrationFails(t *testing.T) {
|
|
apiClientMock := &nomad.ExecutorAPIMock{}
|
|
expectedErr := tests.ErrDefault
|
|
|
|
apiClientMock.On("RegisterNomadJob", mock.AnythingOfType("*api.Job")).Return("", expectedErr)
|
|
|
|
environment := &NomadEnvironment{"", &nomadApi.Job{}, nil}
|
|
environment.SetID(tests.DefaultEnvironmentIDAsInteger)
|
|
err := environment.Register(apiClientMock)
|
|
|
|
assert.ErrorIs(t, err, expectedErr)
|
|
apiClientMock.AssertNotCalled(t, "EvaluationStream")
|
|
}
|
|
|
|
func TestRegisterTemplateJobSucceedsWhenMonitoringEvaluationSucceeds(t *testing.T) {
|
|
apiClientMock := &nomad.ExecutorAPIMock{}
|
|
evaluationID := "id"
|
|
|
|
stream := make(chan *nomadApi.Events)
|
|
readonlyStream := func() <-chan *nomadApi.Events {
|
|
return stream
|
|
}()
|
|
// Immediately close stream to avoid any reading from it resulting in endless wait
|
|
close(stream)
|
|
|
|
apiClientMock.On("RegisterNomadJob", mock.AnythingOfType("*api.Job")).Return(evaluationID, nil)
|
|
apiClientMock.On("MonitorEvaluation", mock.AnythingOfType("string"), mock.Anything).Return(nil)
|
|
apiClientMock.On("EvaluationStream", evaluationID, mock.AnythingOfType("*context.emptyCtx")).
|
|
Return(readonlyStream, nil)
|
|
|
|
environment := &NomadEnvironment{"", &nomadApi.Job{}, nil}
|
|
environment.SetID(tests.DefaultEnvironmentIDAsInteger)
|
|
err := environment.Register(apiClientMock)
|
|
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func TestRegisterTemplateJobReturnsErrorWhenMonitoringEvaluationFails(t *testing.T) {
|
|
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)
|
|
|
|
environment := &NomadEnvironment{"", &nomadApi.Job{}, nil}
|
|
environment.SetID(tests.DefaultEnvironmentIDAsInteger)
|
|
err := environment.Register(apiClientMock)
|
|
|
|
assert.ErrorIs(t, err, tests.ErrDefault)
|
|
}
|
|
|
|
func TestParseJob(t *testing.T) {
|
|
t.Run("parses the given default job", func(t *testing.T) {
|
|
environment, err := NewNomadEnvironment(templateEnvironmentJobHCL)
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, environment.job)
|
|
})
|
|
|
|
t.Run("returns error when given wrong job", func(t *testing.T) {
|
|
environment, err := NewNomadEnvironment("")
|
|
assert.Error(t, err)
|
|
assert.Nil(t, environment)
|
|
})
|
|
}
|
|
|
|
func TestTwoSampleAddExactlyTwoRunners(t *testing.T) {
|
|
apiMock := &nomad.ExecutorAPIMock{}
|
|
apiMock.On("RegisterRunnerJob", mock.AnythingOfType("*api.Job")).Return(nil)
|
|
|
|
_, job := helpers.CreateTemplateJob()
|
|
environment := &NomadEnvironment{templateEnvironmentJobHCL, job, runner.NewLocalRunnerStorage()}
|
|
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(apiMock)
|
|
require.True(t, ok)
|
|
_, ok = environment.Sample(apiMock)
|
|
require.True(t, ok)
|
|
|
|
apiMock.AssertNumberOfCalls(t, "RegisterRunnerJob", 2)
|
|
}
|