Skip to content

Commit

Permalink
ImageRunner: Add support for workflow type (#744)
Browse files Browse the repository at this point in the history
* Add support for workflow type
  • Loading branch information
FriggaHel authored Apr 18, 2023
1 parent 6e30210 commit 33b9b82
Show file tree
Hide file tree
Showing 10 changed files with 227 additions and 15 deletions.
1 change: 1 addition & 0 deletions .sauce/imagerunner.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ sauce:
suites:
- name: busybox num 1 # Describe your configuration
image: busybox:1.35.0 # Name of the container image
workload: other # Kind of workload
imagePullAuth: # Credentials used to pull the container image
user: $DOCKER_USERNAME
token: $DOCKER_PASSWORD
Expand Down
10 changes: 9 additions & 1 deletion api/saucectl.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -2742,10 +2742,18 @@
"10m",
"90s"
]
},
"workload": {
"description": "Sets the kind of workload that is being executed",
"enum": [
"webdriver",
"other"
]
}
},
"required": [
"name"
"name",
"workload"
]
}
},
Expand Down
10 changes: 9 additions & 1 deletion api/v1alpha/framework/imagerunner.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,18 @@
},
"timeout": {
"$ref": "../subschema/common.schema.json#/definitions/timeout"
},
"workload": {
"description": "Sets the kind of workload that is being executed",
"enum": [
"webdriver",
"other"
]
}
},
"required": [
"name"
"name",
"workload"
]
}
},
Expand Down
4 changes: 4 additions & 0 deletions internal/cmd/run/imagerunner.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ func runImageRunner(cmd *cobra.Command) (int, error) {
if err != nil {
return 1, err
}
imagerunner.SetDefaults(&p)
if err := imagerunner.Validate(p); err != nil {
return 1, err
}

regio := region.FromString(p.Sauce.Region)
imageRunnerClient.URL = regio.APIBaseURL()
Expand Down
2 changes: 1 addition & 1 deletion internal/espresso/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ func TestValidateThrowsErrors(t *testing.T) {
},
},
},
expectedErr: errors.New("missing `emulator` in emulator name: Android GoogleApi something. Suite name: no emulator device name. Emulators index: 0"),
expectedErr: errors.New(`missing "emulator" in emulator name: Android GoogleApi something. Suite name: no emulator device name. Emulators index: 0`),
},
{
name: "validating throws error on missing platform versions",
Expand Down
77 changes: 77 additions & 0 deletions internal/imagerunner/config.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
package imagerunner

import (
"errors"
"fmt"
"time"

"github.com/saucelabs/saucectl/internal/config"
"github.com/saucelabs/saucectl/internal/msg"
"github.com/saucelabs/saucectl/internal/region"
)

var (
Kind = "imagerunner"
APIVersion = "v1alpha"

ValidWorkloadType = []string{
"webdriver",
"other",
}
)

type Project struct {
Expand All @@ -32,6 +41,7 @@ type Suite struct {
Artifacts []string `yaml:"artifacts,omitempty" json:"artifacts"`
Env map[string]string `yaml:"env,omitempty" json:"env"`
Timeout time.Duration `yaml:"timeout,omitempty" json:"timeout"`
Workload string `yaml:"workload,omitempty" json:"workload,omitempty"`
}

type ImagePullAuth struct {
Expand All @@ -53,3 +63,70 @@ func FromFile(cfgPath string) (Project, error) {

return p, nil
}

// SetDefaults applies config defaults in case the user has left them blank.
func SetDefaults(p *Project) {
if p.Kind == "" {
p.Kind = Kind
}

if p.APIVersion == "" {
p.APIVersion = APIVersion
}

if p.Sauce.Concurrency < 1 {
p.Sauce.Concurrency = 2
}

if p.Defaults.Timeout < 0 {
p.Defaults.Timeout = 0
}

p.Sauce.Tunnel.SetDefaults()
p.Sauce.Metadata.SetDefaultBuild()

for i, suite := range p.Suites {
if suite.Timeout <= 0 {
p.Suites[i].Timeout = p.Defaults.Timeout
}

if suite.Workload == "" {
p.Suites[i].Workload = p.Defaults.Workload
}
}
}

func Validate(p Project) error {
regio := region.FromString(p.Sauce.Region)
if regio == region.None {
return errors.New(msg.MissingRegion)
}

if len(p.Suites) == 0 {
return errors.New(msg.EmptySuite)
}

for _, suite := range p.Suites {
if suite.Workload == "" {
return fmt.Errorf(msg.MissingImageRunnerWorkloadType, suite.Name)
}

if !sliceContainsString(ValidWorkloadType, suite.Workload) {
return fmt.Errorf(msg.InvalidImageRunnerWorkloadType, suite.Workload, suite.Name)
}

if suite.Image == "" {
return fmt.Errorf(msg.MissingImageRunnerImage, suite.Name)
}
}
return nil
}

func sliceContainsString(slice []string, val string) bool {
for _, value := range slice {
if value == val {
return true
}
}
return false
}
102 changes: 102 additions & 0 deletions internal/imagerunner/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package imagerunner

import (
"testing"

"github.com/saucelabs/saucectl/internal/config"
"github.com/saucelabs/saucectl/internal/region"
)

func TestValidate(t *testing.T) {
type args struct {
p Project
}
tests := []struct {
name string
args args
wantErr string
}{
{
name: "Passing",
args: args{
p: Project{
Sauce: config.SauceConfig{
Region: region.USWest1.String(),
},
Suites: []Suite{
{
Name: "Main Suite",
Workload: "other",
Image: "dummy/image",
},
},
},
},
wantErr: "",
},
{
name: "No Image",
args: args{
p: Project{
Sauce: config.SauceConfig{
Region: region.USWest1.String(),
},
Suites: []Suite{
{
Name: "Main Suite",
Workload: "other",
},
},
},
},
wantErr: `missing "image" for suite: Main Suite`,
},
{
name: "No Workload Type",
args: args{
p: Project{
Sauce: config.SauceConfig{
Region: region.USWest1.String(),
},
Suites: []Suite{
{
Name: "Main Suite",
Image: "dummy/image",
},
},
},
},
wantErr: `missing "workload" value for suite: Main Suite`,
},
{
name: "Invalid Workload Type",
args: args{
p: Project{
Sauce: config.SauceConfig{
Region: region.USWest1.String(),
},
Suites: []Suite{
{
Name: "Main Suite",
Image: "dummy/image",
Workload: "invalid-workload-type",
},
},
},
},
wantErr: `"invalid-workload-type" is an invalid "workload" value for suite: Main Suite`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := Validate(tt.args.p)
errStr := ""
if err != nil {
errStr = err.Error()
}
if errStr != tt.wantErr {
t.Errorf("Validate() error = %v, wantErr %v", errStr, tt.wantErr)
}
})
}
}
13 changes: 7 additions & 6 deletions internal/imagerunner/imagerunner.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,13 @@ func Done(status string) bool {
var ErrResourceNotFound = errors.New("resource not found")

type RunnerSpec struct {
Container Container `json:"container,omitempty"`
EntryPoint string `json:"entrypoint,omitempty"`
Env []EnvItem `json:"env,omitempty"`
Files []FileData `json:"files,omitempty"`
Metadata map[string]string `json:"metadata,omitempty"`
Artifacts []string `json:"artifacts,omitempty"`
Container Container `json:"container,omitempty"`
EntryPoint string `json:"entrypoint,omitempty"`
Env []EnvItem `json:"env,omitempty"`
Files []FileData `json:"files,omitempty"`
Metadata map[string]string `json:"metadata,omitempty"`
Artifacts []string `json:"artifacts,omitempty"`
WorkloadType string `json:"workloadType,omitempty"`
}

type Container struct {
Expand Down
12 changes: 11 additions & 1 deletion internal/msg/errormsg.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,11 +155,21 @@ const (
// MissingEmulatorName indicates empty emulator name
MissingEmulatorName = "missing emulator name for suite: %s. Emulators index: %d"
// InvalidEmulatorName indicates invalid emulator name
InvalidEmulatorName = "missing `emulator` in emulator name: %s. Suite name: %s. Emulators index: %d"
InvalidEmulatorName = `missing "emulator" in emulator name: %s. Suite name: %s. Emulators index: %d`
// MissingEmulatorPlatformVersion indicates no emulator platform version provided
MissingEmulatorPlatformVersion = "missing platform versions for emulator: %s. Suite name: %s. Emulators index: %d"
)

// ImageRunner config settings
const (
// MissingImageRunnerWorkloadType indicates no workload type provided
MissingImageRunnerWorkloadType = `missing "workload" value for suite: %s`
// InvalidImageRunnerWorkloadType indicates invalid workload type provided
InvalidImageRunnerWorkloadType = `%q is an invalid "workload" value for suite: %s`
// MissingImageRunnerImage indicates no docker image provided
MissingImageRunnerImage = `missing "image" for suite: %s`
)

// testcafe config settings
const (
// InvalidTestCafeDeviceSetting indicates the unsupported device keyword in the config
Expand Down
11 changes: 6 additions & 5 deletions internal/saucecloud/imagerunner.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,11 +181,12 @@ func (r *ImgRunner) runSuite(suite imagerunner.Suite) (imagerunner.Runner, error
Name: suite.Image,
Auth: auth,
},
EntryPoint: suite.EntryPoint,
Env: mapEnv(suite.Env),
Files: files,
Artifacts: suite.Artifacts,
Metadata: metadata,
EntryPoint: suite.EntryPoint,
Env: mapEnv(suite.Env),
Files: files,
Artifacts: suite.Artifacts,
Metadata: metadata,
WorkloadType: suite.Workload,
})
if errors.Is(err, context.DeadlineExceeded) && ctx.Err() != nil {
run.Status = imagerunner.StateCancelled
Expand Down

0 comments on commit 33b9b82

Please sign in to comment.