diff --git a/cmd/vela-worker/exec.go b/cmd/vela-worker/exec.go index 62aa11988..76ec0ac54 100644 --- a/cmd/vela-worker/exec.go +++ b/cmd/vela-worker/exec.go @@ -52,6 +52,7 @@ func (w *Worker) exec(index int) error { // https://pkg.go.dev/github.com/go-vela/worker/runtime?tab=doc#New w.Runtime, err = runtime.New(&runtime.Setup{ Logger: logger, + Mock: w.Config.Runtime.Mock, Driver: w.Config.Runtime.Driver, ConfigFile: w.Config.Runtime.ConfigFile, HostVolumes: w.Config.Runtime.HostVolumes, diff --git a/cmd/vela-worker/exec_test.go b/cmd/vela-worker/exec_test.go new file mode 100644 index 000000000..cd8bc16fe --- /dev/null +++ b/cmd/vela-worker/exec_test.go @@ -0,0 +1,470 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package main + +import ( + "context" + "encoding/json" + "fmt" + "net/http/httptest" + "net/url" + "testing" + "time" + + "github.com/go-vela/sdk-go/vela" + "github.com/go-vela/server/mock/server" + "github.com/go-vela/server/queue/redis" + "github.com/go-vela/types" + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" + "github.com/go-vela/types/pipeline" + "github.com/go-vela/worker/executor" + "github.com/go-vela/worker/mock/worker" + "github.com/go-vela/worker/runtime" +) + +func TestWorker_exec(t *testing.T) { + // setup types for tests + _repo := testRepo() + _user := testUser() + + type testStruct struct { + name string + config *workerTestConfig + pipeline *pipeline.Build + wantErr bool + } + + // this gets expanded into the product of runtime-executor-baseTest + baseTests := []testStruct{ + { + name: "steps", + pipeline: _steps, + config: &workerTestConfig{}, + }, + { + name: "stages", + pipeline: _stages, + config: &workerTestConfig{}, + }, + } + executors := []workerTestConfig{ + { + name: constants.DriverLinux, + executorDriver: constants.DriverLinux, + //executorLogMethod: + }, + { + name: constants.DriverLocal, + executorDriver: constants.DriverLocal, + //executorLogMethod: + }, + } + runtimes := []workerTestConfig{ + { + name: constants.DriverDocker, + runtimeDriver: constants.DriverDocker, + }, + // TODO: kubernetes tests are hanging. Fix in a follow-up. + //{ + // name: constants.DriverKubernetes, + // runtimeDriver: constants.DriverKubernetes, + // runtimeNamespace: "test", + // runtimeConfigFile: "../../runtime/kubernetes/testdata/config", + //}, + } + + // if tests are needed beyond the matrix of tests, they can be added explicitly here. + var tests []testStruct + + for _, r := range runtimes { + for _, e := range executors { + for _, test := range baseTests { + tests = append(tests, testStruct{ + // matrix name format: runtime-executor-subtest + name: fmt.Sprintf("%s-%s-%s", r.name, e.name, test.name), + pipeline: test.pipeline, + config: (&workerTestConfig{ + // executor + executorDriver: e.executorDriver, + executorLogMethod: e.executorLogMethod, + executorMaxLogSize: e.executorMaxLogSize, + // runtime + runtimeDriver: r.runtimeDriver, + runtimeConfigFile: r.runtimeConfigFile, + runtimeNamespace: r.runtimeNamespace, + runtimePodsTemplateName: r.runtimePodsTemplateName, + runtimePodsTemplateFile: r.runtimePodsTemplateFile, + runtimePrivilegedImages: r.runtimePrivilegedImages, + runtimeHostVolumes: r.runtimeHostVolumes, + // etc + buildTimeout: test.config.buildTimeout, + logFormat: test.config.logFormat, + logLevel: test.config.logLevel, + route: test.config.route, + queueRoutes: test.config.queueRoutes, + queuePopTimeout: test.config.queuePopTimeout, + }).applyDefaults(), + }) + } + } + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + var ( + err error + w *Worker + byteItem []byte + ) + + w, err = mockWorker(test.config) + if err != nil { + t.Errorf("mockWorker error = %v", err) + } + + _build := testBuild(w.Config) + + byteItem, err = json.Marshal(types.Item{ + Build: _build, + Pipeline: test.pipeline, + Repo: _repo, + User: _user, + }) + if err != nil { + t.Errorf("queue queueItem marshall error = %v", err) + } + + // add test.queueItem to the queue + err = w.Queue.Push(context.Background(), test.config.route, byteItem) + if err != nil { + t.Errorf("queue push error = %v", err) + } + + // actually run our test + if err = w.exec(0); (err != nil) != test.wantErr { + t.Errorf("exec() error = %v, wantErr %v", err, test.wantErr) + } + }) + } +} + +type workerTestConfig struct { + name string + buildTimeout time.Duration + executorDriver string + executorLogMethod string + executorMaxLogSize uint + logFormat string + logLevel string + runtimeDriver string + runtimeConfigFile string // only for k8s + runtimeNamespace string // only for k8s + runtimePodsTemplateName string // only for k8s + runtimePodsTemplateFile string // only for k8s + runtimePrivilegedImages []string + runtimeHostVolumes []string + route string + queueRoutes []string + queuePopTimeout time.Duration +} + +// applyDefaults applies defaults for tests +// nolint:wsl // wsl prevents visual grouping of defaults +func (c *workerTestConfig) applyDefaults() *workerTestConfig { + // defaults from flags.go (might need to lower for tests) + if c.buildTimeout == 0 { + c.buildTimeout = 30 * time.Minute + } + if c.logFormat == "" { + c.logFormat = "json" + } + if c.logLevel == "" { + c.logLevel = "info" + } + + // defaults from executor.Flags + if c.executorLogMethod == "" { + c.executorLogMethod = "byte-chunks" + } + + // defaults from runtime.Flags + if c.runtimeDriver == "" { + c.runtimeDriver = constants.DriverDocker + } + if c.runtimePrivilegedImages == nil { + c.runtimePrivilegedImages = []string{"target/vela-docker"} + } + + // defaults from runtime.Flags + if c.queueRoutes == nil { + c.queueRoutes = []string{constants.DefaultRoute} + } + if c.queuePopTimeout == 0 { + c.queuePopTimeout = 60 * time.Second + } + + // convenient default (not based on anything) + if c.route == "" { + c.route = constants.DefaultRoute + } + + return c +} + +func mockWorker(cfg *workerTestConfig) (*Worker, error) { + var err error + + // Worker initialized in run() + w := &Worker{ + // worker configuration (skipping fields unused by exec()) + Config: &Config{ + // api configuration + API: &API{}, + // build configuration + Build: &Build{ + Limit: 1, + Timeout: cfg.buildTimeout, + }, + // executor configuration + Executor: &executor.Setup{ + Driver: cfg.executorDriver, + LogMethod: cfg.executorLogMethod, + MaxLogSize: cfg.executorMaxLogSize, + }, + // logger configuration + Logger: &Logger{ + Format: cfg.logFormat, + Level: cfg.logLevel, + }, + // runtime configuration + Runtime: &runtime.Setup{ + Mock: true, + Driver: cfg.runtimeDriver, + ConfigFile: cfg.runtimeConfigFile, + Namespace: cfg.runtimeNamespace, + PodsTemplateName: cfg.runtimePodsTemplateName, + PodsTemplateFile: cfg.runtimePodsTemplateFile, + HostVolumes: cfg.runtimeHostVolumes, + PrivilegedImages: cfg.runtimePrivilegedImages, + }, + // server configuration + Server: &Server{ + // address is mocked below + Secret: "server.secret", + }, + }, + // exec() creates the runtime (including the mocked runtime). + // exec() creates the executor and adds it here. + Executors: make(map[int]executor.Engine), + } + + // setup mock vela server + s := httptest.NewServer(server.FakeHandler()) + w.Config.Server.Address = s.URL + + // setup mock vela worker + api := httptest.NewServer(worker.FakeHandler()) + + w.Config.API.Address, err = url.Parse(api.URL) + if err != nil { + return nil, fmt.Errorf("unable to parse mock address: %w", err) + } + + // set up VelaClient (setup happens in operate()) + w.VelaClient, err = setupClient(w.Config.Server) + if err != nil { + return nil, fmt.Errorf("vela client setup error = %w", err) + } + + // set up mock Redis client (setup happens in operate()) + w.Queue, err = redis.NewTest(cfg.queueRoutes...) + if err != nil { + return nil, fmt.Errorf("queue setup error = %w", err) + } + + return w, nil +} + +var ( + _stages = &pipeline.Build{ + Version: "1", + ID: "github-octocat-1", + Services: pipeline.ContainerSlice{ + { + ID: "service-github-octocat-1-postgres", + Directory: "/vela/src/github.com/octocat/helloworld", + Environment: map[string]string{"FOO": "bar"}, + Image: "postgres:12-alpine", + Name: "postgres", + Number: 4, + Ports: []string{"5432:5432"}, + }, + }, + Stages: pipeline.StageSlice{ + { + Name: "init", + Steps: pipeline.ContainerSlice{ + { + ID: "step-github-octocat-1-init-init", + Directory: "/vela/src/github.com/octocat/helloworld", + Environment: map[string]string{"FOO": "bar"}, + Image: "#init", + Name: "init", + Number: 1, + Pull: "always", + }, + }, + }, + { + Name: "clone", + Needs: []string{"init"}, + Steps: pipeline.ContainerSlice{ + { + ID: "step-github-octocat-1-clone-clone", + Directory: "/vela/src/github.com/octocat/helloworld", + Environment: map[string]string{"FOO": "bar"}, + Image: "target/vela-git:v0.4.0", + Name: "clone", + Number: 2, + Pull: "always", + }, + }, + }, + { + Name: "echo", + Needs: []string{"clone"}, + Steps: pipeline.ContainerSlice{ + { + ID: "step-github-octocat-1-echo-echo", + Commands: []string{"echo hello"}, + Detach: true, + Directory: "/vela/src/github.com/octocat/helloworld", + Environment: map[string]string{"FOO": "bar"}, + Image: "alpine:latest", + Name: "echo", + Number: 3, + Pull: "always", + }, + }, + }, + }, + } + + _steps = &pipeline.Build{ + Version: "1", + ID: "github-octocat-1", + Services: pipeline.ContainerSlice{ + { + ID: "service-github-octocat-1-postgres", + Directory: "/vela/src/github.com/octocat/helloworld", + Environment: map[string]string{"FOO": "bar"}, + Image: "postgres:12-alpine", + Name: "postgres", + Number: 4, + Ports: []string{"5432:5432"}, + }, + }, + Steps: pipeline.ContainerSlice{ + { + ID: "step-github-octocat-1-init", + Directory: "/vela/src/github.com/octocat/helloworld", + Environment: map[string]string{"FOO": "bar"}, + Image: "#init", + Name: "init", + Number: 1, + Pull: "always", + }, + { + ID: "step-github-octocat-1-clone", + Directory: "/vela/src/github.com/octocat/helloworld", + Environment: map[string]string{"FOO": "bar"}, + Image: "target/vela-git:v0.4.0", + Name: "clone", + Number: 2, + Pull: "always", + }, + { + ID: "step-github-octocat-1-echo", + Commands: []string{"echo hello"}, + Detach: true, + Directory: "/vela/src/github.com/octocat/helloworld", + Environment: map[string]string{"FOO": "bar"}, + Image: "alpine:latest", + Name: "echo", + Number: 3, + Pull: "always", + }, + }, + } +) + +// testBuild is a test helper function to create a Build +// type with all fields set to a fake value. +func testBuild(cfg *Config) *library.Build { + return &library.Build{ + ID: vela.Int64(1), + Number: vela.Int(1), + Parent: vela.Int(1), + Event: vela.String("push"), + Status: vela.String("success"), + Error: vela.String(""), + Enqueued: vela.Int64(1563474077), + Created: vela.Int64(1563474076), + Started: vela.Int64(1563474077), + Finished: vela.Int64(0), + Deploy: vela.String(""), + Clone: vela.String("https://github.com/github/octocat.git"), + Source: vela.String("https://github.com/github/octocat/abcdefghi123456789"), + Title: vela.String("push received from https://github.com/github/octocat"), + Message: vela.String("First commit..."), + Commit: vela.String("48afb5bdc41ad69bf22588491333f7cf71135163"), + Sender: vela.String("OctoKitty"), + Author: vela.String("OctoKitty"), + Branch: vela.String("master"), + Ref: vela.String("refs/heads/master"), + BaseRef: vela.String(""), + Host: vela.String(cfg.API.Address.Host), + Runtime: vela.String(cfg.Runtime.Driver), + Distribution: vela.String(cfg.Executor.Driver), + } +} + +// testRepo is a test helper function to create a Repo +// type with all fields set to a fake value. +func testRepo() *library.Repo { + return &library.Repo{ + ID: vela.Int64(1), + Org: vela.String("github"), + Name: vela.String("octocat"), + FullName: vela.String("github/octocat"), + Link: vela.String("https://github.com/github/octocat"), + Clone: vela.String("https://github.com/github/octocat.git"), + Branch: vela.String("master"), + Timeout: vela.Int64(60), + Visibility: vela.String("public"), + Private: vela.Bool(false), + Trusted: vela.Bool(false), + Active: vela.Bool(true), + AllowPull: vela.Bool(false), + AllowPush: vela.Bool(true), + AllowDeploy: vela.Bool(false), + AllowTag: vela.Bool(false), + } +} + +// testUser is a test helper function to create a User +// type with all fields set to a fake value. +func testUser() *library.User { + return &library.User{ + ID: vela.Int64(1), + Name: vela.String("octocat"), + Token: vela.String("superSecretToken"), + Hash: vela.String("MzM4N2MzMDAtNmY4Mi00OTA5LWFhZDAtNWIzMTlkNTJkODMy"), + Favorites: vela.Strings([]string{"github/octocat"}), + Active: vela.Bool(true), + Admin: vela.Bool(false), + } +} diff --git a/mock/worker/build.go b/mock/worker/build.go new file mode 100644 index 000000000..d8e05fc98 --- /dev/null +++ b/mock/worker/build.go @@ -0,0 +1,86 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package worker + +import ( + "encoding/json" + "fmt" + "net/http" + "strings" + + "github.com/gin-gonic/gin" + "github.com/go-vela/types" + "github.com/go-vela/types/library" +) + +const ( + // BuildResp represents a JSON return for a single build. + BuildResp = `{ + "id": 1, + "repo_id": 1, + "number": 1, + "parent": 1, + "event": "push", + "status": "created", + "error": "", + "enqueued": 1563474077, + "created": 1563474076, + "started": 1563474077, + "finished": 0, + "deploy": "", + "clone": "https://github.com/github/octocat.git", + "source": "https://github.com/github/octocat/commit/48afb5bdc41ad69bf22588491333f7cf71135163", + "title": "push received from https://github.com/github/octocat", + "message": "First commit...", + "commit": "48afb5bdc41ad69bf22588491333f7cf71135163", + "sender": "OctoKitty", + "author": "OctoKitty", + "email": "octokitty@github.com", + "link": "https://vela.example.company.com/github/octocat/1", + "branch": "master", + "ref": "refs/heads/master", + "base_ref": "", + "host": "example.company.com", + "runtime": "docker", + "distribution": "linux" +}` +) + +// getBuild has a param :build returns mock JSON for a http GET. +func getBuild(c *gin.Context) { + b := c.Param("build") + + if strings.EqualFold(b, "0") { + msg := fmt.Sprintf("Build %s does not exist", b) + + c.AbortWithStatusJSON(http.StatusNotFound, types.Error{Message: &msg}) + + return + } + + data := []byte(BuildResp) + + var body library.Build + _ = json.Unmarshal(data, &body) + + c.JSON(http.StatusOK, body) +} + +// cancelBuild has a param :build returns mock JSON for a http DELETE. +// +// Pass "0" to :build to test receiving a http 404 response. +func cancelBuild(c *gin.Context) { + b := c.Param("build") + + if strings.EqualFold(b, "0") { + msg := fmt.Sprintf("Build %s does not exist", b) + + c.AbortWithStatusJSON(http.StatusNotFound, types.Error{Message: &msg}) + + return + } + + c.JSON(http.StatusOK, BuildResp) +} diff --git a/mock/worker/doc.go b/mock/worker/doc.go new file mode 100644 index 000000000..281bb5810 --- /dev/null +++ b/mock/worker/doc.go @@ -0,0 +1,10 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +// Package worker provides a mock for using the Worker API. +// +// Usage: +// +// import "github.com/go-vela/worker/mock/worker" +package worker diff --git a/mock/worker/executor.go b/mock/worker/executor.go new file mode 100644 index 000000000..f9af3c47e --- /dev/null +++ b/mock/worker/executor.go @@ -0,0 +1,63 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package worker + +import ( + "encoding/json" + "fmt" + "net/http" + "strings" + + "github.com/gin-gonic/gin" + "github.com/go-vela/types" + "github.com/go-vela/types/library" +) + +const ( + // ExecutorResp represents a JSON return for a single worker. + ExecutorResp = ` + { + "id": 1, + "host": "worker_1", + "runtime": "docker", + "distribution": "linux", + "build": ` + BuildResp + `, + "pipeline": ` + PipelineResp + `, + "repo": ` + RepoResp + ` + }` + + // ExecutorsResp represents a JSON return for one to many workers. + ExecutorsResp = `[ ` + ExecutorResp + `,` + ExecutorResp + `]` +) + +// getExecutors returns mock JSON for a http GET. +func getExecutors(c *gin.Context) { + data := []byte(ExecutorsResp) + + var body []library.Executor + _ = json.Unmarshal(data, &body) + + c.JSON(http.StatusOK, body) +} + +// getExecutor has a param :executor returns mock JSON for a http GET. +func getExecutor(c *gin.Context) { + w := c.Param("executor") + + if strings.EqualFold(w, "0") { + msg := fmt.Sprintf("Executor %s does not exist", w) + + c.AbortWithStatusJSON(http.StatusNotFound, types.Error{Message: &msg}) + + return + } + + data := []byte(ExecutorResp) + + var body library.Executor + _ = json.Unmarshal(data, &body) + + c.JSON(http.StatusOK, body) +} diff --git a/mock/worker/pipeline.go b/mock/worker/pipeline.go new file mode 100644 index 000000000..9184615d6 --- /dev/null +++ b/mock/worker/pipeline.go @@ -0,0 +1,60 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package worker + +import ( + "encoding/json" + "fmt" + "net/http" + "strings" + + "github.com/go-vela/types/library" + + "github.com/gin-gonic/gin" + "github.com/go-vela/types" +) + +const ( + // PipelineResp represents a JSON return for a single pipeline. + PipelineResp = `{ + "id": 1, + "repo_id": 1, + "commit": "48afb5bdc41ad69bf22588491333f7cf71135163", + "flavor": "", + "platform": "", + "ref": "refs/heads/master", + "type": "yaml", + "version": "1", + "external_secrets": false, + "internal_secrets": false, + "services": false, + "stages": false, + "steps": true, + "templates": false, + "data": "LS0tCnZlcnNpb246ICIxIgoKc3RlcHM6CiAgLSBuYW1lOiBlY2hvCiAgICBpbWFnZTogYWxwaW5lOmxhdGVzdAogICAgY29tbWFuZHM6IFtlY2hvIGZvb10=" +}` +) + +// getPipeline has a param :pipeline returns mock YAML for a http GET. +// +// Pass "0" to :pipeline to test receiving a http 404 response. +func getPipeline(c *gin.Context) { + p := c.Param("pipeline") + + if strings.EqualFold(p, "0") { + msg := fmt.Sprintf("Pipeline %s does not exist", p) + + c.AbortWithStatusJSON(http.StatusNotFound, types.Error{Message: &msg}) + + return + } + + data := []byte(PipelineResp) + + var body library.Pipeline + _ = json.Unmarshal(data, &body) + + c.JSON(http.StatusOK, body) +} diff --git a/mock/worker/repo.go b/mock/worker/repo.go new file mode 100644 index 000000000..da6d1d479 --- /dev/null +++ b/mock/worker/repo.go @@ -0,0 +1,62 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package worker + +import ( + "encoding/json" + "fmt" + "net/http" + "strings" + + "github.com/gin-gonic/gin" + "github.com/go-vela/types" + "github.com/go-vela/types/library" +) + +const ( + // RepoResp represents a JSON return for a single repo. + RepoResp = `{ + "id": 1, + "user_id": 1, + "org": "github", + "name": "octocat", + "full_name": "github/octocat", + "link": "https://github.com/github/octocat", + "clone": "https://github.com/github/octocat", + "branch": "master", + "build_limit": 10, + "timeout": 60, + "visibility": "public", + "private": false, + "trusted": true, + "active": true, + "allow_pr": false, + "allow_push": true, + "allow_deploy": false, + "allow_tag": false +}` +) + +// getRepo has a param :repo returns mock JSON for a http GET. +// +// Pass "not-found" to :repo to test receiving a http 404 response. +func getRepo(c *gin.Context) { + r := c.Param("repo") + + if strings.Contains(r, "not-found") { + msg := fmt.Sprintf("Repo %s does not exist", r) + + c.AbortWithStatusJSON(http.StatusNotFound, types.Error{Message: &msg}) + + return + } + + data := []byte(RepoResp) + + var body library.Repo + _ = json.Unmarshal(data, &body) + + c.JSON(http.StatusOK, body) +} diff --git a/mock/worker/server.go b/mock/worker/server.go new file mode 100644 index 000000000..95011fe33 --- /dev/null +++ b/mock/worker/server.go @@ -0,0 +1,41 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package worker + +import ( + "net/http" + + "github.com/gin-gonic/gin" +) + +// FakeHandler returns an http.Handler that is capable of handling +// Vela API requests and returning mock responses. +func FakeHandler() http.Handler { + gin.SetMode(gin.TestMode) + + e := gin.New() + + // mock endpoints for utility calls + //e.GET("/health", getHealth) + //e.GET("/metrics", getMetrics) + //e.GET("/version", getVersion) + //e.POST("/api/v1/shutdown", postShutdown) + + // mock endpoints for executor calls + e.GET("/api/v1/executors", getExecutors) + e.GET("/api/v1/executors/:executor", getExecutor) + + // mock endpoints for build calls + e.GET("/api/v1/executors/:executor/build", getBuild) + e.DELETE("/api/v1/executors/:executor/build/cancel", cancelBuild) + + // mock endpoints for pipeline calls + e.GET("/api/v1/executors/:executor/pipeline", getPipeline) + + // mock endpoints for repo calls + e.GET("/api/v1/executors/:executor/repo", getRepo) + + return e +} diff --git a/runtime/setup.go b/runtime/setup.go index 3a88c75ac..7207f39c7 100644 --- a/runtime/setup.go +++ b/runtime/setup.go @@ -13,6 +13,7 @@ import ( "github.com/go-vela/types/constants" "github.com/sirupsen/logrus" + v1 "k8s.io/api/core/v1" ) // Setup represents the configuration necessary for @@ -24,6 +25,9 @@ type Setup struct { // Runtime Configuration + // Mock should only be true for tests. + Mock bool + // specifies the driver to use for the runtime client Driver string // specifies the path to a configuration file to use for the runtime client @@ -45,14 +49,23 @@ type Setup struct { func (s *Setup) Docker() (Engine, error) { logrus.Trace("creating docker runtime client from setup") - // create new Docker runtime engine - // - // https://pkg.go.dev/github.com/go-vela/worker/runtime/docker?tab=doc#New - return docker.New( + opts := []docker.ClientOpt{ docker.WithHostVolumes(s.HostVolumes), docker.WithPrivilegedImages(s.PrivilegedImages), docker.WithLogger(s.Logger), - ) + } + + if s.Mock { + // create new mock Docker runtime engine + // + // https://pkg.go.dev/github.com/go-vela/worker/runtime/docker?tab=doc#NewMock + return docker.NewMock(opts...) + } + + // create new Docker runtime engine + // + // https://pkg.go.dev/github.com/go-vela/worker/runtime/docker?tab=doc#New + return docker.New(opts...) } // Kubernetes creates and returns a Vela engine capable of @@ -60,17 +73,26 @@ func (s *Setup) Docker() (Engine, error) { func (s *Setup) Kubernetes() (Engine, error) { logrus.Trace("creating kubernetes runtime client from setup") - // create new Kubernetes runtime engine - // - // https://pkg.go.dev/github.com/go-vela/worker/runtime/kubernetes?tab=doc#New - return kubernetes.New( + opts := []kubernetes.ClientOpt{ kubernetes.WithConfigFile(s.ConfigFile), kubernetes.WithHostVolumes(s.HostVolumes), kubernetes.WithNamespace(s.Namespace), kubernetes.WithPodsTemplate(s.PodsTemplateName, s.PodsTemplateFile), kubernetes.WithPrivilegedImages(s.PrivilegedImages), kubernetes.WithLogger(s.Logger), - ) + } + + if s.Mock { + // create new mock Kubernetes runtime engine + // + // https://pkg.go.dev/github.com/go-vela/worker/runtime/kubernetes?tab=doc#NewMock + return kubernetes.NewMock(&v1.Pod{}, opts...) + } + + // create new Kubernetes runtime engine + // + // https://pkg.go.dev/github.com/go-vela/worker/runtime/kubernetes?tab=doc#New + return kubernetes.New(opts...) } // Validate verifies the necessary fields for the