Add unit tests
This commit is contained in:
26
cmd/poseidon/main_test.go
Normal file
26
cmd/poseidon/main_test.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/openHPI/poseidon/internal/environment"
|
||||||
|
"github.com/openHPI/poseidon/internal/runner"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAWSDisabledUsesNomadManager(t *testing.T) {
|
||||||
|
runnerManager, environmentManager := createManagerHandler(createNomadManager, true,
|
||||||
|
runner.NewAbstractManager(), &environment.AbstractManager{})
|
||||||
|
awsRunnerManager, awsEnvironmentManager := createManagerHandler(createAWSManager, false,
|
||||||
|
runnerManager, environmentManager)
|
||||||
|
assert.Equal(t, runnerManager, awsRunnerManager)
|
||||||
|
assert.Equal(t, environmentManager, awsEnvironmentManager)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAWSEnabledWrappesNomadManager(t *testing.T) {
|
||||||
|
runnerManager, environmentManager := createManagerHandler(createNomadManager, true,
|
||||||
|
runner.NewAbstractManager(), &environment.AbstractManager{})
|
||||||
|
awsRunnerManager, awsEnvironmentManager := createManagerHandler(createAWSManager,
|
||||||
|
true, runnerManager, environmentManager)
|
||||||
|
assert.NotEqual(t, runnerManager, awsRunnerManager)
|
||||||
|
assert.NotEqual(t, environmentManager, awsEnvironmentManager)
|
||||||
|
}
|
112
internal/environment/aws_manager_test.go
Normal file
112
internal/environment/aws_manager_test.go
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
package environment
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/openHPI/poseidon/internal/runner"
|
||||||
|
"github.com/openHPI/poseidon/pkg/dto"
|
||||||
|
"github.com/openHPI/poseidon/tests"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/mock"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAWSEnvironmentManager_CreateOrUpdate(t *testing.T) {
|
||||||
|
runnerManager := runner.NewAWSRunnerManager()
|
||||||
|
m := NewAWSEnvironmentManager(runnerManager)
|
||||||
|
uniqueImage := "random image string"
|
||||||
|
|
||||||
|
t.Run("can create default Java environment", func(t *testing.T) {
|
||||||
|
_, err := m.CreateOrUpdate(runner.AwsJavaEnvironmentID, dto.ExecutionEnvironmentRequest{Image: uniqueImage})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("can retrieve added environment", func(t *testing.T) {
|
||||||
|
environment, err := m.Get(runner.AwsJavaEnvironmentID, false)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, environment.Image(), uniqueImage)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("non handleable requests are forwarded to the next manager", func(t *testing.T) {
|
||||||
|
nextHandler := &ManagerHandlerMock{}
|
||||||
|
nextHandler.On("CreateOrUpdate", mock.AnythingOfType("dto.EnvironmentID"),
|
||||||
|
mock.AnythingOfType("dto.ExecutionEnvironmentRequest")).Return(true, nil)
|
||||||
|
m.SetNextHandler(nextHandler)
|
||||||
|
|
||||||
|
request := dto.ExecutionEnvironmentRequest{}
|
||||||
|
_, err := m.CreateOrUpdate(tests.DefaultEnvironmentIDAsInteger, request)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
nextHandler.AssertCalled(t, "CreateOrUpdate",
|
||||||
|
dto.EnvironmentID(tests.DefaultEnvironmentIDAsInteger), request)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAWSEnvironmentManager_Get(t *testing.T) {
|
||||||
|
runnerManager := runner.NewAWSRunnerManager()
|
||||||
|
m := NewAWSEnvironmentManager(runnerManager)
|
||||||
|
|
||||||
|
t.Run("Calls next handler when not found", func(t *testing.T) {
|
||||||
|
nextHandler := &ManagerHandlerMock{}
|
||||||
|
nextHandler.On("Get", mock.AnythingOfType("dto.EnvironmentID"), mock.AnythingOfType("bool")).
|
||||||
|
Return(nil, nil)
|
||||||
|
m.SetNextHandler(nextHandler)
|
||||||
|
|
||||||
|
_, err := m.Get(tests.DefaultEnvironmentIDAsInteger, false)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
nextHandler.AssertCalled(t, "Get", dto.EnvironmentID(tests.DefaultEnvironmentIDAsInteger), false)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Returns error when not found", func(t *testing.T) {
|
||||||
|
nextHandler := &AbstractManager{nil}
|
||||||
|
m.SetNextHandler(nextHandler)
|
||||||
|
|
||||||
|
_, err := m.Get(tests.DefaultEnvironmentIDAsInteger, false)
|
||||||
|
assert.ErrorIs(t, err, runner.ErrRunnerNotFound)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Returns environment when it was added before", func(t *testing.T) {
|
||||||
|
expectedEnvironment := NewAWSEnvironment()
|
||||||
|
expectedEnvironment.SetID(tests.DefaultEnvironmentIDAsInteger)
|
||||||
|
runnerManager.StoreEnvironment(expectedEnvironment)
|
||||||
|
|
||||||
|
environment, err := m.Get(tests.DefaultEnvironmentIDAsInteger, false)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, expectedEnvironment, environment)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAWSEnvironmentManager_List(t *testing.T) {
|
||||||
|
runnerManager := runner.NewAWSRunnerManager()
|
||||||
|
m := NewAWSEnvironmentManager(runnerManager)
|
||||||
|
|
||||||
|
t.Run("contains the \"Load\"-ed environments", func(t *testing.T) {
|
||||||
|
environments, err := m.List(false)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
require.Len(t, environments, 1)
|
||||||
|
assert.Equal(t, environments[0].ID(), dto.EnvironmentID(runner.AwsJavaEnvironmentID))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("returs also environments of the rest of the manager chain", func(t *testing.T) {
|
||||||
|
nextHandler := &ManagerHandlerMock{}
|
||||||
|
existingEnvironment := NewAWSEnvironment()
|
||||||
|
nextHandler.On("List", mock.AnythingOfType("bool")).
|
||||||
|
Return([]runner.ExecutionEnvironment{existingEnvironment}, nil)
|
||||||
|
m.SetNextHandler(nextHandler)
|
||||||
|
|
||||||
|
environments, err := m.List(false)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
require.Len(t, environments, 2)
|
||||||
|
assert.Contains(t, environments, existingEnvironment)
|
||||||
|
})
|
||||||
|
m.SetNextHandler(nil)
|
||||||
|
|
||||||
|
t.Run("Returns added environment", func(t *testing.T) {
|
||||||
|
localEnvironment := NewAWSEnvironment()
|
||||||
|
localEnvironment.SetID(tests.DefaultEnvironmentIDAsInteger)
|
||||||
|
runnerManager.StoreEnvironment(localEnvironment)
|
||||||
|
|
||||||
|
environments, err := m.List(false)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, environments, 2)
|
||||||
|
assert.Contains(t, environments, localEnvironment)
|
||||||
|
})
|
||||||
|
}
|
87
internal/runner/aws_manager_test.go
Normal file
87
internal/runner/aws_manager_test.go
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
package runner
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/openHPI/poseidon/pkg/dto"
|
||||||
|
"github.com/openHPI/poseidon/tests"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/mock"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAWSRunnerManager_EnvironmentAccessor(t *testing.T) {
|
||||||
|
m := NewAWSRunnerManager()
|
||||||
|
|
||||||
|
environments := m.ListEnvironments()
|
||||||
|
assert.Empty(t, environments)
|
||||||
|
|
||||||
|
environment := &ExecutionEnvironmentMock{}
|
||||||
|
environment.On("ID").Return(dto.EnvironmentID(tests.DefaultEnvironmentIDAsInteger))
|
||||||
|
m.StoreEnvironment(environment)
|
||||||
|
|
||||||
|
environments = m.ListEnvironments()
|
||||||
|
assert.Len(t, environments, 1)
|
||||||
|
assert.Equal(t, environments[0].ID(), dto.EnvironmentID(tests.DefaultEnvironmentIDAsInteger))
|
||||||
|
|
||||||
|
e, ok := m.GetEnvironment(tests.DefaultEnvironmentIDAsInteger)
|
||||||
|
assert.True(t, ok)
|
||||||
|
assert.Equal(t, environment, e)
|
||||||
|
|
||||||
|
_, ok = m.GetEnvironment(tests.AnotherEnvironmentIDAsInteger)
|
||||||
|
assert.False(t, ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAWSRunnerManager_Claim(t *testing.T) {
|
||||||
|
m := NewAWSRunnerManager()
|
||||||
|
environment := &ExecutionEnvironmentMock{}
|
||||||
|
environment.On("ID").Return(dto.EnvironmentID(tests.DefaultEnvironmentIDAsInteger))
|
||||||
|
r, err := NewAWSFunctionWorkload(environment, nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
environment.On("Sample").Return(r, true)
|
||||||
|
m.StoreEnvironment(environment)
|
||||||
|
|
||||||
|
t.Run("returns runner for AWS environment", func(t *testing.T) {
|
||||||
|
r, err := m.Claim(tests.DefaultEnvironmentIDAsInteger, 60)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, r)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("forwards request for non AWS environments", func(t *testing.T) {
|
||||||
|
nextHandler := &ManagerMock{}
|
||||||
|
nextHandler.On("Claim", mock.AnythingOfType("dto.EnvironmentID"), mock.AnythingOfType("int")).
|
||||||
|
Return(nil, nil)
|
||||||
|
m.SetNextHandler(nextHandler)
|
||||||
|
|
||||||
|
_, err := m.Claim(tests.AnotherEnvironmentIDAsInteger, 60)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
nextHandler.AssertCalled(t, "Claim", dto.EnvironmentID(tests.AnotherEnvironmentIDAsInteger), 60)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAWSRunnerManager_Return(t *testing.T) {
|
||||||
|
m := NewAWSRunnerManager()
|
||||||
|
environment := &ExecutionEnvironmentMock{}
|
||||||
|
environment.On("ID").Return(dto.EnvironmentID(tests.DefaultEnvironmentIDAsInteger))
|
||||||
|
m.StoreEnvironment(environment)
|
||||||
|
r, err := NewAWSFunctionWorkload(environment, nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
t.Run("removes usedRunner", func(t *testing.T) {
|
||||||
|
m.usedRunners.Add(r)
|
||||||
|
assert.Contains(t, m.usedRunners.List(), r)
|
||||||
|
|
||||||
|
err := m.Return(r)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotContains(t, m.usedRunners.List(), r)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("calls nextHandler for non AWS runner", func(t *testing.T) {
|
||||||
|
nextHandler := &ManagerMock{}
|
||||||
|
nextHandler.On("Return", mock.AnythingOfType("*runner.NomadJob")).Return(nil)
|
||||||
|
m.SetNextHandler(nextHandler)
|
||||||
|
|
||||||
|
nonAWSRunner := NewNomadJob(tests.DefaultRunnerID, nil, nil, nil)
|
||||||
|
err := m.Return(nonAWSRunner)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
nextHandler.AssertCalled(t, "Return", nonAWSRunner)
|
||||||
|
})
|
||||||
|
}
|
143
internal/runner/aws_runner_test.go
Normal file
143
internal/runner/aws_runner_test.go
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
package runner
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
"github.com/openHPI/poseidon/internal/config"
|
||||||
|
"github.com/openHPI/poseidon/pkg/dto"
|
||||||
|
"github.com/openHPI/poseidon/tests"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAWSExecutionRequestIsStored(t *testing.T) {
|
||||||
|
r, err := NewAWSFunctionWorkload(nil, nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
executionRequest := &dto.ExecutionRequest{
|
||||||
|
Command: "command",
|
||||||
|
TimeLimit: 10,
|
||||||
|
Environment: nil,
|
||||||
|
}
|
||||||
|
r.StoreExecution(defaultExecutionID, executionRequest)
|
||||||
|
assert.True(t, r.ExecutionExists(defaultExecutionID))
|
||||||
|
storedExecutionRunner, ok := r.executions.Pop(defaultExecutionID)
|
||||||
|
assert.True(t, ok, "Getting an execution should not return ok false")
|
||||||
|
assert.Equal(t, executionRequest, storedExecutionRunner)
|
||||||
|
}
|
||||||
|
|
||||||
|
type awsEndpointMock struct {
|
||||||
|
hasConnected bool
|
||||||
|
ctx context.Context
|
||||||
|
receivedData string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *awsEndpointMock) handler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
upgrader := websocket.Upgrader{}
|
||||||
|
c, err := upgrader.Upgrade(w, r, nil)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
a.hasConnected = true
|
||||||
|
for a.ctx.Err() == nil {
|
||||||
|
_, message, err := c.ReadMessage()
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
a.receivedData = string(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAWSFunctionWorkload_ExecuteInteractively(t *testing.T) {
|
||||||
|
environment := &ExecutionEnvironmentMock{}
|
||||||
|
environment.On("Image").Return("testImage or AWS endpoint")
|
||||||
|
r, err := NewAWSFunctionWorkload(environment, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var cancel context.CancelFunc
|
||||||
|
awsMock := &awsEndpointMock{}
|
||||||
|
s := httptest.NewServer(http.HandlerFunc(awsMock.handler))
|
||||||
|
|
||||||
|
t.Run("establishes WebSocket connection to AWS endpoint", func(t *testing.T) {
|
||||||
|
// Convert http://127.0.0.1 to ws://127.0.0.
|
||||||
|
config.Config.AWS.Endpoint = "ws" + strings.TrimPrefix(s.URL, "http")
|
||||||
|
awsMock.ctx, cancel = context.WithCancel(context.Background())
|
||||||
|
cancel()
|
||||||
|
|
||||||
|
r.StoreExecution(defaultExecutionID, &dto.ExecutionRequest{})
|
||||||
|
exit, _, err := r.ExecuteInteractively(defaultExecutionID, nil, io.Discard, io.Discard)
|
||||||
|
require.NoError(t, err)
|
||||||
|
<-exit
|
||||||
|
assert.True(t, awsMock.hasConnected)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("sends execution request", func(t *testing.T) {
|
||||||
|
awsMock.ctx, cancel = context.WithTimeout(context.Background(), tests.ShortTimeout)
|
||||||
|
defer cancel()
|
||||||
|
command := "sl"
|
||||||
|
request := &dto.ExecutionRequest{Command: command}
|
||||||
|
r.StoreExecution(defaultExecutionID, request)
|
||||||
|
|
||||||
|
_, cancel, err := r.ExecuteInteractively(defaultExecutionID, nil, io.Discard, io.Discard)
|
||||||
|
require.NoError(t, err)
|
||||||
|
<-time.After(tests.ShortTimeout)
|
||||||
|
cancel()
|
||||||
|
|
||||||
|
expectedRequestData := "{\"action\":\"" + environment.Image() +
|
||||||
|
"\",\"cmd\":[\"env\",\"sh\",\"-c\",\"" + command + "\"],\"files\":{}}"
|
||||||
|
assert.Equal(t, expectedRequestData, awsMock.receivedData)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAWSFunctionWorkload_UpdateFileSystem(t *testing.T) {
|
||||||
|
environment := &ExecutionEnvironmentMock{}
|
||||||
|
environment.On("Image").Return("testImage or AWS endpoint")
|
||||||
|
r, err := NewAWSFunctionWorkload(environment, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var cancel context.CancelFunc
|
||||||
|
awsMock := &awsEndpointMock{}
|
||||||
|
s := httptest.NewServer(http.HandlerFunc(awsMock.handler))
|
||||||
|
|
||||||
|
// Convert http://127.0.0.1 to ws://127.0.0.
|
||||||
|
config.Config.AWS.Endpoint = "ws" + strings.TrimPrefix(s.URL, "http")
|
||||||
|
awsMock.ctx, cancel = context.WithTimeout(context.Background(), tests.ShortTimeout)
|
||||||
|
defer cancel()
|
||||||
|
command := "sl"
|
||||||
|
request := &dto.ExecutionRequest{Command: command}
|
||||||
|
r.StoreExecution(defaultExecutionID, request)
|
||||||
|
myFile := dto.File{Path: "myPath", Content: []byte("myContent")}
|
||||||
|
|
||||||
|
err = r.UpdateFileSystem(&dto.UpdateFileSystemRequest{Copy: []dto.File{myFile}})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_, execCancel, err := r.ExecuteInteractively(defaultExecutionID, nil, io.Discard, io.Discard)
|
||||||
|
require.NoError(t, err)
|
||||||
|
<-time.After(tests.ShortTimeout)
|
||||||
|
execCancel()
|
||||||
|
|
||||||
|
expectedRequestData := "{\"action\":\"" + environment.Image() +
|
||||||
|
"\",\"cmd\":[\"env\",\"sh\",\"-c\",\"" + command + "\"]," +
|
||||||
|
"\"files\":{\"" + string(myFile.Path) + "\":\"" + base64.StdEncoding.EncodeToString(myFile.Content) + "\"}}"
|
||||||
|
assert.Equal(t, expectedRequestData, awsMock.receivedData)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAWSFunctionWorkload_Destroy(t *testing.T) {
|
||||||
|
hasDestroyBeenCalled := false
|
||||||
|
r, err := NewAWSFunctionWorkload(nil, func(_ Runner) error {
|
||||||
|
hasDestroyBeenCalled = true
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
err = r.Destroy()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, hasDestroyBeenCalled)
|
||||||
|
}
|
Reference in New Issue
Block a user