mirror of
https://github.com/redhat-developer/odo.git
synced 2025-10-19 03:06:19 +03:00
1814 lines
52 KiB
Go
1814 lines
52 KiB
Go
package libdevfile
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
|
|
devfilepkg "github.com/devfile/api/v2/pkg/devfile"
|
|
"github.com/devfile/library/pkg/devfile/parser"
|
|
"github.com/devfile/library/pkg/devfile/parser/data"
|
|
devfileFileSystem "github.com/devfile/library/pkg/testingutil/filesystem"
|
|
dfutil "github.com/devfile/library/pkg/util"
|
|
"github.com/golang/mock/gomock"
|
|
"github.com/google/go-cmp/cmp"
|
|
"k8s.io/utils/pointer"
|
|
|
|
"github.com/redhat-developer/odo/pkg/libdevfile/generator"
|
|
"github.com/redhat-developer/odo/pkg/testingutil"
|
|
"github.com/redhat-developer/odo/pkg/util"
|
|
)
|
|
|
|
var buildGroup = v1alpha2.BuildCommandGroupKind
|
|
var runGroup = v1alpha2.RunCommandGroupKind
|
|
|
|
func TestGetCommand(t *testing.T) {
|
|
|
|
commands := [...]string{"ls -la", "pwd"}
|
|
components := [...]string{"alias1", "alias2"}
|
|
|
|
tests := []struct {
|
|
name string
|
|
requestedType []v1alpha2.CommandGroupKind
|
|
execCommands []v1alpha2.Command
|
|
compCommands []v1alpha2.Command
|
|
reqCommandName string
|
|
retCommandName string
|
|
wantErr bool
|
|
wantPresent bool
|
|
}{
|
|
{
|
|
name: "Case 1: Valid devfile",
|
|
execCommands: []v1alpha2.Command{
|
|
getExecCommand("build", buildGroup),
|
|
getExecCommand("run", runGroup),
|
|
},
|
|
requestedType: []v1alpha2.CommandGroupKind{buildGroup, runGroup},
|
|
wantErr: false,
|
|
wantPresent: true,
|
|
},
|
|
{
|
|
name: "Case 2: Valid devfile with devrun and devbuild",
|
|
execCommands: []v1alpha2.Command{
|
|
getExecCommand("build", buildGroup),
|
|
getExecCommand("run", runGroup),
|
|
},
|
|
requestedType: []v1alpha2.CommandGroupKind{buildGroup, runGroup},
|
|
wantErr: false,
|
|
wantPresent: true,
|
|
},
|
|
{
|
|
name: "Case 3: Valid devfile with empty workdir",
|
|
execCommands: []v1alpha2.Command{
|
|
{
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Exec: &v1alpha2.ExecCommand{
|
|
LabeledCommand: v1alpha2.LabeledCommand{
|
|
BaseCommand: v1alpha2.BaseCommand{
|
|
Group: &v1alpha2.CommandGroup{Kind: runGroup},
|
|
},
|
|
},
|
|
CommandLine: commands[0],
|
|
Component: components[0],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
requestedType: []v1alpha2.CommandGroupKind{runGroup},
|
|
wantErr: false,
|
|
wantPresent: true,
|
|
},
|
|
{
|
|
name: "Case 4.1: Mismatched command type",
|
|
execCommands: []v1alpha2.Command{
|
|
{
|
|
Id: "build command",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Exec: &v1alpha2.ExecCommand{
|
|
LabeledCommand: v1alpha2.LabeledCommand{
|
|
BaseCommand: v1alpha2.BaseCommand{
|
|
Group: &v1alpha2.CommandGroup{Kind: runGroup},
|
|
},
|
|
},
|
|
CommandLine: commands[0],
|
|
Component: components[0],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
reqCommandName: "build command",
|
|
requestedType: []v1alpha2.CommandGroupKind{buildGroup},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "Case 4.2: Matching command by name and type",
|
|
execCommands: []v1alpha2.Command{
|
|
{
|
|
Id: "build command",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Exec: &v1alpha2.ExecCommand{
|
|
LabeledCommand: v1alpha2.LabeledCommand{
|
|
BaseCommand: v1alpha2.BaseCommand{
|
|
Group: &v1alpha2.CommandGroup{Kind: buildGroup},
|
|
},
|
|
},
|
|
CommandLine: commands[0],
|
|
Component: components[0],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
reqCommandName: "build command",
|
|
requestedType: []v1alpha2.CommandGroupKind{buildGroup},
|
|
wantErr: false,
|
|
wantPresent: true,
|
|
},
|
|
{
|
|
name: "Case 5: Default command is returned",
|
|
execCommands: []v1alpha2.Command{
|
|
{
|
|
Id: "defaultRunCommand",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Exec: &v1alpha2.ExecCommand{
|
|
LabeledCommand: v1alpha2.LabeledCommand{
|
|
BaseCommand: v1alpha2.BaseCommand{
|
|
Group: &v1alpha2.CommandGroup{Kind: runGroup, IsDefault: util.GetBoolPtr(true)},
|
|
},
|
|
},
|
|
CommandLine: commands[0],
|
|
Component: components[0],
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Id: "runCommand",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Exec: &v1alpha2.ExecCommand{
|
|
LabeledCommand: v1alpha2.LabeledCommand{
|
|
BaseCommand: v1alpha2.BaseCommand{
|
|
Group: &v1alpha2.CommandGroup{Kind: runGroup},
|
|
},
|
|
},
|
|
CommandLine: commands[0],
|
|
Component: components[0],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
retCommandName: "defaultRunCommand",
|
|
requestedType: []v1alpha2.CommandGroupKind{runGroup},
|
|
wantErr: false,
|
|
wantPresent: true,
|
|
},
|
|
{
|
|
name: "Case 5.1: if only one command is present, it is returned and assumed as default",
|
|
execCommands: []v1alpha2.Command{
|
|
{
|
|
Id: "defaultRunCommand",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Exec: &v1alpha2.ExecCommand{
|
|
LabeledCommand: v1alpha2.LabeledCommand{
|
|
BaseCommand: v1alpha2.BaseCommand{
|
|
Group: &v1alpha2.CommandGroup{Kind: runGroup},
|
|
},
|
|
},
|
|
CommandLine: commands[0],
|
|
Component: components[0],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
retCommandName: "defaultRunCommand",
|
|
requestedType: []v1alpha2.CommandGroupKind{runGroup},
|
|
wantErr: false,
|
|
wantPresent: true,
|
|
},
|
|
{
|
|
name: "Case 5.2: if multiple default commands are present, error is returned",
|
|
execCommands: []v1alpha2.Command{
|
|
{
|
|
Id: "runCommand1",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Exec: &v1alpha2.ExecCommand{
|
|
LabeledCommand: v1alpha2.LabeledCommand{
|
|
BaseCommand: v1alpha2.BaseCommand{
|
|
Group: &v1alpha2.CommandGroup{Kind: runGroup, IsDefault: util.GetBoolPtr(true)},
|
|
},
|
|
},
|
|
CommandLine: commands[0],
|
|
Component: components[0],
|
|
},
|
|
},
|
|
}, {
|
|
Id: "runCommand2",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Exec: &v1alpha2.ExecCommand{
|
|
LabeledCommand: v1alpha2.LabeledCommand{
|
|
BaseCommand: v1alpha2.BaseCommand{
|
|
Group: &v1alpha2.CommandGroup{Kind: runGroup, IsDefault: util.GetBoolPtr(true)},
|
|
},
|
|
},
|
|
CommandLine: commands[0],
|
|
Component: components[0],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
requestedType: []v1alpha2.CommandGroupKind{runGroup},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "Case 5.2: if multiple default commands are present, error is returned",
|
|
execCommands: []v1alpha2.Command{
|
|
{
|
|
Id: "runCommand1",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Exec: &v1alpha2.ExecCommand{
|
|
LabeledCommand: v1alpha2.LabeledCommand{
|
|
BaseCommand: v1alpha2.BaseCommand{
|
|
Group: &v1alpha2.CommandGroup{Kind: runGroup, IsDefault: util.GetBoolPtr(true)},
|
|
},
|
|
},
|
|
CommandLine: commands[0],
|
|
Component: components[0],
|
|
},
|
|
},
|
|
}, {
|
|
Id: "runCommand2",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Exec: &v1alpha2.ExecCommand{
|
|
LabeledCommand: v1alpha2.LabeledCommand{
|
|
BaseCommand: v1alpha2.BaseCommand{
|
|
Group: &v1alpha2.CommandGroup{Kind: runGroup, IsDefault: util.GetBoolPtr(true)},
|
|
},
|
|
},
|
|
CommandLine: commands[0],
|
|
Component: components[0],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
requestedType: []v1alpha2.CommandGroupKind{runGroup},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "Case 6: Composite command is returned",
|
|
execCommands: []v1alpha2.Command{
|
|
{
|
|
Id: "build",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Exec: &v1alpha2.ExecCommand{
|
|
LabeledCommand: v1alpha2.LabeledCommand{
|
|
BaseCommand: v1alpha2.BaseCommand{
|
|
Group: &v1alpha2.CommandGroup{Kind: buildGroup, IsDefault: util.GetBoolPtr(false)},
|
|
},
|
|
},
|
|
CommandLine: commands[0],
|
|
Component: components[0],
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Id: "run",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Exec: &v1alpha2.ExecCommand{
|
|
LabeledCommand: v1alpha2.LabeledCommand{
|
|
BaseCommand: v1alpha2.BaseCommand{
|
|
Group: &v1alpha2.CommandGroup{Kind: runGroup},
|
|
},
|
|
},
|
|
CommandLine: commands[0],
|
|
Component: components[0],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
compCommands: []v1alpha2.Command{
|
|
{
|
|
Id: "myComposite",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Composite: &v1alpha2.CompositeCommand{
|
|
LabeledCommand: v1alpha2.LabeledCommand{
|
|
BaseCommand: v1alpha2.BaseCommand{
|
|
Group: &v1alpha2.CommandGroup{Kind: buildGroup, IsDefault: util.GetBoolPtr(true)},
|
|
},
|
|
},
|
|
Commands: []string{"build", "run"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
retCommandName: "myComposite",
|
|
requestedType: []v1alpha2.CommandGroupKind{buildGroup},
|
|
wantErr: false,
|
|
wantPresent: true,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
components := []v1alpha2.Component{testingutil.GetFakeContainerComponent(tt.execCommands[0].Exec.Component)}
|
|
devObj := parser.DevfileObj{
|
|
Data: func() data.DevfileData {
|
|
devfileData, err := data.NewDevfileData(string(data.APISchemaVersion200))
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
err = devfileData.AddCommands(tt.execCommands)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
err = devfileData.AddCommands(tt.compCommands)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
err = devfileData.AddComponents(components)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
return devfileData
|
|
}(),
|
|
}
|
|
|
|
for _, gtype := range tt.requestedType {
|
|
cmd, ok, err := GetCommand(devObj, tt.reqCommandName, gtype)
|
|
if tt.wantErr != (err != nil) {
|
|
t.Errorf("TestGetCommand unexpected error for command: %v wantErr: %v err: %v", gtype, tt.wantErr, err)
|
|
return
|
|
} else if tt.wantErr {
|
|
return
|
|
}
|
|
if tt.wantPresent != ok {
|
|
t.Errorf("TestGetCommand unexpected presence for command: %v wantPresent: %v ok: %v", gtype, tt.wantPresent, ok)
|
|
return
|
|
}
|
|
|
|
if len(tt.retCommandName) > 0 && cmd.Id != tt.retCommandName {
|
|
t.Errorf("TestGetCommand error: command names do not match expected: %v actual: %v", tt.retCommandName, cmd.Id)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
}
|
|
|
|
func TestDeploy(t *testing.T) {
|
|
deployDefault1 := generator.GetCompositeCommand(generator.CompositeCommandParams{
|
|
Kind: v1alpha2.DeployCommandGroupKind,
|
|
Id: "deploy-default-1",
|
|
IsDefault: pointer.BoolPtr(true),
|
|
Commands: []string{"image-command", "deployment-command", "service-command"},
|
|
})
|
|
applyImageCommand := generator.GetApplyCommand(generator.ApplyCommandParams{
|
|
Kind: v1alpha2.DeployCommandGroupKind,
|
|
Id: "image-command",
|
|
IsDefault: pointer.BoolPtr(false),
|
|
Component: "image-component",
|
|
})
|
|
applyDeploymentCommand := generator.GetApplyCommand(generator.ApplyCommandParams{
|
|
Kind: v1alpha2.DeployCommandGroupKind,
|
|
Id: "deployment-command",
|
|
IsDefault: pointer.BoolPtr(false),
|
|
Component: "deployment-component",
|
|
})
|
|
applyServiceCommand := generator.GetApplyCommand(generator.ApplyCommandParams{
|
|
Kind: v1alpha2.DeployCommandGroupKind,
|
|
Id: "service-command",
|
|
IsDefault: pointer.BoolPtr(false),
|
|
Component: "service-component",
|
|
})
|
|
|
|
imageComponent := generator.GetImageComponent(generator.ImageComponentParams{
|
|
Name: "image-component",
|
|
Image: v1alpha2.Image{
|
|
ImageName: "an-image-name",
|
|
},
|
|
})
|
|
deploymentComponent := generator.GetKubernetesComponent(generator.KubernetesComponentParams{
|
|
Name: "deployment-component",
|
|
Kubernetes: &v1alpha2.KubernetesComponent{},
|
|
})
|
|
serviceComponent := generator.GetKubernetesComponent(generator.KubernetesComponentParams{
|
|
Name: "service-component",
|
|
Kubernetes: &v1alpha2.KubernetesComponent{},
|
|
})
|
|
|
|
type args struct {
|
|
devfileObj func() parser.DevfileObj
|
|
handler func(ctrl *gomock.Controller) Handler
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "deploy an image and two kubernetes components",
|
|
args: args{
|
|
devfileObj: func() parser.DevfileObj {
|
|
dData, _ := data.NewDevfileData(string(data.APISchemaVersion200))
|
|
_ = dData.AddCommands([]v1alpha2.Command{deployDefault1, applyImageCommand, applyDeploymentCommand, applyServiceCommand})
|
|
_ = dData.AddComponents([]v1alpha2.Component{imageComponent, deploymentComponent, serviceComponent})
|
|
return parser.DevfileObj{
|
|
Data: dData,
|
|
}
|
|
},
|
|
handler: func(ctrl *gomock.Controller) Handler {
|
|
h := NewMockHandler(ctrl)
|
|
h.EXPECT().ApplyImage(imageComponent)
|
|
h.EXPECT().ApplyKubernetes(deploymentComponent)
|
|
h.EXPECT().ApplyKubernetes(serviceComponent)
|
|
return h
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "deploy with multiple deploy and no default",
|
|
args: args{
|
|
devfileObj: func() parser.DevfileObj {
|
|
dData, _ := data.NewDevfileData(string(data.APISchemaVersion200))
|
|
_ = dData.AddCommands([]v1alpha2.Command{applyServiceCommand, applyDeploymentCommand})
|
|
_ = dData.AddComponents([]v1alpha2.Component{deploymentComponent, serviceComponent})
|
|
return parser.DevfileObj{
|
|
Data: dData,
|
|
}
|
|
},
|
|
handler: func(ctrl *gomock.Controller) Handler {
|
|
return NewMockHandler(ctrl)
|
|
},
|
|
},
|
|
wantErr: true,
|
|
},
|
|
// TODO: Add test cases.
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
ctrl := gomock.NewController(t)
|
|
if err := Deploy(tt.args.devfileObj(), tt.args.handler(ctrl)); (err != nil) != tt.wantErr {
|
|
t.Errorf("Deploy() error = %v, wantErr %v", err, tt.wantErr)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestBuild(t *testing.T) {
|
|
containerComp := v1alpha2.Component{
|
|
Name: "my-container",
|
|
ComponentUnion: v1alpha2.ComponentUnion{
|
|
Container: &v1alpha2.ContainerComponent{
|
|
Container: v1alpha2.Container{
|
|
Image: "my-image",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
defaultBuildCommand := generator.GetExecCommand(generator.ExecCommandParams{
|
|
Kind: v1alpha2.BuildCommandGroupKind,
|
|
Id: "my-default-build-command",
|
|
IsDefault: pointer.BoolPtr(true),
|
|
CommandLine: "build my-app",
|
|
Component: containerComp.Name,
|
|
})
|
|
nonDefaultBuildCommandExplicit := generator.GetExecCommand(generator.ExecCommandParams{
|
|
Kind: v1alpha2.BuildCommandGroupKind,
|
|
Id: "my-explicit-non-default-build-command",
|
|
IsDefault: pointer.BoolPtr(false),
|
|
CommandLine: "build my-app",
|
|
Component: containerComp.Name,
|
|
})
|
|
nonDefaultBuildCommandImplicit := generator.GetExecCommand(generator.ExecCommandParams{
|
|
Kind: v1alpha2.BuildCommandGroupKind,
|
|
Id: "my-implicit-non-default-build-command",
|
|
CommandLine: "build my-app",
|
|
Component: containerComp.Name,
|
|
})
|
|
type args struct {
|
|
devfileObj func() parser.DevfileObj
|
|
handler func(ctrl *gomock.Controller) Handler
|
|
cmdName string
|
|
}
|
|
for _, tt := range []struct {
|
|
name string
|
|
args args
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "missing default command",
|
|
args: args{
|
|
devfileObj: func() parser.DevfileObj {
|
|
dData, _ := data.NewDevfileData(string(data.APISchemaVersion200))
|
|
_ = dData.AddCommands([]v1alpha2.Command{nonDefaultBuildCommandExplicit, nonDefaultBuildCommandImplicit})
|
|
_ = dData.AddComponents([]v1alpha2.Component{containerComp})
|
|
return parser.DevfileObj{
|
|
Data: dData,
|
|
}
|
|
},
|
|
handler: func(ctrl *gomock.Controller) Handler {
|
|
h := NewMockHandler(ctrl)
|
|
h.EXPECT().Execute(gomock.Eq(defaultBuildCommand)).Times(0)
|
|
h.EXPECT().Execute(gomock.Eq(nonDefaultBuildCommandExplicit)).Times(0)
|
|
h.EXPECT().Execute(gomock.Eq(nonDefaultBuildCommandImplicit)).Times(0)
|
|
return h
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "with default command",
|
|
args: args{
|
|
devfileObj: func() parser.DevfileObj {
|
|
dData, _ := data.NewDevfileData(string(data.APISchemaVersion200))
|
|
_ = dData.AddCommands([]v1alpha2.Command{defaultBuildCommand, nonDefaultBuildCommandExplicit, nonDefaultBuildCommandImplicit})
|
|
_ = dData.AddComponents([]v1alpha2.Component{containerComp})
|
|
return parser.DevfileObj{
|
|
Data: dData,
|
|
}
|
|
},
|
|
handler: func(ctrl *gomock.Controller) Handler {
|
|
h := NewMockHandler(ctrl)
|
|
h.EXPECT().Execute(gomock.Eq(defaultBuildCommand)).Times(1)
|
|
h.EXPECT().Execute(gomock.Eq(nonDefaultBuildCommandExplicit)).Times(0)
|
|
h.EXPECT().Execute(gomock.Eq(nonDefaultBuildCommandImplicit)).Times(0)
|
|
return h
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "missing custom command",
|
|
args: args{
|
|
devfileObj: func() parser.DevfileObj {
|
|
dData, _ := data.NewDevfileData(string(data.APISchemaVersion200))
|
|
_ = dData.AddCommands([]v1alpha2.Command{defaultBuildCommand})
|
|
_ = dData.AddComponents([]v1alpha2.Component{containerComp})
|
|
return parser.DevfileObj{
|
|
Data: dData,
|
|
}
|
|
},
|
|
handler: func(ctrl *gomock.Controller) Handler {
|
|
h := NewMockHandler(ctrl)
|
|
h.EXPECT().Execute(gomock.Eq(defaultBuildCommand)).Times(0)
|
|
h.EXPECT().Execute(gomock.Eq(nonDefaultBuildCommandExplicit)).Times(0)
|
|
h.EXPECT().Execute(gomock.Eq(nonDefaultBuildCommandImplicit)).Times(0)
|
|
return h
|
|
},
|
|
cmdName: "my-explicit-non-default-build-command",
|
|
},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "with custom command",
|
|
args: args{
|
|
devfileObj: func() parser.DevfileObj {
|
|
dData, _ := data.NewDevfileData(string(data.APISchemaVersion200))
|
|
_ = dData.AddCommands([]v1alpha2.Command{nonDefaultBuildCommandExplicit, nonDefaultBuildCommandImplicit})
|
|
_ = dData.AddComponents([]v1alpha2.Component{containerComp})
|
|
return parser.DevfileObj{
|
|
Data: dData,
|
|
}
|
|
},
|
|
handler: func(ctrl *gomock.Controller) Handler {
|
|
h := NewMockHandler(ctrl)
|
|
h.EXPECT().Execute(gomock.Eq(defaultBuildCommand)).Times(0)
|
|
h.EXPECT().Execute(gomock.Eq(nonDefaultBuildCommandExplicit)).Times(1)
|
|
h.EXPECT().Execute(gomock.Eq(nonDefaultBuildCommandImplicit)).Times(0)
|
|
return h
|
|
},
|
|
cmdName: "my-explicit-non-default-build-command",
|
|
},
|
|
},
|
|
} {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
err := Build(tt.args.devfileObj(), tt.args.cmdName, tt.args.handler(gomock.NewController(t)))
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("Build() error = %v, wantErr %v", err, tt.wantErr)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetContainerEndpointMapping(t *testing.T) {
|
|
type args struct {
|
|
containers []v1alpha2.Component
|
|
}
|
|
|
|
imageComponent := generator.GetImageComponent(generator.ImageComponentParams{
|
|
Name: "image-component",
|
|
Image: v1alpha2.Image{
|
|
ImageName: "an-image-name",
|
|
},
|
|
})
|
|
|
|
containerWithNoEndpoints := generator.GetContainerComponent(generator.ContainerComponentParams{
|
|
Name: "container 1",
|
|
Endpoints: nil,
|
|
})
|
|
|
|
containerWithOnePublicEndpoint := generator.GetContainerComponent(generator.ContainerComponentParams{
|
|
Name: "container 2",
|
|
Endpoints: []v1alpha2.Endpoint{
|
|
{
|
|
Name: "ep1",
|
|
TargetPort: 8080,
|
|
Exposure: v1alpha2.PublicEndpointExposure,
|
|
},
|
|
},
|
|
})
|
|
|
|
containerWithOneInternalEndpoint := generator.GetContainerComponent(generator.ContainerComponentParams{
|
|
Name: "container 3",
|
|
Endpoints: []v1alpha2.Endpoint{
|
|
{
|
|
Name: "ep2",
|
|
TargetPort: 9090,
|
|
Exposure: v1alpha2.InternalEndpointExposure,
|
|
},
|
|
},
|
|
})
|
|
|
|
containerWithOneNoneInternalEndpoint := generator.GetContainerComponent(generator.ContainerComponentParams{
|
|
Name: "container-none-endpoint",
|
|
Endpoints: []v1alpha2.Endpoint{
|
|
{
|
|
Name: "debug",
|
|
TargetPort: 9099,
|
|
Exposure: v1alpha2.NoneEndpointExposure,
|
|
},
|
|
},
|
|
})
|
|
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want map[string][]int
|
|
}{
|
|
{
|
|
name: "invalid input - image components instead of container components",
|
|
args: args{
|
|
containers: []v1alpha2.Component{imageComponent},
|
|
},
|
|
want: map[string][]int{},
|
|
},
|
|
{
|
|
name: "one container with no endpoints exposed",
|
|
args: args{
|
|
containers: []v1alpha2.Component{containerWithNoEndpoints},
|
|
},
|
|
want: map[string][]int{containerWithNoEndpoints.Name: {}},
|
|
},
|
|
{
|
|
name: "multiple containers with varying types of endpoints",
|
|
args: args{
|
|
containers: []v1alpha2.Component{
|
|
containerWithNoEndpoints,
|
|
containerWithOnePublicEndpoint,
|
|
containerWithOneInternalEndpoint,
|
|
containerWithOneNoneInternalEndpoint,
|
|
},
|
|
},
|
|
want: map[string][]int{
|
|
containerWithNoEndpoints.Name: {},
|
|
containerWithOnePublicEndpoint.Name: {8080},
|
|
containerWithOneInternalEndpoint.Name: {9090},
|
|
containerWithOneNoneInternalEndpoint.Name: {9099},
|
|
},
|
|
},
|
|
{
|
|
name: "invalid input - one image component with rest being containers",
|
|
args: args{
|
|
containers: []v1alpha2.Component{
|
|
containerWithNoEndpoints,
|
|
containerWithOnePublicEndpoint,
|
|
containerWithOneInternalEndpoint,
|
|
containerWithOneNoneInternalEndpoint,
|
|
imageComponent,
|
|
},
|
|
},
|
|
want: map[string][]int{
|
|
containerWithNoEndpoints.Name: {},
|
|
containerWithOnePublicEndpoint.Name: {8080},
|
|
containerWithOneInternalEndpoint.Name: {9090},
|
|
containerWithOneNoneInternalEndpoint.Name: {9099},
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := GetContainerEndpointMapping(tt.args.containers)
|
|
|
|
if diff := cmp.Diff(tt.want, got); diff != "" {
|
|
t.Errorf("GetContainerEndpointMapping() mismatch (-want +got):\n%s", diff)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetEndpointsFromDevfile(t *testing.T) {
|
|
type args struct {
|
|
devfileObj func() parser.DevfileObj
|
|
ignoreExposures []v1alpha2.EndpointExposure
|
|
}
|
|
ep1 := v1alpha2.Endpoint{Name: "ep1", TargetPort: 8080, Exposure: v1alpha2.NoneEndpointExposure}
|
|
ep2 := v1alpha2.Endpoint{Name: "ep2", TargetPort: 9090, Exposure: v1alpha2.InternalEndpointExposure}
|
|
ep3 := v1alpha2.Endpoint{Name: "ep3", TargetPort: 8888, Exposure: v1alpha2.PublicEndpointExposure}
|
|
|
|
container := generator.GetContainerComponent(generator.ContainerComponentParams{
|
|
Name: "container-1",
|
|
Endpoints: []v1alpha2.Endpoint{ep1, ep2, ep3},
|
|
})
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want []v1alpha2.Endpoint
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "Ignore exposure of type none",
|
|
args: args{
|
|
devfileObj: func() parser.DevfileObj {
|
|
data, _ := data.NewDevfileData(string(data.APISchemaVersion200))
|
|
_ = data.AddComponents([]v1alpha2.Component{container})
|
|
return parser.DevfileObj{
|
|
Data: data,
|
|
}
|
|
},
|
|
ignoreExposures: []v1alpha2.EndpointExposure{v1alpha2.NoneEndpointExposure},
|
|
},
|
|
want: []v1alpha2.Endpoint{ep2, ep3},
|
|
},
|
|
{
|
|
name: "Ignore exposure of type public",
|
|
args: args{
|
|
devfileObj: func() parser.DevfileObj {
|
|
data, _ := data.NewDevfileData(string(data.APISchemaVersion200))
|
|
_ = data.AddComponents([]v1alpha2.Component{container})
|
|
return parser.DevfileObj{
|
|
Data: data,
|
|
}
|
|
},
|
|
ignoreExposures: []v1alpha2.EndpointExposure{v1alpha2.PublicEndpointExposure},
|
|
},
|
|
want: []v1alpha2.Endpoint{ep1, ep2},
|
|
},
|
|
{
|
|
name: "Ignore exposure of type internal",
|
|
args: args{
|
|
devfileObj: func() parser.DevfileObj {
|
|
data, _ := data.NewDevfileData(string(data.APISchemaVersion200))
|
|
_ = data.AddComponents([]v1alpha2.Component{container})
|
|
return parser.DevfileObj{
|
|
Data: data,
|
|
}
|
|
},
|
|
ignoreExposures: []v1alpha2.EndpointExposure{v1alpha2.InternalEndpointExposure},
|
|
},
|
|
want: []v1alpha2.Endpoint{ep1, ep3},
|
|
},
|
|
{
|
|
name: "Ignore none",
|
|
args: args{
|
|
devfileObj: func() parser.DevfileObj {
|
|
data, _ := data.NewDevfileData(string(data.APISchemaVersion200))
|
|
_ = data.AddComponents([]v1alpha2.Component{container})
|
|
return parser.DevfileObj{
|
|
Data: data,
|
|
}
|
|
},
|
|
ignoreExposures: []v1alpha2.EndpointExposure{},
|
|
},
|
|
want: []v1alpha2.Endpoint{ep1, ep2, ep3},
|
|
},
|
|
{
|
|
name: "Ignore all exposure types",
|
|
args: args{
|
|
devfileObj: func() parser.DevfileObj {
|
|
data, _ := data.NewDevfileData(string(data.APISchemaVersion200))
|
|
_ = data.AddComponents([]v1alpha2.Component{container})
|
|
return parser.DevfileObj{
|
|
Data: data,
|
|
}
|
|
},
|
|
ignoreExposures: []v1alpha2.EndpointExposure{v1alpha2.InternalEndpointExposure, v1alpha2.NoneEndpointExposure, v1alpha2.PublicEndpointExposure},
|
|
},
|
|
want: nil,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := GetEndpointsFromDevfile(tt.args.devfileObj(), tt.args.ignoreExposures)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("GetEndpointsFromDevfile() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if diff := cmp.Diff(tt.want, got); diff != "" {
|
|
t.Errorf("GetEndpointsFromDevfile() mismatch (-want +got):\n%s", diff)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetK8sManifestWithVariablesSubstituted(t *testing.T) {
|
|
fakeFs := devfileFileSystem.NewFakeFs()
|
|
cmpName := "my-cmp-1"
|
|
for _, tt := range []struct {
|
|
name string
|
|
setupFunc func() error
|
|
devfileObjFunc func() parser.DevfileObj
|
|
wantErr bool
|
|
want string
|
|
}{
|
|
{
|
|
name: "Missing Component",
|
|
devfileObjFunc: func() parser.DevfileObj {
|
|
devfileData, _ := data.NewDevfileData(string(data.APISchemaVersion220))
|
|
cmp := generator.GetContainerComponent(generator.ContainerComponentParams{
|
|
Name: "a-different-component",
|
|
})
|
|
s := v1alpha2.DevWorkspaceTemplateSpec{
|
|
DevWorkspaceTemplateSpecContent: v1alpha2.DevWorkspaceTemplateSpecContent{
|
|
Components: []v1alpha2.Component{cmp},
|
|
},
|
|
}
|
|
devfileData.SetDevfileWorkspaceSpec(s)
|
|
return parser.DevfileObj{
|
|
Data: devfileData,
|
|
}
|
|
},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "Multiple Components with the same name",
|
|
devfileObjFunc: func() parser.DevfileObj {
|
|
devfileData, _ := data.NewDevfileData(string(data.APISchemaVersion220))
|
|
cmp1 := generator.GetContainerComponent(generator.ContainerComponentParams{
|
|
Name: cmpName,
|
|
})
|
|
cmp2 := generator.GetImageComponent(generator.ImageComponentParams{
|
|
Name: cmpName,
|
|
})
|
|
s := v1alpha2.DevWorkspaceTemplateSpec{
|
|
DevWorkspaceTemplateSpecContent: v1alpha2.DevWorkspaceTemplateSpecContent{
|
|
Components: []v1alpha2.Component{cmp1, cmp2},
|
|
},
|
|
}
|
|
devfileData.SetDevfileWorkspaceSpec(s)
|
|
return parser.DevfileObj{
|
|
Data: devfileData,
|
|
}
|
|
},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "Container Component",
|
|
devfileObjFunc: func() parser.DevfileObj {
|
|
devfileData, _ := data.NewDevfileData(string(data.APISchemaVersion220))
|
|
cmp := generator.GetContainerComponent(generator.ContainerComponentParams{
|
|
Name: cmpName,
|
|
})
|
|
s := v1alpha2.DevWorkspaceTemplateSpec{
|
|
DevWorkspaceTemplateSpecContent: v1alpha2.DevWorkspaceTemplateSpecContent{
|
|
Components: []v1alpha2.Component{cmp},
|
|
},
|
|
}
|
|
devfileData.SetDevfileWorkspaceSpec(s)
|
|
return parser.DevfileObj{
|
|
Data: devfileData,
|
|
}
|
|
},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "Image Component",
|
|
devfileObjFunc: func() parser.DevfileObj {
|
|
devfileData, _ := data.NewDevfileData(string(data.APISchemaVersion220))
|
|
cmp := generator.GetImageComponent(generator.ImageComponentParams{
|
|
Name: cmpName,
|
|
})
|
|
s := v1alpha2.DevWorkspaceTemplateSpec{
|
|
DevWorkspaceTemplateSpecContent: v1alpha2.DevWorkspaceTemplateSpecContent{
|
|
Components: []v1alpha2.Component{cmp},
|
|
},
|
|
}
|
|
devfileData.SetDevfileWorkspaceSpec(s)
|
|
return parser.DevfileObj{
|
|
Data: devfileData,
|
|
}
|
|
},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "Kubernetes Component - Inlined with no variables",
|
|
devfileObjFunc: func() parser.DevfileObj {
|
|
devfileData, _ := data.NewDevfileData(string(data.APISchemaVersion220))
|
|
cmp := generator.GetKubernetesComponent(generator.KubernetesComponentParams{
|
|
Name: cmpName,
|
|
Kubernetes: &v1alpha2.KubernetesComponent{
|
|
K8sLikeComponent: v1alpha2.K8sLikeComponent{
|
|
K8sLikeComponentLocation: v1alpha2.K8sLikeComponentLocation{
|
|
Inlined: "some-text-inlined",
|
|
},
|
|
},
|
|
},
|
|
})
|
|
s := v1alpha2.DevWorkspaceTemplateSpec{
|
|
DevWorkspaceTemplateSpecContent: v1alpha2.DevWorkspaceTemplateSpecContent{
|
|
Components: []v1alpha2.Component{cmp},
|
|
},
|
|
}
|
|
devfileData.SetDevfileWorkspaceSpec(s)
|
|
return parser.DevfileObj{
|
|
Data: devfileData,
|
|
}
|
|
},
|
|
wantErr: false,
|
|
want: "some-text-inlined",
|
|
},
|
|
{
|
|
name: "Kubernetes Component - Inlined with variables",
|
|
devfileObjFunc: func() parser.DevfileObj {
|
|
devfileData, _ := data.NewDevfileData(string(data.APISchemaVersion220))
|
|
cmp := generator.GetKubernetesComponent(generator.KubernetesComponentParams{
|
|
Name: cmpName,
|
|
Kubernetes: &v1alpha2.KubernetesComponent{
|
|
K8sLikeComponent: v1alpha2.K8sLikeComponent{
|
|
K8sLikeComponentLocation: v1alpha2.K8sLikeComponentLocation{
|
|
Inlined: "image: {{MY_CONTAINER_IMAGE}}",
|
|
},
|
|
},
|
|
},
|
|
})
|
|
s := v1alpha2.DevWorkspaceTemplateSpec{
|
|
DevWorkspaceTemplateSpecContent: v1alpha2.DevWorkspaceTemplateSpecContent{
|
|
Variables: map[string]string{
|
|
"MY_CONTAINER_IMAGE": "quay.io/unknown-account/my-image:1.2.3",
|
|
},
|
|
Components: []v1alpha2.Component{cmp},
|
|
},
|
|
}
|
|
devfileData.SetDevfileWorkspaceSpec(s)
|
|
return parser.DevfileObj{
|
|
Data: devfileData,
|
|
}
|
|
},
|
|
wantErr: false,
|
|
want: "image: quay.io/unknown-account/my-image:1.2.3",
|
|
},
|
|
{
|
|
name: "Kubernetes Component - Inlined with unknown variables",
|
|
devfileObjFunc: func() parser.DevfileObj {
|
|
devfileData, _ := data.NewDevfileData(string(data.APISchemaVersion220))
|
|
cmp := generator.GetKubernetesComponent(generator.KubernetesComponentParams{
|
|
Name: cmpName,
|
|
Kubernetes: &v1alpha2.KubernetesComponent{
|
|
K8sLikeComponent: v1alpha2.K8sLikeComponent{
|
|
K8sLikeComponentLocation: v1alpha2.K8sLikeComponentLocation{
|
|
Inlined: "image: {{MY_CONTAINER_IMAGE}}:{{ MY_CONTAINER_IMAGE_VERSION_UNKNOWN }}",
|
|
},
|
|
},
|
|
},
|
|
})
|
|
s := v1alpha2.DevWorkspaceTemplateSpec{
|
|
DevWorkspaceTemplateSpecContent: v1alpha2.DevWorkspaceTemplateSpecContent{
|
|
Variables: map[string]string{
|
|
"MY_CONTAINER_IMAGE": "quay.io/unknown-account/my-image",
|
|
},
|
|
Components: []v1alpha2.Component{cmp},
|
|
},
|
|
}
|
|
devfileData.SetDevfileWorkspaceSpec(s)
|
|
return parser.DevfileObj{
|
|
Data: devfileData,
|
|
}
|
|
},
|
|
wantErr: true,
|
|
want: "image: quay.io/unknown-account/my-image:{{ MY_CONTAINER_IMAGE_VERSION_UNKNOWN }}",
|
|
},
|
|
{
|
|
name: "Kubernetes Component - non-existing external file",
|
|
devfileObjFunc: func() parser.DevfileObj {
|
|
devfileData, _ := data.NewDevfileData(string(data.APISchemaVersion220))
|
|
cmp := generator.GetKubernetesComponent(generator.KubernetesComponentParams{
|
|
Name: cmpName,
|
|
Kubernetes: &v1alpha2.KubernetesComponent{
|
|
K8sLikeComponent: v1alpha2.K8sLikeComponent{
|
|
K8sLikeComponentLocation: v1alpha2.K8sLikeComponentLocation{
|
|
Uri: "kubernetes/my-external-file-with-should-not-exist",
|
|
},
|
|
},
|
|
},
|
|
})
|
|
s := v1alpha2.DevWorkspaceTemplateSpec{
|
|
DevWorkspaceTemplateSpecContent: v1alpha2.DevWorkspaceTemplateSpecContent{
|
|
Components: []v1alpha2.Component{cmp},
|
|
},
|
|
}
|
|
devfileData.SetDevfileWorkspaceSpec(s)
|
|
return parser.DevfileObj{
|
|
Data: devfileData,
|
|
}
|
|
},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "Kubernetes Component - URI with no variables",
|
|
setupFunc: func() error {
|
|
return fakeFs.WriteFile("kubernetes/my-external-file",
|
|
[]byte("some-text-with-no-variables"),
|
|
os.ModePerm)
|
|
},
|
|
devfileObjFunc: func() parser.DevfileObj {
|
|
devfileData, _ := data.NewDevfileData(string(data.APISchemaVersion220))
|
|
cmp := generator.GetKubernetesComponent(generator.KubernetesComponentParams{
|
|
Name: cmpName,
|
|
Kubernetes: &v1alpha2.KubernetesComponent{
|
|
K8sLikeComponent: v1alpha2.K8sLikeComponent{
|
|
K8sLikeComponentLocation: v1alpha2.K8sLikeComponentLocation{
|
|
Uri: "kubernetes/my-external-file",
|
|
},
|
|
},
|
|
},
|
|
})
|
|
s := v1alpha2.DevWorkspaceTemplateSpec{
|
|
DevWorkspaceTemplateSpecContent: v1alpha2.DevWorkspaceTemplateSpecContent{
|
|
Components: []v1alpha2.Component{cmp},
|
|
},
|
|
}
|
|
devfileData.SetDevfileWorkspaceSpec(s)
|
|
return parser.DevfileObj{
|
|
Data: devfileData,
|
|
}
|
|
},
|
|
wantErr: false,
|
|
want: "some-text-with-no-variables",
|
|
},
|
|
{
|
|
name: "Kubernetes Component - URI with variables",
|
|
setupFunc: func() error {
|
|
return fakeFs.WriteFile("kubernetes/my-deployment.yaml",
|
|
[]byte("image: {{ MY_CONTAINER_IMAGE }}:{{MY_CONTAINER_IMAGE_VERSION}}"),
|
|
os.ModePerm)
|
|
},
|
|
devfileObjFunc: func() parser.DevfileObj {
|
|
devfileData, _ := data.NewDevfileData(string(data.APISchemaVersion220))
|
|
cmp := generator.GetKubernetesComponent(generator.KubernetesComponentParams{
|
|
Name: cmpName,
|
|
Kubernetes: &v1alpha2.KubernetesComponent{
|
|
K8sLikeComponent: v1alpha2.K8sLikeComponent{
|
|
K8sLikeComponentLocation: v1alpha2.K8sLikeComponentLocation{
|
|
Uri: "kubernetes/my-deployment.yaml",
|
|
},
|
|
},
|
|
},
|
|
})
|
|
s := v1alpha2.DevWorkspaceTemplateSpec{
|
|
DevWorkspaceTemplateSpecContent: v1alpha2.DevWorkspaceTemplateSpecContent{
|
|
Variables: map[string]string{
|
|
"MY_CONTAINER_IMAGE": "quay.io/unknown-account/my-image",
|
|
"MY_CONTAINER_IMAGE_VERSION": "1.2.3",
|
|
},
|
|
Components: []v1alpha2.Component{cmp},
|
|
},
|
|
}
|
|
devfileData.SetDevfileWorkspaceSpec(s)
|
|
return parser.DevfileObj{
|
|
Data: devfileData,
|
|
}
|
|
},
|
|
wantErr: false,
|
|
want: "image: quay.io/unknown-account/my-image:1.2.3",
|
|
},
|
|
{
|
|
name: "Kubernetes Component - URI with unknown variables",
|
|
setupFunc: func() error {
|
|
return fakeFs.WriteFile("kubernetes/my-external-file.yaml",
|
|
[]byte("image: {{MY_CONTAINER_IMAGE}}:{{ MY_CONTAINER_IMAGE_VERSION_UNKNOWN }}"),
|
|
os.ModePerm)
|
|
},
|
|
devfileObjFunc: func() parser.DevfileObj {
|
|
devfileData, _ := data.NewDevfileData(string(data.APISchemaVersion220))
|
|
cmp := generator.GetKubernetesComponent(generator.KubernetesComponentParams{
|
|
Name: cmpName,
|
|
Kubernetes: &v1alpha2.KubernetesComponent{
|
|
K8sLikeComponent: v1alpha2.K8sLikeComponent{
|
|
K8sLikeComponentLocation: v1alpha2.K8sLikeComponentLocation{
|
|
Uri: "kubernetes/my-external-file.yaml",
|
|
},
|
|
},
|
|
},
|
|
})
|
|
s := v1alpha2.DevWorkspaceTemplateSpec{
|
|
DevWorkspaceTemplateSpecContent: v1alpha2.DevWorkspaceTemplateSpecContent{
|
|
Variables: map[string]string{
|
|
"MY_CONTAINER_IMAGE": "quay.io/unknown-account/my-image",
|
|
},
|
|
Components: []v1alpha2.Component{cmp},
|
|
},
|
|
}
|
|
devfileData.SetDevfileWorkspaceSpec(s)
|
|
return parser.DevfileObj{
|
|
Data: devfileData,
|
|
}
|
|
},
|
|
wantErr: true,
|
|
want: "image: quay.io/unknown-account/my-image:{{ MY_CONTAINER_IMAGE_VERSION_UNKNOWN }}",
|
|
},
|
|
} {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if tt.setupFunc != nil {
|
|
if err := tt.setupFunc(); err != nil {
|
|
t.Errorf("setup function returned an error: %v", err)
|
|
return
|
|
}
|
|
}
|
|
if tt.devfileObjFunc == nil {
|
|
t.Error("devfileObjFunc function not defined for test case")
|
|
return
|
|
}
|
|
|
|
got, err := GetK8sManifestWithVariablesSubstituted(tt.devfileObjFunc(), cmpName, "", fakeFs)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("GetK8sManifestWithVariablesSubstituted() error = %v, wantErr %v",
|
|
err, tt.wantErr)
|
|
return
|
|
}
|
|
if got != tt.want {
|
|
t.Errorf("GetK8sManifestWithVariablesSubstituted() got = %v, want %v",
|
|
got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestValidateAndGetCommand(t *testing.T) {
|
|
|
|
commands := [...]string{"ls -la", "pwd"}
|
|
components := [...]string{"alias1", "alias2"}
|
|
|
|
tests := []struct {
|
|
name string
|
|
requestedType []v1alpha2.CommandGroupKind
|
|
execCommands []v1alpha2.Command
|
|
compCommands []v1alpha2.Command
|
|
reqCommandName string
|
|
retCommandName []string
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "Case 1: Valid devfile, default command returned even if it is not marked as IsDefault",
|
|
execCommands: []v1alpha2.Command{
|
|
getExecCommand("build", buildGroup),
|
|
getExecCommand("run", runGroup),
|
|
},
|
|
requestedType: []v1alpha2.CommandGroupKind{buildGroup, runGroup},
|
|
wantErr: false,
|
|
retCommandName: []string{"build", "run"},
|
|
},
|
|
{
|
|
name: "Case 2: Valid devfile, but error returned because multiple build commands without default",
|
|
execCommands: []v1alpha2.Command{
|
|
getExecCommand("build", buildGroup),
|
|
getExecCommand("build2", buildGroup),
|
|
getExecCommand("run", runGroup),
|
|
},
|
|
requestedType: []v1alpha2.CommandGroupKind{buildGroup, runGroup},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "Case 3: Valid devfile with empty workdir",
|
|
execCommands: []v1alpha2.Command{
|
|
{
|
|
Id: "run",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Exec: &v1alpha2.ExecCommand{
|
|
LabeledCommand: v1alpha2.LabeledCommand{
|
|
BaseCommand: v1alpha2.BaseCommand{
|
|
Group: &v1alpha2.CommandGroup{Kind: runGroup},
|
|
},
|
|
},
|
|
CommandLine: commands[0],
|
|
Component: components[0],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
requestedType: []v1alpha2.CommandGroupKind{runGroup},
|
|
wantErr: false,
|
|
retCommandName: []string{"run"},
|
|
},
|
|
{
|
|
name: "Case 4.1: Mismatched command type",
|
|
execCommands: []v1alpha2.Command{
|
|
{
|
|
Id: "build command",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Exec: &v1alpha2.ExecCommand{
|
|
LabeledCommand: v1alpha2.LabeledCommand{
|
|
BaseCommand: v1alpha2.BaseCommand{
|
|
Group: &v1alpha2.CommandGroup{Kind: runGroup},
|
|
},
|
|
},
|
|
CommandLine: commands[0],
|
|
Component: components[0],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
reqCommandName: "build command",
|
|
requestedType: []v1alpha2.CommandGroupKind{buildGroup},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "Case 4.2: Matching command by name and type",
|
|
execCommands: []v1alpha2.Command{
|
|
{
|
|
Id: "build command",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Exec: &v1alpha2.ExecCommand{
|
|
LabeledCommand: v1alpha2.LabeledCommand{
|
|
BaseCommand: v1alpha2.BaseCommand{
|
|
Group: &v1alpha2.CommandGroup{Kind: buildGroup},
|
|
},
|
|
},
|
|
CommandLine: commands[0],
|
|
Component: components[0],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
reqCommandName: "build command",
|
|
requestedType: []v1alpha2.CommandGroupKind{buildGroup},
|
|
retCommandName: []string{"build command"},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "Case 5: Default command is returned",
|
|
execCommands: []v1alpha2.Command{
|
|
{
|
|
Id: "defaultRunCommand",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Exec: &v1alpha2.ExecCommand{
|
|
LabeledCommand: v1alpha2.LabeledCommand{
|
|
BaseCommand: v1alpha2.BaseCommand{
|
|
Group: &v1alpha2.CommandGroup{Kind: runGroup, IsDefault: util.GetBoolPtr(true)},
|
|
},
|
|
},
|
|
CommandLine: commands[0],
|
|
Component: components[0],
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Id: "runCommand",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Exec: &v1alpha2.ExecCommand{
|
|
LabeledCommand: v1alpha2.LabeledCommand{
|
|
BaseCommand: v1alpha2.BaseCommand{
|
|
Group: &v1alpha2.CommandGroup{Kind: runGroup},
|
|
},
|
|
},
|
|
CommandLine: commands[0],
|
|
Component: components[0],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
retCommandName: []string{"defaultRunCommand"},
|
|
requestedType: []v1alpha2.CommandGroupKind{runGroup},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "Case 6: Composite command is returned",
|
|
execCommands: []v1alpha2.Command{
|
|
{
|
|
Id: "build",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Exec: &v1alpha2.ExecCommand{
|
|
LabeledCommand: v1alpha2.LabeledCommand{
|
|
BaseCommand: v1alpha2.BaseCommand{
|
|
Group: &v1alpha2.CommandGroup{Kind: buildGroup, IsDefault: util.GetBoolPtr(false)},
|
|
},
|
|
},
|
|
CommandLine: commands[0],
|
|
Component: components[0],
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Id: "run",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Exec: &v1alpha2.ExecCommand{
|
|
LabeledCommand: v1alpha2.LabeledCommand{
|
|
BaseCommand: v1alpha2.BaseCommand{
|
|
Group: &v1alpha2.CommandGroup{Kind: runGroup},
|
|
},
|
|
},
|
|
CommandLine: commands[0],
|
|
Component: components[0],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
compCommands: []v1alpha2.Command{
|
|
{
|
|
Id: "myComposite",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Composite: &v1alpha2.CompositeCommand{
|
|
LabeledCommand: v1alpha2.LabeledCommand{
|
|
BaseCommand: v1alpha2.BaseCommand{
|
|
Group: &v1alpha2.CommandGroup{Kind: buildGroup, IsDefault: util.GetBoolPtr(true)},
|
|
},
|
|
},
|
|
Commands: []string{"build", "run"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
retCommandName: []string{"myComposite"},
|
|
requestedType: []v1alpha2.CommandGroupKind{buildGroup},
|
|
wantErr: false,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
if !tt.wantErr && (len(tt.requestedType) != len(tt.retCommandName)) {
|
|
t.Errorf("Invalid test definition %q requestedType length must match retCommandName length.", tt.name)
|
|
}
|
|
components := []v1alpha2.Component{testingutil.GetFakeContainerComponent(tt.execCommands[0].Exec.Component)}
|
|
devObj := parser.DevfileObj{
|
|
Data: func() data.DevfileData {
|
|
devfileData, err := data.NewDevfileData(string(data.APISchemaVersion200))
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
err = devfileData.AddCommands(tt.execCommands)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
err = devfileData.AddCommands(tt.compCommands)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
err = devfileData.AddComponents(components)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
return devfileData
|
|
}(),
|
|
}
|
|
|
|
for i, gtype := range tt.requestedType {
|
|
cmd, err := ValidateAndGetCommand(devObj, tt.reqCommandName, gtype)
|
|
if tt.wantErr != (err != nil) {
|
|
t.Errorf("TestGetCommand unexpected error for command: %v wantErr: %v err: %v", gtype, tt.wantErr, err)
|
|
return
|
|
} else if tt.wantErr {
|
|
return
|
|
}
|
|
|
|
if cmd.Id != tt.retCommandName[i] {
|
|
t.Errorf("TestGetCommand error: command names do not match expected: %v actual: %v", tt.retCommandName[i], cmd.Id)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
}
|
|
|
|
func TestValidateAndGetPushCommands(t *testing.T) {
|
|
|
|
command := "ls -la"
|
|
component := "alias1"
|
|
workDir := "/"
|
|
emptyString := ""
|
|
|
|
execCommands := []v1alpha2.Command{
|
|
{
|
|
Id: "run command",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Exec: &v1alpha2.ExecCommand{
|
|
LabeledCommand: v1alpha2.LabeledCommand{
|
|
BaseCommand: v1alpha2.BaseCommand{
|
|
Group: &v1alpha2.CommandGroup{
|
|
Kind: runGroup,
|
|
IsDefault: util.GetBoolPtr(true),
|
|
},
|
|
},
|
|
},
|
|
CommandLine: command,
|
|
Component: component,
|
|
WorkingDir: workDir,
|
|
},
|
|
},
|
|
},
|
|
|
|
{
|
|
Id: "build command",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Exec: &v1alpha2.ExecCommand{
|
|
LabeledCommand: v1alpha2.LabeledCommand{
|
|
BaseCommand: v1alpha2.BaseCommand{
|
|
Group: &v1alpha2.CommandGroup{Kind: buildGroup},
|
|
},
|
|
},
|
|
CommandLine: command,
|
|
Component: component,
|
|
WorkingDir: workDir,
|
|
},
|
|
},
|
|
},
|
|
|
|
{
|
|
Id: "customcommand",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Exec: &v1alpha2.ExecCommand{
|
|
LabeledCommand: v1alpha2.LabeledCommand{
|
|
BaseCommand: v1alpha2.BaseCommand{
|
|
Group: &v1alpha2.CommandGroup{Kind: runGroup},
|
|
},
|
|
},
|
|
CommandLine: command,
|
|
Component: component,
|
|
WorkingDir: workDir,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
defaultBuildCommand := v1alpha2.Command{
|
|
Id: "default build command",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Exec: &v1alpha2.ExecCommand{
|
|
LabeledCommand: v1alpha2.LabeledCommand{
|
|
BaseCommand: v1alpha2.BaseCommand{
|
|
Group: &v1alpha2.CommandGroup{Kind: buildGroup, IsDefault: util.GetBoolPtr(true)},
|
|
},
|
|
},
|
|
CommandLine: command,
|
|
Component: component,
|
|
WorkingDir: workDir,
|
|
},
|
|
},
|
|
}
|
|
|
|
wrongCompTypeCmd := v1alpha2.Command{
|
|
|
|
Id: "wrong",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Exec: &v1alpha2.ExecCommand{
|
|
LabeledCommand: v1alpha2.LabeledCommand{
|
|
BaseCommand: v1alpha2.BaseCommand{
|
|
Group: &v1alpha2.CommandGroup{Kind: runGroup},
|
|
},
|
|
},
|
|
CommandLine: command,
|
|
Component: "",
|
|
WorkingDir: workDir,
|
|
},
|
|
},
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
buildCommand string
|
|
runCommand string
|
|
execCommands []v1alpha2.Command
|
|
numberOfCommands int
|
|
missingBuildCommand bool
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "Case 1: Default Devfile Commands",
|
|
buildCommand: emptyString,
|
|
runCommand: emptyString,
|
|
execCommands: execCommands,
|
|
numberOfCommands: 2,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "Case 2: Default Build Command, and Provided Run Command",
|
|
buildCommand: emptyString,
|
|
runCommand: "customcommand",
|
|
execCommands: execCommands,
|
|
//only the specified run command is returned, because the build command is not marked as default
|
|
numberOfCommands: 2,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "Case 2.2: Default Build Command, and Default Run Command",
|
|
buildCommand: emptyString,
|
|
runCommand: emptyString,
|
|
execCommands: append(execCommands, defaultBuildCommand),
|
|
numberOfCommands: 2,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "Case 3: Empty Component",
|
|
buildCommand: "customcommand",
|
|
runCommand: "customcommand",
|
|
execCommands: append(execCommands, wrongCompTypeCmd),
|
|
numberOfCommands: 0,
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "Case 4: Provided Wrong Build Command and Provided Run Command",
|
|
buildCommand: "customcommand123",
|
|
runCommand: "customcommand",
|
|
execCommands: execCommands,
|
|
numberOfCommands: 1,
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "Case 5: Missing Build Command, and Provided Run Command",
|
|
buildCommand: emptyString,
|
|
runCommand: "customcommand",
|
|
execCommands: []v1alpha2.Command{
|
|
{
|
|
Id: "customcommand",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Exec: &v1alpha2.ExecCommand{
|
|
LabeledCommand: v1alpha2.LabeledCommand{
|
|
BaseCommand: v1alpha2.BaseCommand{
|
|
Group: &v1alpha2.CommandGroup{Kind: runGroup},
|
|
},
|
|
},
|
|
Component: component,
|
|
CommandLine: command,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
numberOfCommands: 1,
|
|
wantErr: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
devObj := parser.DevfileObj{
|
|
Data: func() data.DevfileData {
|
|
devfileData, err := data.NewDevfileData(string(data.APISchemaVersion200))
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
err = devfileData.AddCommands(tt.execCommands)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
err = devfileData.AddComponents(([]v1alpha2.Component{testingutil.GetFakeContainerComponent(component)}))
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
return devfileData
|
|
}(),
|
|
}
|
|
|
|
pushCommands, err := ValidateAndGetPushCommands(devObj, tt.buildCommand, tt.runCommand)
|
|
if !tt.wantErr == (err != nil) {
|
|
t.Errorf("TestValidateAndGetPushDevfileCommands unexpected error when validating commands wantErr: %v err: %v", tt.wantErr, err)
|
|
} else if tt.wantErr && err != nil {
|
|
return
|
|
}
|
|
|
|
if len(pushCommands) != tt.numberOfCommands {
|
|
t.Errorf("TestValidateAndGetPushDevfileCommands error: wrong number of validated commands expected: %v actual :%v", tt.numberOfCommands, len(pushCommands))
|
|
}
|
|
})
|
|
}
|
|
|
|
}
|
|
|
|
func TestGetContainerComponentsForCommand(t *testing.T) {
|
|
devfileData, _ := data.NewDevfileData(string(data.APISchemaVersion220))
|
|
devfileData.SetMetadata(devfilepkg.DevfileMetadata{Name: "my-app"})
|
|
_ = devfileData.AddComponents([]v1alpha2.Component{
|
|
{
|
|
Name: "my-container1",
|
|
ComponentUnion: v1alpha2.ComponentUnion{
|
|
Container: &v1alpha2.ContainerComponent{
|
|
Container: v1alpha2.Container{Image: "my-image"},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "my-container2",
|
|
ComponentUnion: v1alpha2.ComponentUnion{
|
|
Container: &v1alpha2.ContainerComponent{
|
|
Container: v1alpha2.Container{Image: "my-image"},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "my-container3",
|
|
ComponentUnion: v1alpha2.ComponentUnion{
|
|
Container: &v1alpha2.ContainerComponent{
|
|
Container: v1alpha2.Container{Image: "my-image"},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "my-image1",
|
|
ComponentUnion: v1alpha2.ComponentUnion{
|
|
Image: &v1alpha2.ImageComponent{
|
|
Image: v1alpha2.Image{
|
|
ImageName: "my-image",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "my-k8s",
|
|
ComponentUnion: v1alpha2.ComponentUnion{
|
|
Kubernetes: &v1alpha2.KubernetesComponent{
|
|
K8sLikeComponent: v1alpha2.K8sLikeComponent{
|
|
K8sLikeComponentLocation: v1alpha2.K8sLikeComponentLocation{
|
|
Inlined: "---",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
customCmd := v1alpha2.Command{
|
|
Id: "custom",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Custom: &v1alpha2.CustomCommand{},
|
|
},
|
|
}
|
|
execCmdCont1 := v1alpha2.Command{
|
|
Id: "execCmdCont1",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Exec: &v1alpha2.ExecCommand{Component: "my-container1"},
|
|
},
|
|
}
|
|
execCmdCont2 := v1alpha2.Command{
|
|
Id: "execCmdCont2",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Exec: &v1alpha2.ExecCommand{Component: "my-container2"},
|
|
},
|
|
}
|
|
execCmdCont3 := v1alpha2.Command{
|
|
Id: "execCmdCont3",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Exec: &v1alpha2.ExecCommand{Component: "my-container3"},
|
|
},
|
|
}
|
|
applyCmdCont1 := v1alpha2.Command{
|
|
Id: "applyCmdCont1",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Apply: &v1alpha2.ApplyCommand{Component: "my-container1"},
|
|
},
|
|
}
|
|
applyCmdImg1 := v1alpha2.Command{
|
|
Id: "applyCmdImg1",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Apply: &v1alpha2.ApplyCommand{Component: "my-image1"},
|
|
},
|
|
}
|
|
applyK8s1 := v1alpha2.Command{
|
|
Id: "applyK8s1",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Apply: &v1alpha2.ApplyCommand{Component: "my-k8s"},
|
|
},
|
|
}
|
|
childCompositeCmd := v1alpha2.Command{
|
|
Id: "child-composite",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Composite: &v1alpha2.CompositeCommand{
|
|
Commands: []string{execCmdCont3.Id, applyK8s1.Id},
|
|
},
|
|
},
|
|
}
|
|
|
|
_ = devfileData.AddCommands([]v1alpha2.Command{
|
|
customCmd, execCmdCont1, execCmdCont2, execCmdCont3, applyCmdCont1, applyCmdImg1, applyK8s1, childCompositeCmd})
|
|
|
|
devfileObj := parser.DevfileObj{Data: devfileData}
|
|
|
|
type args struct {
|
|
cmd v1alpha2.Command
|
|
}
|
|
for _, tt := range []struct {
|
|
name string
|
|
args args
|
|
wantErr bool
|
|
want []string
|
|
}{
|
|
{
|
|
name: "zero -value command",
|
|
args: args{cmd: v1alpha2.Command{}},
|
|
},
|
|
{
|
|
name: "GetCommandType returning an error",
|
|
args: args{cmd: v1alpha2.Command{Id: "unknown"}},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "non-supported command type",
|
|
args: args{cmd: customCmd},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "exec command matching existing container component",
|
|
args: args{cmd: execCmdCont1},
|
|
want: []string{"my-container1"},
|
|
},
|
|
{
|
|
name: "exec command not matching existing container component",
|
|
args: args{
|
|
cmd: v1alpha2.Command{
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Exec: &v1alpha2.ExecCommand{Component: "my-k8s"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "apply command matching existing container component",
|
|
args: args{cmd: applyCmdCont1},
|
|
want: []string{"my-container1"},
|
|
},
|
|
{
|
|
name: "apply command not matching existing container component",
|
|
args: args{cmd: applyCmdImg1},
|
|
},
|
|
{
|
|
name: "composite command with one command missing not declared in Devfile commands",
|
|
args: args{
|
|
cmd: v1alpha2.Command{
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Composite: &v1alpha2.CompositeCommand{
|
|
Commands: []string{execCmdCont1.Id, "a-command-not-found-in-devfile"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "composite command with at least one unsupported component",
|
|
args: args{
|
|
cmd: v1alpha2.Command{
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Composite: &v1alpha2.CompositeCommand{
|
|
Commands: []string{childCompositeCmd.Id, customCmd.Id, applyCmdImg1.Id},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "composite command with no non-unsupported component",
|
|
args: args{
|
|
cmd: v1alpha2.Command{
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Composite: &v1alpha2.CompositeCommand{
|
|
Commands: []string{childCompositeCmd.Id, applyCmdImg1.Id, execCmdCont1.Id},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: []string{"my-container3", "my-container1"},
|
|
},
|
|
} {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := GetContainerComponentsForCommand(devfileObj, tt.args.cmd)
|
|
|
|
if tt.wantErr != (err != nil) {
|
|
t.Errorf("unexpected error, wantErr: %v, err: %v", tt.wantErr, err)
|
|
}
|
|
if diff := cmp.Diff(tt.want, got); diff != "" {
|
|
t.Errorf("GetContainerComponentsForCommand() mismatch (-want +got):\n%s", diff)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func getExecCommand(id string, group v1alpha2.CommandGroupKind) v1alpha2.Command {
|
|
if len(id) == 0 {
|
|
id = fmt.Sprintf("%s-%s", "cmd", dfutil.GenerateRandomString(10))
|
|
}
|
|
commands := [...]string{"ls -la", "pwd"}
|
|
components := [...]string{"alias1", "alias2"}
|
|
workDir := [...]string{"/", "/root"}
|
|
|
|
return v1alpha2.Command{
|
|
Id: id,
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Exec: &v1alpha2.ExecCommand{
|
|
LabeledCommand: v1alpha2.LabeledCommand{
|
|
BaseCommand: v1alpha2.BaseCommand{
|
|
Group: &v1alpha2.CommandGroup{Kind: group},
|
|
},
|
|
},
|
|
CommandLine: commands[0],
|
|
Component: components[0],
|
|
WorkingDir: workDir[0],
|
|
},
|
|
},
|
|
}
|
|
|
|
}
|