mirror of
https://github.com/redhat-developer/odo.git
synced 2025-10-19 03:06:19 +03:00
* Add sample Devfile with multiple autoBuild/deployByDefault combinations It will be used for integration tests. * Add helper function to update a given Devfile Command Group This will allow supporting cases where we need to run a custom command, but this is not implemented yet on odo (cases with 'odo dev --debug' and 'odo deploy'). In this case, this helper will allow updating the Devfile for example to unmark the current default command as non-default, and mark the custom one as default. * Add test cases for 'odo dev' * Add test cases for 'odo deploy' * Add test cases for 'odo build-images' 'odo build-images' should build all images regardless of the 'autoBuild' property. * Display the spinner when creating or updating Kubernetes resources This helps understand what resources are being patched. * Handle deployByDefault on K8s and OpenShift components * Add 'devfile.GetImageComponentsToPush' functions that returns the list of image components to auto-create See https://github.com/devfile/api/issues/852#issuecomment-1211928487 for more context. * Handle automatic image component creation for 'odo dev' on Kubernetes * Handle automatic image component creation for 'odo dev' on Podman * Handle automatic image and K8s/OpenShift component creation for 'odo deploy' * Bump Devfile library to the latest commit at this time (c1b23d2) This includes the fix for [1], which provides a way not to set default values automatically [1] https://github.com/devfile/api/issues/1067 * Do not set default values when parsing a Devfile See [1] for the rationale [1] https://github.com/redhat-developer/odo/issues/5694\#issuecomment-1465778398 * Add documentation in the Devfile reference page * Revert "Display the spinner when creating or updating Kubernetes resources" This reverts commit 6ad073e63cb0e685f165eed767619a90997393a3. * Avoid re-applying Image components multiple times 'adapter#Push' might get called several times when there are state transitions (either on the Deployment in the cluster, or from 'odo'). It might be confusing to apply Image components over and over again (and also it can be slower if we need to push images to remote registries). * Move GetK8sAndOcComponentsToPush and GetImageComponentsToPush to libdevfile package As suggested in review, this should be the responsibility of the devfile library Co-authored-by: Philippe Martin <phmartin@redhat.com> * fixup! Handle automatic image and K8s/OpenShift component creation for 'odo deploy' * fixup! Handle automatic image component creation for 'odo dev' on Podman * fixup! Avoid re-applying Image components multiple times * Apply suggestions from code review Co-authored-by: Parthvi Vala <pvala@redhat.com> * fixup! Do not set default values when parsing a Devfile * Fix devfile-deploy-functional-pods.yaml (used in 'odo logs' tests) Set deployByDefault to false on innerloop-pod component. Otherwise, since it is not referenced by any apply command, it will be automatically created by *both* 'odo dev' and 'odo deploy'. --------- Co-authored-by: Philippe Martin <phmartin@redhat.com> Co-authored-by: Parthvi Vala <pvala@redhat.com>
255 lines
8.0 KiB
Go
255 lines
8.0 KiB
Go
package libdevfile
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
|
|
devfilepkg "github.com/devfile/api/v2/pkg/devfile"
|
|
"github.com/devfile/library/v2/pkg/devfile/parser"
|
|
devfileCtx "github.com/devfile/library/v2/pkg/devfile/parser/context"
|
|
"github.com/devfile/library/v2/pkg/devfile/parser/data"
|
|
devfileFileSystem "github.com/devfile/library/v2/pkg/testingutil/filesystem"
|
|
"github.com/google/go-cmp/cmp"
|
|
"github.com/google/go-cmp/cmp/cmpopts"
|
|
"k8s.io/utils/pointer"
|
|
|
|
devfiletesting "github.com/redhat-developer/odo/pkg/devfile/testing"
|
|
)
|
|
|
|
func TestGetK8sAndOcComponentsToPush(t *testing.T) {
|
|
fs := devfileFileSystem.NewFakeFs()
|
|
|
|
buildK8sOrOcComponent := func(k8s bool, name string, deployByDefault *bool, referenced bool) (v1alpha2.Component, v1alpha2.Command) {
|
|
k8sLikeComponent := v1alpha2.K8sLikeComponent{
|
|
DeployByDefault: deployByDefault,
|
|
K8sLikeComponentLocation: v1alpha2.K8sLikeComponentLocation{
|
|
Inlined: name,
|
|
},
|
|
}
|
|
comp := v1alpha2.Component{Name: name}
|
|
if k8s {
|
|
comp.ComponentUnion.Kubernetes = &v1alpha2.KubernetesComponent{K8sLikeComponent: k8sLikeComponent}
|
|
} else {
|
|
comp.ComponentUnion.Openshift = &v1alpha2.OpenshiftComponent{K8sLikeComponent: k8sLikeComponent}
|
|
}
|
|
if referenced {
|
|
cmd := v1alpha2.Command{
|
|
Id: "apply-" + name,
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Apply: &v1alpha2.ApplyCommand{
|
|
Component: name,
|
|
},
|
|
},
|
|
}
|
|
return comp, cmd
|
|
}
|
|
return comp, v1alpha2.Command{}
|
|
}
|
|
|
|
var (
|
|
k8sDeployByDefaultTrueReferenced, applyK8sDeployByDefaultTrueReferenced = buildK8sOrOcComponent(
|
|
true, "k8sDeployByDefaultTrueReferenced", pointer.Bool(true), true)
|
|
ocDeployByDefaultTrueReferenced, applyOcDeployByDefaultTrueReferenced = buildK8sOrOcComponent(
|
|
false, "ocDeployByDefaultTrueReferenced", pointer.Bool(true), true)
|
|
|
|
k8sDeployByDefaultTrueNotReferenced, _ = buildK8sOrOcComponent(
|
|
true, "k8sDeployByDefaultTrueNotReferenced", pointer.Bool(true), false)
|
|
ocDeployByDefaultTrueNotReferenced, _ = buildK8sOrOcComponent(
|
|
false, "ocDeployByDefaultTrueNotReferenced", pointer.Bool(true), false)
|
|
|
|
k8sDeployByDefaultFalseReferenced, applyK8sDeployByDefaultFalseReferenced = buildK8sOrOcComponent(
|
|
true, "k8sDeployByDefaultFalseReferenced", pointer.Bool(false), true)
|
|
ocDeployByDefaultFalseReferenced, applyOcDeployByDefaultFalseReferenced = buildK8sOrOcComponent(
|
|
false, "ocDeployByDefaultFalseReferenced", pointer.Bool(false), true)
|
|
|
|
k8sDeployByDefaultFalseNotReferenced, _ = buildK8sOrOcComponent(
|
|
true, "k8sDeployByDefaultFalseNotReferenced", pointer.Bool(false), false)
|
|
ocDeployByDefaultFalseNotReferenced, _ = buildK8sOrOcComponent(
|
|
false, "ocDeployByDefaultFalseNotReferenced", pointer.Bool(false), false)
|
|
|
|
k8sDeployByDefaultNotSetReferenced, applyK8sDeployByDefaultNotSetReferenced = buildK8sOrOcComponent(
|
|
true, "k8sDeployByDefaultNotSetReferenced", nil, true)
|
|
ocDeployByDefaultNotSetReferenced, applyOcDeployByDefaultNotSetReferenced = buildK8sOrOcComponent(
|
|
false, "ocDeployByDefaultNotSetReferenced", nil, true)
|
|
|
|
k8sDeployByDefaultNotSetNotReferenced, _ = buildK8sOrOcComponent(
|
|
true, "k8sDeployByDefaultNotSetNotReferenced", nil, false)
|
|
ocDeployByDefaultNotSetNotReferenced, _ = buildK8sOrOcComponent(
|
|
false, "ocDeployByDefaultNotSetNotReferenced", nil, false)
|
|
)
|
|
|
|
buildFullDevfile := func() (parser.DevfileObj, error) {
|
|
devfileData, err := data.NewDevfileData(string(data.APISchemaVersion220))
|
|
if err != nil {
|
|
return parser.DevfileObj{}, err
|
|
}
|
|
devfileData.SetMetadata(devfilepkg.DevfileMetadata{Name: "my-devfile"})
|
|
err = devfileData.AddComponents([]v1alpha2.Component{
|
|
k8sDeployByDefaultNotSetNotReferenced,
|
|
k8sDeployByDefaultNotSetReferenced,
|
|
ocDeployByDefaultNotSetReferenced,
|
|
ocDeployByDefaultNotSetNotReferenced,
|
|
|
|
k8sDeployByDefaultTrueNotReferenced,
|
|
k8sDeployByDefaultTrueReferenced,
|
|
ocDeployByDefaultTrueReferenced,
|
|
ocDeployByDefaultTrueNotReferenced,
|
|
|
|
k8sDeployByDefaultFalseNotReferenced,
|
|
k8sDeployByDefaultFalseReferenced,
|
|
ocDeployByDefaultFalseReferenced,
|
|
ocDeployByDefaultFalseNotReferenced,
|
|
|
|
//Add other kinds of components
|
|
{
|
|
Name: "my-image-component",
|
|
ComponentUnion: v1alpha2.ComponentUnion{
|
|
Image: &v1alpha2.ImageComponent{
|
|
Image: v1alpha2.Image{
|
|
ImageName: "image-component-1",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "container-component",
|
|
ComponentUnion: v1alpha2.ComponentUnion{
|
|
Container: &v1alpha2.ContainerComponent{
|
|
Container: v1alpha2.Container{
|
|
DedicatedPod: pointer.Bool(true),
|
|
Image: "my-container-image",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
if err != nil {
|
|
return parser.DevfileObj{}, err
|
|
}
|
|
err = devfileData.AddCommands([]v1alpha2.Command{
|
|
applyK8sDeployByDefaultNotSetReferenced,
|
|
applyOcDeployByDefaultNotSetReferenced,
|
|
applyK8sDeployByDefaultTrueReferenced,
|
|
applyOcDeployByDefaultTrueReferenced,
|
|
applyK8sDeployByDefaultFalseReferenced,
|
|
applyOcDeployByDefaultFalseReferenced,
|
|
|
|
//Add other kinds of components
|
|
{
|
|
Id: "apply-image",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Apply: &v1alpha2.ApplyCommand{
|
|
Component: "my-image-component",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Id: "exec-command",
|
|
CommandUnion: v1alpha2.CommandUnion{
|
|
Apply: &v1alpha2.ApplyCommand{
|
|
Component: "my-image-component",
|
|
},
|
|
Exec: &v1alpha2.ExecCommand{
|
|
CommandLine: "/path/to/my/command -success",
|
|
Component: "container-component",
|
|
},
|
|
},
|
|
},
|
|
})
|
|
if err != nil {
|
|
return parser.DevfileObj{}, err
|
|
}
|
|
return parser.DevfileObj{
|
|
Ctx: devfileCtx.FakeContext(fs, parser.OutputDevfileYamlPath),
|
|
Data: devfileData,
|
|
}, nil
|
|
}
|
|
|
|
type args struct {
|
|
devfileObj func() (parser.DevfileObj, error)
|
|
allowApply bool
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want []v1alpha2.Component
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "empty devfile",
|
|
args: args{
|
|
devfileObj: func() (parser.DevfileObj, error) {
|
|
return parser.DevfileObj{
|
|
Data: devfiletesting.GetDevfileData(t, nil, nil),
|
|
Ctx: devfileCtx.FakeContext(fs, parser.OutputDevfileYamlPath),
|
|
}, nil
|
|
},
|
|
},
|
|
want: []v1alpha2.Component{},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "allowApply=false => return components that need to be created automatically on startup",
|
|
args: args{
|
|
devfileObj: buildFullDevfile,
|
|
allowApply: false,
|
|
},
|
|
want: []v1alpha2.Component{
|
|
k8sDeployByDefaultTrueNotReferenced,
|
|
k8sDeployByDefaultTrueReferenced,
|
|
ocDeployByDefaultTrueNotReferenced,
|
|
ocDeployByDefaultTrueReferenced,
|
|
k8sDeployByDefaultNotSetNotReferenced,
|
|
ocDeployByDefaultNotSetNotReferenced,
|
|
},
|
|
},
|
|
{
|
|
name: "allowApply=true => return components that need to be created automatically on startup and those referenced",
|
|
args: args{
|
|
devfileObj: buildFullDevfile,
|
|
allowApply: true,
|
|
},
|
|
want: []v1alpha2.Component{
|
|
k8sDeployByDefaultTrueNotReferenced,
|
|
k8sDeployByDefaultTrueReferenced,
|
|
ocDeployByDefaultTrueNotReferenced,
|
|
ocDeployByDefaultTrueReferenced,
|
|
k8sDeployByDefaultNotSetNotReferenced,
|
|
ocDeployByDefaultNotSetNotReferenced,
|
|
|
|
k8sDeployByDefaultFalseReferenced,
|
|
ocDeployByDefaultFalseReferenced,
|
|
k8sDeployByDefaultNotSetReferenced,
|
|
ocDeployByDefaultNotSetReferenced,
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
devfileObj, err := tt.args.devfileObj()
|
|
if err != nil {
|
|
t.Errorf("unable to create Devfile object: %v", err)
|
|
return
|
|
}
|
|
got, err := GetK8sAndOcComponentsToPush(devfileObj, tt.args.allowApply)
|
|
gotErr := err != nil
|
|
if gotErr != tt.wantErr {
|
|
t.Errorf("Got error %v, expected %v\n", err, tt.wantErr)
|
|
}
|
|
|
|
if len(got) != len(tt.want) {
|
|
t.Errorf("Got %d components, expected %d\n", len(got), len(tt.want))
|
|
}
|
|
|
|
lessFn := func(x, y v1alpha2.Component) bool {
|
|
return x.Name < y.Name
|
|
}
|
|
if diff := cmp.Diff(tt.want, got, cmpopts.EquateEmpty(), cmpopts.SortSlices(lessFn)); diff != "" {
|
|
t.Errorf("GetK8sAndOcComponentsToPush() mismatch (-want +got):\n%s", diff)
|
|
}
|
|
})
|
|
}
|
|
}
|