166 lines
5.5 KiB
Go
166 lines
5.5 KiB
Go
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"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
func (s *MainTestSuite) TestAWSExecutionRequestIsStored() {
|
|
environment := &ExecutionEnvironmentMock{}
|
|
environment.On("ID").Return(dto.EnvironmentID(tests.DefaultEnvironmentIDAsInteger))
|
|
r, err := NewAWSFunctionWorkload(environment, func(_ Runner) error { return nil })
|
|
s.NoError(err)
|
|
executionRequest := &dto.ExecutionRequest{
|
|
Command: "command",
|
|
TimeLimit: 10,
|
|
Environment: nil,
|
|
}
|
|
r.StoreExecution(tests.DefaultEnvironmentIDAsString, executionRequest)
|
|
s.True(r.ExecutionExists(tests.DefaultEnvironmentIDAsString))
|
|
storedExecutionRunner, ok := r.executions.Pop(tests.DefaultEnvironmentIDAsString)
|
|
s.True(ok, "Getting an execution should not return ok false")
|
|
s.Equal(executionRequest, storedExecutionRunner)
|
|
|
|
err = r.Destroy(nil)
|
|
s.NoError(err)
|
|
}
|
|
|
|
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 (s *MainTestSuite) TestAWSFunctionWorkload_ExecuteInteractively() {
|
|
environment := &ExecutionEnvironmentMock{}
|
|
environment.On("ID").Return(dto.EnvironmentID(tests.DefaultEnvironmentIDAsInteger))
|
|
environment.On("Image").Return("testImage or AWS endpoint")
|
|
r, err := NewAWSFunctionWorkload(environment, func(_ Runner) error { return nil })
|
|
s.Require().NoError(err)
|
|
|
|
var cancel context.CancelFunc
|
|
awsMock := &awsEndpointMock{}
|
|
sv := httptest.NewServer(http.HandlerFunc(awsMock.handler))
|
|
defer sv.Close()
|
|
|
|
s.Run("establishes WebSocket connection to AWS endpoint", func() {
|
|
// Convert http://127.0.0.1 to ws://127.0.0.1
|
|
config.Config.AWS.Endpoint = "ws" + strings.TrimPrefix(sv.URL, "http")
|
|
awsMock.ctx, cancel = context.WithCancel(context.Background())
|
|
cancel()
|
|
|
|
r.StoreExecution(tests.DefaultEnvironmentIDAsString, &dto.ExecutionRequest{})
|
|
exit, _, err := r.ExecuteInteractively(
|
|
tests.DefaultEnvironmentIDAsString, nil, io.Discard, io.Discard, s.TestCtx)
|
|
s.Require().NoError(err)
|
|
<-exit
|
|
s.True(awsMock.hasConnected)
|
|
})
|
|
|
|
s.Run("sends execution request", func() {
|
|
s.T().Skip("The AWS runner ignores its context for executions and waits infinetly for the exit message.") // ToDo
|
|
awsMock.ctx, cancel = context.WithTimeout(context.Background(), tests.ShortTimeout)
|
|
defer cancel()
|
|
command := "sl"
|
|
request := &dto.ExecutionRequest{Command: command}
|
|
r.StoreExecution(tests.DefaultEnvironmentIDAsString, request)
|
|
|
|
_, cancel, err := r.ExecuteInteractively(
|
|
tests.DefaultEnvironmentIDAsString, nil, io.Discard, io.Discard, s.TestCtx)
|
|
s.Require().NoError(err)
|
|
<-time.After(tests.ShortTimeout)
|
|
cancel()
|
|
|
|
expectedRequestData := `{"action":"` + environment.Image() +
|
|
`","cmd":["/bin/bash","-c","env CODEOCEAN=true /bin/bash -c \"unset \\\"\\${!AWS@}\\\" \u0026\u0026 ` + command +
|
|
`\""],"files":{}}`
|
|
s.Equal(expectedRequestData, awsMock.receivedData)
|
|
})
|
|
|
|
err = r.Destroy(nil)
|
|
s.NoError(err)
|
|
}
|
|
|
|
func (s *MainTestSuite) TestAWSFunctionWorkload_UpdateFileSystem() {
|
|
s.T().Skip("The AWS runner ignores its context for executions and waits infinetly for the exit message.") // ToDo
|
|
|
|
environment := &ExecutionEnvironmentMock{}
|
|
environment.On("ID").Return(dto.EnvironmentID(tests.DefaultEnvironmentIDAsInteger))
|
|
environment.On("Image").Return("testImage or AWS endpoint")
|
|
r, err := NewAWSFunctionWorkload(environment, nil)
|
|
s.Require().NoError(err)
|
|
|
|
var cancel context.CancelFunc
|
|
awsMock := &awsEndpointMock{}
|
|
sv := httptest.NewServer(http.HandlerFunc(awsMock.handler))
|
|
defer sv.Close()
|
|
|
|
// Convert http://127.0.0.1 to ws://127.0.0.1
|
|
config.Config.AWS.Endpoint = "ws" + strings.TrimPrefix(sv.URL, "http")
|
|
awsMock.ctx, cancel = context.WithTimeout(context.Background(), tests.ShortTimeout)
|
|
defer cancel()
|
|
command := "sl"
|
|
request := &dto.ExecutionRequest{Command: command}
|
|
r.StoreExecution(tests.DefaultEnvironmentIDAsString, request)
|
|
myFile := dto.File{Path: "myPath", Content: []byte("myContent")}
|
|
|
|
err = r.UpdateFileSystem(&dto.UpdateFileSystemRequest{Copy: []dto.File{myFile}}, s.TestCtx)
|
|
s.NoError(err)
|
|
_, execCancel, err := r.ExecuteInteractively(
|
|
tests.DefaultEnvironmentIDAsString, nil, io.Discard, io.Discard, s.TestCtx)
|
|
s.Require().NoError(err)
|
|
<-time.After(tests.ShortTimeout)
|
|
execCancel()
|
|
|
|
expectedRequestData := `{"action":"` + environment.Image() +
|
|
`","cmd":["/bin/bash","-c","env CODEOCEAN=true /bin/bash -c \"unset \\\"\\${!AWS@}\\\" \u0026\u0026 ` + command +
|
|
`\""],"files":{"` + string(myFile.Path) + `":"` + base64.StdEncoding.EncodeToString(myFile.Content) + `"}}`
|
|
s.Equal(expectedRequestData, awsMock.receivedData)
|
|
|
|
err = r.Destroy(nil)
|
|
s.NoError(err)
|
|
}
|
|
|
|
func (s *MainTestSuite) TestAWSFunctionWorkload_Destroy() {
|
|
environment := &ExecutionEnvironmentMock{}
|
|
environment.On("ID").Return(dto.EnvironmentID(tests.DefaultEnvironmentIDAsInteger))
|
|
hasDestroyBeenCalled := false
|
|
r, err := NewAWSFunctionWorkload(environment, func(_ Runner) error {
|
|
hasDestroyBeenCalled = true
|
|
return nil
|
|
})
|
|
s.Require().NoError(err)
|
|
|
|
var reason error
|
|
err = r.Destroy(reason)
|
|
s.NoError(err)
|
|
s.True(hasDestroyBeenCalled)
|
|
}
|