Add tests for runners execute route
Co-authored-by: Tobias Kantusch <tobias.kantusch@student.hpi.uni-potsdam.de>
This commit is contained in:
12
api/api.go
12
api/api.go
@ -3,7 +3,7 @@ package api
|
||||
import (
|
||||
"github.com/gorilla/mux"
|
||||
"gitlab.hpi.de/codeocean/codemoon/poseidon/api/auth"
|
||||
"gitlab.hpi.de/codeocean/codemoon/poseidon/api/dto"
|
||||
"gitlab.hpi.de/codeocean/codemoon/poseidon/environment/pool"
|
||||
"gitlab.hpi.de/codeocean/codemoon/poseidon/logging"
|
||||
"net/http"
|
||||
)
|
||||
@ -21,18 +21,18 @@ const (
|
||||
// always returns a router for the newest version of our API. We
|
||||
// use gorilla/mux because it is more convenient than net/http, e.g.
|
||||
// when extracting path parameters.
|
||||
func NewRouter() http.Handler {
|
||||
func NewRouter(runnerPool pool.RunnerPool) *mux.Router {
|
||||
router := mux.NewRouter()
|
||||
router.Use(logging.HTTPLoggingMiddleware)
|
||||
// this can later be restricted to a specific host with
|
||||
// `router.Host(...)` and to HTTPS with `router.Schemes("https")`
|
||||
newRouterV1(router)
|
||||
router = newRouterV1(router, runnerPool)
|
||||
router.Use(logging.HTTPLoggingMiddleware)
|
||||
return router
|
||||
}
|
||||
|
||||
// newRouterV1 returns a sub-router containing the routes of version
|
||||
// 1 of our API.
|
||||
func newRouterV1(router *mux.Router) *mux.Router {
|
||||
func newRouterV1(router *mux.Router, runnerPool pool.RunnerPool) *mux.Router {
|
||||
v1 := router.PathPrefix(RouteBase).Subrouter()
|
||||
v1.HandleFunc(RouteHealth, Health).Methods(http.MethodGet)
|
||||
|
||||
@ -42,7 +42,7 @@ func newRouterV1(router *mux.Router) *mux.Router {
|
||||
v1 = v1.PathPrefix("").Subrouter()
|
||||
v1.Use(auth.HTTPAuthenticationMiddleware)
|
||||
}
|
||||
registerRunnerRoutes(v1.PathPrefix(RouteRunners).Subrouter())
|
||||
registerRunnerRoutes(v1.PathPrefix(RouteRunners).Subrouter(), runnerPool)
|
||||
|
||||
return v1
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gitlab.hpi.de/codeocean/codemoon/poseidon/config"
|
||||
"gitlab.hpi.de/codeocean/codemoon/poseidon/environment/pool"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
@ -16,7 +17,7 @@ func mockHTTPHandler(writer http.ResponseWriter, _ *http.Request) {
|
||||
func TestNewRouterV1WithAuthenticationDisabled(t *testing.T) {
|
||||
config.Config.Server.Token = ""
|
||||
router := mux.NewRouter()
|
||||
v1 := newRouterV1(router)
|
||||
v1 := newRouterV1(router, pool.NewLocalRunnerPool())
|
||||
|
||||
t.Run("health route is accessible", func(t *testing.T) {
|
||||
request, err := http.NewRequest(http.MethodGet, "/api/v1/health", nil)
|
||||
@ -43,7 +44,7 @@ func TestNewRouterV1WithAuthenticationDisabled(t *testing.T) {
|
||||
func TestNewRouterV1WithAuthenticationEnabled(t *testing.T) {
|
||||
config.Config.Server.Token = "TestToken"
|
||||
router := mux.NewRouter()
|
||||
v1 := newRouterV1(router)
|
||||
v1 := newRouterV1(router, pool.NewLocalRunnerPool())
|
||||
|
||||
t.Run("health route is accessible", func(t *testing.T) {
|
||||
request, err := http.NewRequest(http.MethodGet, "/api/v1/health", nil)
|
||||
|
@ -3,7 +3,6 @@ package api
|
||||
import (
|
||||
"encoding/json"
|
||||
"gitlab.hpi.de/codeocean/codemoon/poseidon/api/dto"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
|
@ -8,13 +8,24 @@ import (
|
||||
"gitlab.hpi.de/codeocean/codemoon/poseidon/api/dto"
|
||||
"gitlab.hpi.de/codeocean/codemoon/poseidon/config"
|
||||
"gitlab.hpi.de/codeocean/codemoon/poseidon/environment"
|
||||
"gitlab.hpi.de/codeocean/codemoon/poseidon/environment/pool"
|
||||
"gitlab.hpi.de/codeocean/codemoon/poseidon/runner"
|
||||
"log"
|
||||
"net/http"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// ProvideRunner tries to respond with the id of a runner
|
||||
var (
|
||||
executions = make(map[string]map[string]dto.ExecutionRequest)
|
||||
executionsLock = sync.Mutex{}
|
||||
)
|
||||
|
||||
func allocateExecutionMap(runner runner.Runner) {
|
||||
executionsLock.Lock()
|
||||
executions[runner.Id()] = make(map[string]dto.ExecutionRequest)
|
||||
executionsLock.Unlock()
|
||||
}
|
||||
|
||||
// provideRunner tries to respond with the id of a runner
|
||||
// This runner is then reserved for future use
|
||||
func provideRunner(writer http.ResponseWriter, request *http.Request) {
|
||||
runnerRequest := new(dto.RunnerRequest)
|
||||
@ -31,18 +42,14 @@ func provideRunner(writer http.ResponseWriter, request *http.Request) {
|
||||
writeInternalServerError(writer, err, dto.ErrorNomadOverload)
|
||||
return
|
||||
}
|
||||
executionsLock.Lock()
|
||||
executions[runner.Id] = make(map[string]dto.ExecutionRequest)
|
||||
executionsLock.Unlock()
|
||||
sendJson(writer, &dto.RunnerResponse{Id: runner.Id}, http.StatusOK)
|
||||
allocateExecutionMap(runner)
|
||||
sendJson(writer, &dto.RunnerResponse{Id: runner.Id()}, http.StatusOK)
|
||||
}
|
||||
|
||||
var (
|
||||
executions = make(map[string]map[string]dto.ExecutionRequest)
|
||||
executionsLock = sync.Mutex{}
|
||||
)
|
||||
|
||||
func executeCommand(writer http.ResponseWriter, request *http.Request) {
|
||||
// executeCommand takes an ExecutionRequest and stores it for a runner.
|
||||
// It returns a url to connect to for a websocket connection to this execution in the corresponding runner.
|
||||
func executeCommand(router *mux.Router) func(w http.ResponseWriter, r *http.Request) {
|
||||
return func(writer http.ResponseWriter, request *http.Request) {
|
||||
executionRequest := new(dto.ExecutionRequest)
|
||||
if err := parseRequestBodyJSON(writer, request, executionRequest); err != nil {
|
||||
return
|
||||
@ -67,7 +74,7 @@ func executeCommand(writer http.ResponseWriter, request *http.Request) {
|
||||
}
|
||||
|
||||
executionsLock.Lock()
|
||||
runnerExecutions, ok := executions[r.Id]
|
||||
runnerExecutions, ok := executions[r.Id()]
|
||||
if !ok {
|
||||
writeNotFound(writer, errors.New("runner has not been provided"))
|
||||
return
|
||||
@ -75,7 +82,7 @@ func executeCommand(writer http.ResponseWriter, request *http.Request) {
|
||||
runnerExecutions[id.String()] = *executionRequest
|
||||
executionsLock.Unlock()
|
||||
|
||||
path, err := router.Get("runner-websocket").URL("runnerId", r.Id)
|
||||
path, err := router.Get("runner-websocket").URL("runnerId", r.Id())
|
||||
if err != nil {
|
||||
log.Printf("Error creating runner websocket URL %v", err)
|
||||
writeInternalServerError(writer, err, dto.ErrorUnknown)
|
||||
@ -83,26 +90,24 @@ func executeCommand(writer http.ResponseWriter, request *http.Request) {
|
||||
}
|
||||
websocketUrl := fmt.Sprintf("%s://%s%s?executionId=%s", scheme, request.Host, path, id)
|
||||
sendJson(writer, &dto.WebsocketResponse{WebsocketUrl: websocketUrl}, http.StatusOK)
|
||||
}
|
||||
}
|
||||
|
||||
func connectToRunner(writer http.ResponseWriter, request *http.Request) {
|
||||
// Upgrade the connection to websocket
|
||||
// Todo: Execute the command, upgrade the connection to websocket and handle forwarding
|
||||
executionId := request.URL.Query()["executionId"]
|
||||
log.Printf("Websocket for execution %s requested", executionId)
|
||||
writer.WriteHeader(http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
func findRunnerMiddleware(next http.Handler) http.Handler {
|
||||
// The findRunnerMiddleware looks up the runnerId for routes containing it
|
||||
// and adds the runner to the context of the request.
|
||||
func findRunnerMiddleware(runnerPool pool.RunnerPool) func(handler http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
|
||||
// Find runner
|
||||
runnerId := mux.Vars(request)["runnerId"]
|
||||
// TODO: Get runner from runner store using runnerId
|
||||
env, err := execution_environment.GetExecutionEnvironment(1)
|
||||
if err != nil {
|
||||
writeNotFound(writer, err)
|
||||
return
|
||||
}
|
||||
r, ok := env.Runners[runnerId]
|
||||
r, ok := runnerPool.GetRunner(runnerId)
|
||||
if !ok {
|
||||
writer.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
@ -111,12 +116,13 @@ func findRunnerMiddleware(next http.Handler) http.Handler {
|
||||
requestWithRunner := request.WithContext(ctx)
|
||||
next.ServeHTTP(writer, requestWithRunner)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func registerRunnerRoutes(router *mux.Router) {
|
||||
func registerRunnerRoutes(router *mux.Router, runnerPool pool.RunnerPool) {
|
||||
router.HandleFunc("", provideRunner).Methods(http.MethodPost)
|
||||
runnerRouter := router.PathPrefix("/{runnerId}").Subrouter()
|
||||
runnerRouter.Use(findRunnerMiddleware)
|
||||
runnerRouter.HandleFunc("/execute", executeCommand).Methods(http.MethodPost).Name("runner-execute")
|
||||
runnerRouter.Use(findRunnerMiddleware(runnerPool))
|
||||
runnerRouter.HandleFunc("/execute", executeCommand(runnerRouter)).Methods(http.MethodPost).Name("runner-execute")
|
||||
runnerRouter.HandleFunc("/websocket", connectToRunner).Methods(http.MethodGet).Name("runner-websocket")
|
||||
}
|
||||
|
150
api/runners_test.go
Normal file
150
api/runners_test.go
Normal file
@ -0,0 +1,150 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gitlab.hpi.de/codeocean/codemoon/poseidon/api/dto"
|
||||
"gitlab.hpi.de/codeocean/codemoon/poseidon/environment/pool"
|
||||
"gitlab.hpi.de/codeocean/codemoon/poseidon/runner"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFindRunnerMiddleware(t *testing.T) {
|
||||
runnerPool := pool.NewLocalRunnerPool()
|
||||
var capturedRunner runner.Runner
|
||||
|
||||
testRunner := runner.NewExerciseRunner("testRunner")
|
||||
runnerPool.AddRunner(testRunner)
|
||||
|
||||
testRunnerIdRoute := func(writer http.ResponseWriter, request *http.Request) {
|
||||
var ok bool
|
||||
capturedRunner, ok = runner.FromContext(request.Context())
|
||||
if ok {
|
||||
writer.WriteHeader(http.StatusOK)
|
||||
} else {
|
||||
writer.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
router := mux.NewRouter()
|
||||
router.Use(findRunnerMiddleware(runnerPool))
|
||||
router.HandleFunc("/test/{runnerId}", testRunnerIdRoute).Name("test-runner-id")
|
||||
|
||||
testRunnerRequest := func(t *testing.T, runnerId string) *http.Request {
|
||||
path, err := router.Get("test-runner-id").URL("runnerId", runnerId)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
request, err := http.NewRequest(
|
||||
http.MethodPost, path.String(), nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return request
|
||||
}
|
||||
|
||||
t.Run("sets runner in context if runner exists", func(t *testing.T) {
|
||||
capturedRunner = nil
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
router.ServeHTTP(recorder, testRunnerRequest(t, testRunner.Id()))
|
||||
|
||||
assert.Equal(t, http.StatusOK, recorder.Code)
|
||||
assert.Equal(t, testRunner, capturedRunner)
|
||||
})
|
||||
|
||||
t.Run("returns 404 if runner does not exist", func(t *testing.T) {
|
||||
recorder := httptest.NewRecorder()
|
||||
router.ServeHTTP(recorder, testRunnerRequest(t, "some-invalid-runner-id"))
|
||||
|
||||
assert.Equal(t, http.StatusNotFound, recorder.Code)
|
||||
})
|
||||
}
|
||||
|
||||
func TestExecuteRoute(t *testing.T) {
|
||||
runnerPool := pool.NewLocalRunnerPool()
|
||||
|
||||
router := NewRouter(runnerPool)
|
||||
|
||||
testRunner := runner.NewExerciseRunner("testRunner")
|
||||
runnerPool.AddRunner(testRunner)
|
||||
allocateExecutionMap(testRunner)
|
||||
|
||||
path, err := router.Get("runner-execute").URL("runnerId", testRunner.Id())
|
||||
if err != nil {
|
||||
t.Fatal("Could not construct execute url")
|
||||
}
|
||||
|
||||
t.Run("valid request", func(t *testing.T) {
|
||||
recorder := httptest.NewRecorder()
|
||||
executionRequest := dto.ExecutionRequest{
|
||||
Command: "command",
|
||||
TimeLimit: 10,
|
||||
Environment: nil,
|
||||
}
|
||||
body, err := json.Marshal(executionRequest)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
request, err := http.NewRequest(http.MethodPost, path.String(), bytes.NewReader(body))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
router.ServeHTTP(recorder, request)
|
||||
|
||||
responseBody, err := io.ReadAll(recorder.Result().Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var websocketResponse dto.WebsocketResponse
|
||||
err = json.Unmarshal(responseBody, &websocketResponse)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Run("returns 200", func(t *testing.T) {
|
||||
assert.Equal(t, http.StatusOK, recorder.Code)
|
||||
})
|
||||
|
||||
t.Run("creates an execution request for the runner", func(t *testing.T) {
|
||||
url, err := url.Parse(websocketResponse.WebsocketUrl)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
executionId := url.Query().Get("executionId")
|
||||
|
||||
assert.Equal(t, executionRequest, executions[testRunner.Id()][executionId])
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("invalid request", func(t *testing.T) {
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
body := ""
|
||||
|
||||
request, err := http.NewRequest(http.MethodPost, path.String(), strings.NewReader(body))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
router.ServeHTTP(recorder, request)
|
||||
|
||||
_, err = io.ReadAll(recorder.Result().Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Run("returns 400", func(t *testing.T) {
|
||||
assert.Equal(t, http.StatusBadRequest, recorder.Code)
|
||||
})
|
||||
|
||||
})
|
||||
}
|
@ -16,7 +16,7 @@ func TestProvideRunnerRoute(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, http.StatusOK, resp.StatusCode, "The response code should be ok")
|
||||
|
||||
runnerResponse := new(dto.ResponseRunner)
|
||||
runnerResponse := new(dto.RunnerResponse)
|
||||
err = json.NewDecoder(resp.Body).Decode(runnerResponse)
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
24
go.sum
24
go.sum
@ -3,23 +3,40 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk=
|
||||
github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk=
|
||||
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
|
||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/hashicorp/cronexpr v1.1.0/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4=
|
||||
github.com/hashicorp/cronexpr v1.1.0/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4=
|
||||
github.com/hashicorp/cronexpr v1.1.1 h1:NJZDd87hGXjoZBdvyCF9mX4DCq5Wy7+A/w+A7q0wn6c=
|
||||
github.com/hashicorp/cronexpr v1.1.1 h1:NJZDd87hGXjoZBdvyCF9mX4DCq5Wy7+A/w+A7q0wn6c=
|
||||
github.com/hashicorp/cronexpr v1.1.1/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4=
|
||||
github.com/hashicorp/cronexpr v1.1.1/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||
github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
|
||||
github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
|
||||
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
||||
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
||||
github.com/hashicorp/nomad/api v0.0.0-20210430020956-28b8767b278f h1:XaaK4F+pOV2ZYk3aCIDAZThm3voKD6nyOUNeUY3yHgY=
|
||||
github.com/hashicorp/nomad/api v0.0.0-20210430020956-28b8767b278f h1:XaaK4F+pOV2ZYk3aCIDAZThm3voKD6nyOUNeUY3yHgY=
|
||||
github.com/hashicorp/nomad/api v0.0.0-20210430020956-28b8767b278f/go.mod h1:vYHP9jMXk4/T2qNUbWlQ1OHCA1hHLil3nvqSmz8mtgc=
|
||||
github.com/hashicorp/nomad/api v0.0.0-20210430020956-28b8767b278f/go.mod h1:vYHP9jMXk4/T2qNUbWlQ1OHCA1hHLil3nvqSmz8mtgc=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
@ -32,7 +49,10 @@ github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk
|
||||
github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
|
||||
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
|
||||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
@ -49,10 +69,14 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 h1:dXfMednGJh/SUUFjTLsWJz3P+TQt9qnR11GgeI3vWKs=
|
||||
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
14
main.go
14
main.go
@ -38,13 +38,13 @@ func runServer(server *http.Server) {
|
||||
}
|
||||
}
|
||||
|
||||
func initServer() *http.Server {
|
||||
func initServer(runnerPool pool.RunnerPool) *http.Server {
|
||||
return &http.Server{
|
||||
Addr: config.Config.PoseidonAPIURL().Host,
|
||||
WriteTimeout: time.Second * 15,
|
||||
ReadTimeout: time.Second * 15,
|
||||
IdleTimeout: time.Second * 60,
|
||||
Handler: api.NewRouter(),
|
||||
Handler: api.NewRouter(runnerPool),
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,17 +67,19 @@ func main() {
|
||||
log.WithError(err).Warn("Could not initialize configuration")
|
||||
}
|
||||
logging.InitializeLogging(config.Config.Logger.Level)
|
||||
server := initServer()
|
||||
log.WithField("address", server.Addr).Info("Starting server")
|
||||
|
||||
// API initialization
|
||||
nomadAPIClient, err := nomad.New(config.Config.NomadAPIURL())
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("nomad url", config.Config.NomadAPIURL()).Fatal("Error parsing the nomad url")
|
||||
}
|
||||
|
||||
// ToDo: Move to create execution environment
|
||||
runnersPool := pool.NewLocalRunnerPool()
|
||||
environment.DebugInit(runnersPool, nomadAPIClient)
|
||||
runnerPool := pool.NewLocalRunnerPool()
|
||||
environment.DebugInit(runnerPool, nomadAPIClient)
|
||||
|
||||
server := initServer(runnerPool)
|
||||
log.WithField("address", server.Addr).Info("Starting server")
|
||||
|
||||
go runServer(server)
|
||||
shutdownOnOSSignal(server)
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
)
|
||||
|
||||
type Status string
|
||||
type ContextKey string
|
||||
|
||||
const (
|
||||
StatusReady Status = "ready"
|
||||
@ -15,7 +16,7 @@ const (
|
||||
StatusFinished Status = "finished"
|
||||
|
||||
// runnerContextKey is the key used to store runners in context.Context
|
||||
runnerContextKey = "runner"
|
||||
runnerContextKey ContextKey = "runner"
|
||||
)
|
||||
|
||||
type Runner interface {
|
||||
@ -74,11 +75,11 @@ func (r *ExerciseRunner) Id() string {
|
||||
return r.id
|
||||
}
|
||||
|
||||
func NewContext(ctx context.Context, runner *Runner) context.Context {
|
||||
func NewContext(ctx context.Context, runner Runner) context.Context {
|
||||
return context.WithValue(ctx, runnerContextKey, runner)
|
||||
}
|
||||
|
||||
func FromContext(ctx context.Context) (*Runner, bool) {
|
||||
runner, ok := ctx.Value(runnerContextKey).(*Runner)
|
||||
func FromContext(ctx context.Context) (Runner, bool) {
|
||||
runner, ok := ctx.Value(runnerContextKey).(Runner)
|
||||
return runner, ok
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package runner
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
@ -30,3 +31,29 @@ func TestMarshalRunner(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "{\"runnerId\":\"42\",\"status\":\"ready\"}", string(marshal))
|
||||
}
|
||||
|
||||
func TestNewContextReturnsNewContextWithRunner(t *testing.T) {
|
||||
runner := NewExerciseRunner("testRunner")
|
||||
ctx := context.Background()
|
||||
newCtx := NewContext(ctx, runner)
|
||||
storedRunner := newCtx.Value(runnerContextKey).(Runner)
|
||||
|
||||
assert.NotEqual(t, ctx, newCtx)
|
||||
assert.Equal(t, runner, storedRunner)
|
||||
}
|
||||
|
||||
func TestFromContextReturnsRunner(t *testing.T) {
|
||||
runner := NewExerciseRunner("testRunner")
|
||||
ctx := NewContext(context.Background(), runner)
|
||||
storedRunner, ok := FromContext(ctx)
|
||||
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, runner, storedRunner)
|
||||
}
|
||||
|
||||
func TestFromContextReturnsIsNotOkWhenContextHasNoRunner(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
_, ok := FromContext(ctx)
|
||||
|
||||
assert.False(t, ok)
|
||||
}
|
||||
|
Reference in New Issue
Block a user