Add e2e tests in ci stage

This commit is contained in:
Maximilian Paß
2021-04-28 13:42:33 +02:00
parent 77f84ccf56
commit 0dc4d28c1b
12 changed files with 118 additions and 23 deletions

View File

@@ -48,15 +48,33 @@ test:
stage: test stage: test
needs: [] needs: []
script: script:
- go test $(go list ./... | grep -v /e2e) -v -coverprofile coverage.cov - go test $(go list ./... | grep -v /e2e | grep -v /poseidon$) -v -coverprofile coverage.cov
- go tool cover -func=coverage.cov - go tool cover -func=coverage.cov
- go tool cover -html=coverage.cov -o coverage.html - go tool cover -html=coverage.cov -o coverage_unit.html
artifacts: artifacts:
paths: paths:
- coverage.html - coverage_unit.html
expire_in: 1 week expire_in: 1 week
expose_as: coverageReport expose_as: coverageReport
e2e_test:
image: drp.codemoon.xopic.de/nomad-ci:latest
stage: test
services:
- name: docker:dind
alias: docker
script:
# Avoid docker pull limit
- docker login -u $DOCKER_REGISTRY_USER -p $DOCKER_REGISTRY_PASSWORD $DOCKER_REGISTRY
- docker pull $DOCKER_REGISTRY/openhpi/co_execenv_python:3.8
- docker tag $DOCKER_REGISTRY/openhpi/co_execenv_python:3.8 openhpi/co_execenv_python:3.8
# Setup own nomad cluster
- export NOMAD_ADDR=http://localhost:4646
- nomad agent -dev -log-level=WARN &
- sleep 15
# Start tests
- go test ./ ./e2e -v
dockerimage: dockerimage:
stage: docker stage: docker
image: docker:latest image: docker:latest
@@ -85,8 +103,8 @@ nomadimage:
script: script:
- cd ci - cd ci
- docker login -u $DOCKER_REGISTRY_USER -p $DOCKER_REGISTRY_PASSWORD $DOCKER_REGISTRY - docker login -u $DOCKER_REGISTRY_USER -p $DOCKER_REGISTRY_PASSWORD $DOCKER_REGISTRY
- docker pull $DOCKER_REGISTRY/library/debian:buster-slim - docker pull $DOCKER_REGISTRY/library/golang:latest
- docker tag $DOCKER_REGISTRY/library/debian:buster-slim debian:buster-slim - docker tag $DOCKER_REGISTRY/library/golang:latest golang:latest
# Pull base image to avoid rebuilding every pipeline if nothing changed, prioritize image from branch # Pull base image to avoid rebuilding every pipeline if nothing changed, prioritize image from branch
- docker pull $NOMAD_CI_IMAGE_NAME_GENERAL || docker pull $NOMAD_CI_BASE_IMAGE || true - docker pull $NOMAD_CI_IMAGE_NAME_GENERAL || docker pull $NOMAD_CI_BASE_IMAGE || true
- docker build --cache-from $NOMAD_CI_BASE_IMAGE --cache-from $NOMAD_CI_IMAGE_NAME_GENERAL -t $NOMAD_CI_IMAGE_NAME_ENV -t $NOMAD_CI_IMAGE_NAME_GENERAL . - docker build --cache-from $NOMAD_CI_BASE_IMAGE --cache-from $NOMAD_CI_IMAGE_NAME_GENERAL -t $NOMAD_CI_IMAGE_NAME_ENV -t $NOMAD_CI_IMAGE_NAME_GENERAL .

View File

@@ -27,12 +27,12 @@ func provideRunner(writer http.ResponseWriter, request *http.Request) {
if err := parseJSONRequestBody(writer, request, runnerRequest); err != nil { if err := parseJSONRequestBody(writer, request, runnerRequest); err != nil {
return return
} }
environment, err := environment.GetExecutionEnvironment(runnerRequest.ExecutionEnvironmentId) env, err := environment.GetExecutionEnvironment(runnerRequest.ExecutionEnvironmentId)
if err != nil { if err != nil {
writeNotFound(writer, err) writeNotFound(writer, err)
return return
} }
runner, err := environment.NextRunner() runner, err := env.NextRunner()
if err != nil { if err != nil {
writeInternalServerError(writer, err, dto.ErrorNomadOverload) writeInternalServerError(writer, err, dto.ErrorNomadOverload)
return return

View File

@@ -1,12 +1,25 @@
# Simple image containing the Nomad binary to deploy Nomad jobs # Simple image containing the Nomad binary to deploy Nomad jobs
FROM debian:buster-slim FROM golang:latest
# Install prerequisites, gettext contains envsubst used in the CI # Install prerequisites, gettext contains envsubst used in the CI
RUN apt-get update && \ RUN apt-get update && \
apt install -y unzip wget gettext && \ apt install -y unzip wget gettext && \
apt-get clean && \ apt-get clean && \
rm -rf /var/lib/apt/lists rm -rf /var/lib/apt/lists && \
apt-get install -y \
apt-transport-https \
ca-certificates \
curl \
gnupg
RUN apt-get update && apt-get install -y lsb-release && apt-get clean all
RUN curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
RUN echo \
"deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian \
$(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
RUN apt-get update && \
apt-get install -y docker-ce docker-ce-cli containerd.io
# Download Nomad # Download Nomad
RUN wget "https://releases.hashicorp.com/nomad/1.0.4/nomad_1.0.4_linux_amd64.zip" && \ RUN wget "https://releases.hashicorp.com/nomad/1.0.4/nomad_1.0.4_linux_amd64.zip" && \
@@ -19,3 +32,9 @@ RUN mv nomad /usr/sbin/ && nomad -version
COPY nomad-run-and-wait /usr/sbin/ COPY nomad-run-and-wait /usr/sbin/
RUN chmod +x /usr/sbin/nomad-run-and-wait RUN chmod +x /usr/sbin/nomad-run-and-wait
RUN wget "https://raw.githubusercontent.com/docker-library/docker/f6a0c427f0354dcf5870c430c72c8f1d6b4e6d5e/20.10/docker-entrypoint.sh"
RUN mv ./docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["sh"]

View File

@@ -26,7 +26,7 @@ var (
KeyFile: "", KeyFile: "",
}, },
Nomad: nomad{ Nomad: nomad{
Address: "", Address: "127.0.0.1",
Port: 4646, Port: 4646,
Token: "", Token: "",
TLS: false, TLS: false,

View File

@@ -12,9 +12,7 @@ import (
* For the e2e tests a nomad cluster must be connected and poseidon must be running. * For the e2e tests a nomad cluster must be connected and poseidon must be running.
*/ */
var baseURL = config.Config.PoseidonAPIURL().String()
func buildURL(parts ...string) (url string) { func buildURL(parts ...string) (url string) {
parts = append([]string{baseURL, api.RouteBase}, parts...) parts = append([]string{config.Config.PoseidonAPIURL().String(), api.RouteBase}, parts...)
return strings.Join(parts, "") return strings.Join(parts, "")
} }

View File

@@ -2,6 +2,7 @@ package e2e
import ( import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gitlab.hpi.de/codeocean/codemoon/poseidon/api" "gitlab.hpi.de/codeocean/codemoon/poseidon/api"
"net/http" "net/http"
"testing" "testing"
@@ -9,6 +10,6 @@ import (
func TestHealthRoute(t *testing.T) { func TestHealthRoute(t *testing.T) {
resp, err := http.Get(buildURL(api.RouteHealth)) resp, err := http.Get(buildURL(api.RouteHealth))
assert.NoError(t, err) require.NoError(t, err)
assert.Equal(t, http.StatusNoContent, resp.StatusCode, "The response code should be NoContent") assert.Equal(t, http.StatusNoContent, resp.StatusCode, "The response code should be NoContent")
} }

4
go.mod
View File

@@ -8,12 +8,12 @@ require (
github.com/gorilla/websocket v1.4.2 // indirect github.com/gorilla/websocket v1.4.2 // indirect
github.com/hashicorp/cronexpr v1.1.1 // indirect github.com/hashicorp/cronexpr v1.1.1 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/nomad/api v0.0.0-20210430020956-28b8767b278f github.com/hashicorp/nomad/api v0.0.0-20210505182403-7d5a9ecde95c
github.com/kr/text v0.2.0 // indirect github.com/kr/text v0.2.0 // indirect
github.com/mitchellh/mapstructure v1.4.1 // indirect github.com/mitchellh/mapstructure v1.4.1 // indirect
github.com/sirupsen/logrus v1.8.1 github.com/sirupsen/logrus v1.8.1
github.com/stretchr/objx v0.1.1 // indirect github.com/stretchr/objx v0.1.1 // indirect
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.7.0
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 // indirect golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
) )

10
go.sum
View File

@@ -34,10 +34,8 @@ github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5O
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/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-20210505182403-7d5a9ecde95c h1:b0V392CjnzubekagqWqgxG4YCQQi3lf74yEijJLmyE8=
github.com/hashicorp/nomad/api v0.0.0-20210430020956-28b8767b278f h1:XaaK4F+pOV2ZYk3aCIDAZThm3voKD6nyOUNeUY3yHgY= github.com/hashicorp/nomad/api v0.0.0-20210505182403-7d5a9ecde95c/go.mod h1:vYHP9jMXk4/T2qNUbWlQ1OHCA1hHLil3nvqSmz8mtgc=
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 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@@ -66,8 +64,8 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 h1:dXfMednGJh/SUUFjTLsWJz3P+TQt9qnR11GgeI3vWKs= golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6 h1:cdsMqa2nXzqlgs183pHxtvoVwU7CyzaCTAUOg94af4c=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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 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=

View File

@@ -11,6 +11,7 @@ import (
"net/http" "net/http"
"os" "os"
"os/signal" "os/signal"
"syscall"
"time" "time"
) )
@@ -53,7 +54,7 @@ func initServer(runnerPool pool.RunnerPool) *http.Server {
func shutdownOnOSSignal(server *http.Server) { func shutdownOnOSSignal(server *http.Server) {
// wait for SIGINT // wait for SIGINT
signals := make(chan os.Signal, 1) signals := make(chan os.Signal, 1)
signal.Notify(signals, os.Interrupt) signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
<-signals <-signals
log.Info("Received SIGINT, shutting down ...") log.Info("Received SIGINT, shutting down ...")

32
main_test.go Normal file
View File

@@ -0,0 +1,32 @@
package main
import (
"gitlab.hpi.de/codeocean/codemoon/poseidon/config"
"gitlab.hpi.de/codeocean/codemoon/poseidon/nomad"
"os"
"testing"
"time"
)
// overwrite TestMain for custom setup
func TestMain(m *testing.M) {
log.Print("Test Setup")
setup()
log.Print("Test Run")
code := m.Run()
os.Exit(code)
}
func setup() {
createNomadJob()
go main()
time.Sleep(15 * time.Second)
}
func createNomadJob() {
nomadAPIClient, err := nomad.New(config.Config.NomadAPIURL())
if err != nil {
log.WithError(err).Fatal("[Test] Can not parse nomad config")
}
nomadAPIClient.CreateDebugJob()
}

View File

@@ -12,6 +12,11 @@ type ExecutorApi struct {
mock.Mock mock.Mock
} }
// CreateDebugJob provides a mock function with given fields:
func (_m *ExecutorApi) CreateDebugJob() {
_m.Called()
}
// GetJobScale provides a mock function with given fields: jobId // GetJobScale provides a mock function with given fields: jobId
func (_m *ExecutorApi) GetJobScale(jobId string) (int, error) { func (_m *ExecutorApi) GetJobScale(jobId string) (int, error) {
ret := _m.Called(jobId) ret := _m.Called(jobId)

View File

@@ -2,15 +2,19 @@ package nomad
import ( import (
nomadApi "github.com/hashicorp/nomad/api" nomadApi "github.com/hashicorp/nomad/api"
"gitlab.hpi.de/codeocean/codemoon/poseidon/logging"
"net/url" "net/url"
) )
var log = logging.GetLogger("nomad")
// ExecutorApi provides access to an container orchestration solution // ExecutorApi provides access to an container orchestration solution
type ExecutorApi interface { type ExecutorApi interface {
LoadJobList() (list []*nomadApi.JobListStub, err error) LoadJobList() (list []*nomadApi.JobListStub, err error)
GetJobScale(jobId string) (jobScale int, err error) GetJobScale(jobId string) (jobScale int, err error)
SetJobScaling(jobId string, count int, reason string) (err error) SetJobScaling(jobId string, count int, reason string) (err error)
LoadRunners(jobId string) (runnerIds []string, err error) LoadRunners(jobId string) (runnerIds []string, err error)
CreateDebugJob()
} }
// ApiClient provides access to the Nomad functionality // ApiClient provides access to the Nomad functionality
@@ -41,6 +45,25 @@ func (apiClient *ApiClient) LoadJobList() (list []*nomadApi.JobListStub, err err
return return
} }
// CreateDebugJob creates a simple python job in the nomad cluster
func (apiClient *ApiClient) CreateDebugJob() {
job := nomadApi.NewBatchJob("python", "python", "global", 50)
job.AddDatacenter("dc1")
group := nomadApi.NewTaskGroup("python", 5)
task := nomadApi.NewTask("python", "docker")
task.SetConfig("image", "openhpi/co_execenv_python:3.8")
task.SetConfig("command", "sleep")
task.SetConfig("args", []string{"infinity"})
group.AddTask(task)
job.AddTaskGroup(group)
register, w, err := apiClient.client.Jobs().Register(job, nil)
log.Printf("response: %+v", register)
log.Printf("meta: %+v", w)
if err != nil {
log.WithError(err).Fatal("Error creating nomad job")
}
}
// GetJobScale returns the scale of the passed job. // GetJobScale returns the scale of the passed job.
func (apiClient *ApiClient) GetJobScale(jobId string) (jobScale int, err error) { func (apiClient *ApiClient) GetJobScale(jobId string) (jobScale int, err error) {
status, _, err := apiClient.client.Jobs().ScaleStatus(jobId, nil) status, _, err := apiClient.client.Jobs().ScaleStatus(jobId, nil)