mirror of
https://github.com/redhat-developer/odo.git
synced 2025-10-19 03:06:19 +03:00
733 lines
26 KiB
Go
733 lines
26 KiB
Go
package delete
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
|
|
"github.com/devfile/library/pkg/devfile/parser"
|
|
"github.com/devfile/library/pkg/testingutil/filesystem"
|
|
"github.com/golang/mock/gomock"
|
|
"github.com/google/go-cmp/cmp"
|
|
appsv1 "k8s.io/api/apps/v1"
|
|
corev1 "k8s.io/api/core/v1"
|
|
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
|
"k8s.io/apimachinery/pkg/api/meta"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
|
|
"github.com/redhat-developer/odo/pkg/exec"
|
|
"github.com/redhat-developer/odo/pkg/kclient"
|
|
odolabels "github.com/redhat-developer/odo/pkg/labels"
|
|
odocontext "github.com/redhat-developer/odo/pkg/odo/context"
|
|
odoTestingUtil "github.com/redhat-developer/odo/pkg/testingutil"
|
|
"github.com/redhat-developer/odo/pkg/util"
|
|
)
|
|
|
|
const (
|
|
appName = "app"
|
|
)
|
|
|
|
func TestDeleteComponentClient_ListClusterResourcesToDelete(t *testing.T) {
|
|
res1 := getUnstructured("dep1", "deployment", "v1", "")
|
|
res2 := getUnstructured("svc1", "service", "v1", "")
|
|
|
|
type fields struct {
|
|
kubeClient func(ctrl *gomock.Controller) kclient.ClientInterface
|
|
}
|
|
type args struct {
|
|
componentName string
|
|
namespace string
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
args args
|
|
want []unstructured.Unstructured
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "no resource found",
|
|
fields: fields{
|
|
kubeClient: func(ctrl *gomock.Controller) kclient.ClientInterface {
|
|
client := kclient.NewMockClientInterface(ctrl)
|
|
selector := "app.kubernetes.io/instance=my-component,app.kubernetes.io/managed-by=odo,app.kubernetes.io/part-of=app"
|
|
client.EXPECT().GetAllResourcesFromSelector(selector, "my-ns").Return(nil, nil)
|
|
return client
|
|
},
|
|
},
|
|
args: args{
|
|
componentName: "my-component",
|
|
namespace: "my-ns",
|
|
},
|
|
wantErr: false,
|
|
want: nil,
|
|
},
|
|
{
|
|
name: "2 unrelated resources found",
|
|
fields: fields{
|
|
kubeClient: func(ctrl *gomock.Controller) kclient.ClientInterface {
|
|
var resources []unstructured.Unstructured
|
|
resources = append(resources, res1, res2)
|
|
client := kclient.NewMockClientInterface(ctrl)
|
|
selector := "app.kubernetes.io/instance=my-component,app.kubernetes.io/managed-by=odo,app.kubernetes.io/part-of=app"
|
|
client.EXPECT().GetAllResourcesFromSelector(selector, "my-ns").Return(resources, nil)
|
|
return client
|
|
},
|
|
},
|
|
args: args{
|
|
componentName: "my-component",
|
|
namespace: "my-ns",
|
|
},
|
|
wantErr: false,
|
|
want: []unstructured.Unstructured{res1, res2},
|
|
},
|
|
{
|
|
name: "2 resources found, one owned by the other",
|
|
fields: fields{
|
|
kubeClient: func(ctrl *gomock.Controller) kclient.ClientInterface {
|
|
var resources []unstructured.Unstructured
|
|
res1.SetOwnerReferences([]metav1.OwnerReference{
|
|
{
|
|
APIVersion: res2.GetAPIVersion(),
|
|
Kind: res2.GetKind(),
|
|
Name: res2.GetName(),
|
|
},
|
|
})
|
|
resources = append(resources, res1, res2)
|
|
client := kclient.NewMockClientInterface(ctrl)
|
|
selector := "app.kubernetes.io/instance=my-component,app.kubernetes.io/managed-by=odo,app.kubernetes.io/part-of=app"
|
|
client.EXPECT().GetAllResourcesFromSelector(selector, "my-ns").Return(resources, nil)
|
|
return client
|
|
},
|
|
},
|
|
args: args{
|
|
componentName: "my-component",
|
|
namespace: "my-ns",
|
|
},
|
|
wantErr: false,
|
|
want: []unstructured.Unstructured{res2},
|
|
},
|
|
// TODO: Add test cases.
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
ctrl := gomock.NewController(t)
|
|
kubeClient := tt.fields.kubeClient(ctrl)
|
|
execClient := exec.NewExecClient(kubeClient)
|
|
do := NewDeleteComponentClient(kubeClient, execClient)
|
|
ctx := odocontext.WithApplication(context.TODO(), "app")
|
|
got, err := do.ListClusterResourcesToDelete(ctx, tt.args.componentName, tt.args.namespace)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("DeleteComponentClient.ListResourcesToDelete() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if diff := cmp.Diff(tt.want, got); diff != "" {
|
|
t.Errorf("DeleteComponentClient.ListClusterResourcesToDelete() mismatch (-want +got):\n%s", diff)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDeleteComponentClient_DeleteResources(t *testing.T) {
|
|
res1 := getUnstructured("dep1", "deployment", "v1", "")
|
|
res2 := getUnstructured("svc1", "service", "v1", "")
|
|
|
|
type fields struct {
|
|
kubeClient func(ctrl *gomock.Controller) kclient.ClientInterface
|
|
}
|
|
type args struct {
|
|
resources []unstructured.Unstructured
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
args args
|
|
want []unstructured.Unstructured
|
|
}{
|
|
{
|
|
name: "2 resources deleted succesfully",
|
|
fields: fields{
|
|
kubeClient: func(ctrl *gomock.Controller) kclient.ClientInterface {
|
|
client := kclient.NewMockClientInterface(ctrl)
|
|
client.EXPECT().GetRestMappingFromUnstructured(res1).Return(&meta.RESTMapping{
|
|
Resource: schema.GroupVersionResource{
|
|
Group: "",
|
|
Version: "v1",
|
|
Resource: res1.GetKind(),
|
|
},
|
|
}, nil)
|
|
client.EXPECT().GetRestMappingFromUnstructured(res2).Return(&meta.RESTMapping{
|
|
Resource: schema.GroupVersionResource{
|
|
Group: "",
|
|
Version: "v1",
|
|
Resource: res2.GetKind(),
|
|
},
|
|
}, nil)
|
|
client.EXPECT().DeleteDynamicResource(res1.GetName(), getGVR("", "v1", res1.GetKind()), false)
|
|
client.EXPECT().DeleteDynamicResource(res2.GetName(), getGVR("", "v1", res2.GetKind()), false)
|
|
return client
|
|
},
|
|
},
|
|
args: args{
|
|
resources: []unstructured.Unstructured{res1, res2},
|
|
},
|
|
want: nil,
|
|
},
|
|
{
|
|
name: "2 resources, 1 deleted succesfully, 1 failed during restmapping",
|
|
fields: fields{
|
|
kubeClient: func(ctrl *gomock.Controller) kclient.ClientInterface {
|
|
client := kclient.NewMockClientInterface(ctrl)
|
|
client.EXPECT().GetRestMappingFromUnstructured(res1).Return(nil, errors.New("some restmapping error"))
|
|
client.EXPECT().GetRestMappingFromUnstructured(res2).Return(&meta.RESTMapping{
|
|
Resource: schema.GroupVersionResource{
|
|
Group: "",
|
|
Version: "v1",
|
|
Resource: res2.GetKind(),
|
|
},
|
|
}, nil)
|
|
client.EXPECT().DeleteDynamicResource(res2.GetName(), getGVR("", "v1", res2.GetKind()), false)
|
|
return client
|
|
},
|
|
},
|
|
args: args{
|
|
resources: []unstructured.Unstructured{res1, res2},
|
|
},
|
|
want: []unstructured.Unstructured{res1},
|
|
},
|
|
{
|
|
name: "2 resources, 1 deleted succesfully, 1 failed during deletion",
|
|
fields: fields{
|
|
kubeClient: func(ctrl *gomock.Controller) kclient.ClientInterface {
|
|
client := kclient.NewMockClientInterface(ctrl)
|
|
client.EXPECT().GetRestMappingFromUnstructured(res1).Return(&meta.RESTMapping{
|
|
Resource: schema.GroupVersionResource{
|
|
Group: "",
|
|
Version: "v1",
|
|
Resource: res1.GetKind(),
|
|
},
|
|
}, nil)
|
|
client.EXPECT().GetRestMappingFromUnstructured(res2).Return(&meta.RESTMapping{
|
|
Resource: schema.GroupVersionResource{
|
|
Group: "",
|
|
Version: "v1",
|
|
Resource: res2.GetKind(),
|
|
},
|
|
}, nil)
|
|
client.EXPECT().DeleteDynamicResource(res1.GetName(), getGVR("", "v1", res1.GetKind()), false).Return(errors.New("some error"))
|
|
client.EXPECT().DeleteDynamicResource(res2.GetName(), getGVR("", "v1", res2.GetKind()), false)
|
|
return client
|
|
},
|
|
},
|
|
args: args{
|
|
resources: []unstructured.Unstructured{res1, res2},
|
|
},
|
|
want: []unstructured.Unstructured{res1},
|
|
},
|
|
// TODO: Add test cases.
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
ctrl := gomock.NewController(t)
|
|
kubeClient := tt.fields.kubeClient(ctrl)
|
|
execClient := exec.NewExecClient(kubeClient)
|
|
do := NewDeleteComponentClient(kubeClient, execClient)
|
|
got := do.DeleteResources(tt.args.resources, false)
|
|
if diff := cmp.Diff(tt.want, got); diff != "" {
|
|
t.Errorf("DeleteComponentClient.DeleteResources() mismatch (-want +got):\n%s", diff)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDeleteComponentClient_ListResourcesToDeleteFromDevfile(t *testing.T) {
|
|
const compName = "nodejs-prj1-api-abhz"
|
|
innerLoopCoreDeploymentName, _ := util.NamespaceKubernetesObject(compName, appName)
|
|
|
|
// innerLoopCoreDeployment is the deployment created by odo dev for the component
|
|
innerLoopCoreDeployment := odoTestingUtil.CreateFakeDeployment(compName, true)
|
|
|
|
innerLoopCoreDeploymentUnstructured, e := kclient.ConvertK8sResourceToUnstructured(innerLoopCoreDeployment)
|
|
if e != nil {
|
|
t.Errorf("unable to convert deployment to unstructured")
|
|
}
|
|
|
|
// outerLoopResourceUnstructured is the deployment created by odo deploy
|
|
outerLoopResourceUnstructured := unstructured.Unstructured{
|
|
Object: map[string]interface{}{
|
|
"apiVersion": "apps/v1",
|
|
"kind": "Deployment",
|
|
"metadata": map[string]interface{}{
|
|
"name": "my-component",
|
|
},
|
|
"spec": map[string]interface{}{
|
|
"replicas": float64(1),
|
|
"selector": map[string]interface{}{
|
|
"matchLabels": map[string]interface{}{
|
|
"app": "node-app",
|
|
},
|
|
},
|
|
"template": map[string]interface{}{
|
|
"metadata": map[string]interface{}{
|
|
"labels": map[string]interface{}{
|
|
"app": "node-app",
|
|
},
|
|
},
|
|
"spec": map[string]interface{}{
|
|
"containers": []interface{}{
|
|
map[string]interface{}{
|
|
"image": "quay.io/unknown-account/myimage",
|
|
"name": "main",
|
|
"resources": map[string]interface{}{
|
|
"limits": map[string]interface{}{
|
|
"cpu": "500m",
|
|
"memory": "128Mi",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
// labeledOuterloopResource is the deployment with labels set
|
|
labeledOuterloopResource := *outerLoopResourceUnstructured.DeepCopy()
|
|
labeledOuterloopResource.SetLabels(odolabels.GetLabels(compName, appName, "", odolabels.ComponentDeployMode, false))
|
|
|
|
// innerLoopResourceUnstructured is the deployment that will be deployed by apply command with `odo dev`
|
|
innerLoopResourceUnstructured := *outerLoopResourceUnstructured.DeepCopy()
|
|
innerLoopResourceUnstructured.SetLabels(odolabels.GetLabels(compName, appName, "", odolabels.ComponentDevMode, false))
|
|
|
|
deploymentRESTMapping := meta.RESTMapping{
|
|
Resource: getGVR("apps", "v1", "Deployment"),
|
|
}
|
|
|
|
type fields struct {
|
|
kubeClient func(ctrl *gomock.Controller) kclient.ClientInterface
|
|
}
|
|
type args struct {
|
|
devfileObj parser.DevfileObj
|
|
appName string
|
|
mode string
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
args args
|
|
wantIsInnerLoopDeployed bool
|
|
wantResources []unstructured.Unstructured
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "list innerloop core resource(deployment), and outerloop resources",
|
|
fields: fields{
|
|
kubeClient: func(ctrl *gomock.Controller) kclient.ClientInterface {
|
|
kubeClient := kclient.NewMockClientInterface(ctrl)
|
|
|
|
kubeClient.EXPECT().GetDeploymentByName(innerLoopCoreDeploymentName).Return(innerLoopCoreDeployment, nil)
|
|
|
|
kubeClient.EXPECT().GetRestMappingFromUnstructured(outerLoopResourceUnstructured).Return(&deploymentRESTMapping, nil)
|
|
kubeClient.EXPECT().
|
|
GetDynamicResource(deploymentRESTMapping.Resource, outerLoopResourceUnstructured.GetName()).
|
|
Return(&labeledOuterloopResource, nil)
|
|
|
|
return kubeClient
|
|
},
|
|
},
|
|
args: args{
|
|
devfileObj: odoTestingUtil.GetTestDevfileObjFromFile("devfile-deploy.yaml"),
|
|
appName: appName,
|
|
mode: odolabels.ComponentAnyMode,
|
|
},
|
|
wantIsInnerLoopDeployed: true,
|
|
wantResources: []unstructured.Unstructured{innerLoopCoreDeploymentUnstructured, labeledOuterloopResource},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "list innerloop core resource(deployment) only",
|
|
fields: fields{
|
|
kubeClient: func(ctrl *gomock.Controller) kclient.ClientInterface {
|
|
kubeClient := kclient.NewMockClientInterface(ctrl)
|
|
|
|
kubeClient.EXPECT().GetDeploymentByName(innerLoopCoreDeploymentName).Return(innerLoopCoreDeployment, nil)
|
|
return kubeClient
|
|
},
|
|
},
|
|
args: args{
|
|
devfileObj: func() parser.DevfileObj {
|
|
obj := odoTestingUtil.GetTestDevfileObjFromFile("devfile.yaml")
|
|
// change the metadata name to the desired one since devfile.yaml has a different name
|
|
metadata := obj.Data.GetMetadata()
|
|
metadata.Name = compName
|
|
obj.Data.SetMetadata(metadata)
|
|
return obj
|
|
}(),
|
|
appName: appName,
|
|
mode: odolabels.ComponentDevMode,
|
|
},
|
|
wantIsInnerLoopDeployed: true,
|
|
wantResources: []unstructured.Unstructured{innerLoopCoreDeploymentUnstructured},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "list innerloop core resources(deployment), another innerloop resources",
|
|
fields: fields{
|
|
kubeClient: func(ctrl *gomock.Controller) kclient.ClientInterface {
|
|
kubeClient := kclient.NewMockClientInterface(ctrl)
|
|
|
|
kubeClient.EXPECT().GetDeploymentByName(innerLoopCoreDeploymentName).Return(innerLoopCoreDeployment, nil)
|
|
|
|
kubeClient.EXPECT().GetRestMappingFromUnstructured(outerLoopResourceUnstructured).Return(&deploymentRESTMapping, nil)
|
|
kubeClient.EXPECT().
|
|
GetDynamicResource(deploymentRESTMapping.Resource, outerLoopResourceUnstructured.GetName()).
|
|
Return(&innerLoopResourceUnstructured, nil)
|
|
|
|
return kubeClient
|
|
},
|
|
},
|
|
args: args{
|
|
devfileObj: func() parser.DevfileObj {
|
|
obj := odoTestingUtil.GetTestDevfileObjFromFile("devfile-composite-apply-commands.yaml")
|
|
// change the metadata name to the desired one since devfile.yaml has a different name
|
|
metadata := obj.Data.GetMetadata()
|
|
metadata.Name = compName
|
|
obj.Data.SetMetadata(metadata)
|
|
return obj
|
|
}(),
|
|
appName: appName,
|
|
mode: odolabels.ComponentDevMode,
|
|
},
|
|
wantIsInnerLoopDeployed: true,
|
|
wantResources: []unstructured.Unstructured{innerLoopCoreDeploymentUnstructured, innerLoopResourceUnstructured},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "list outerloop resources only",
|
|
fields: fields{
|
|
kubeClient: func(ctrl *gomock.Controller) kclient.ClientInterface {
|
|
kubeClient := kclient.NewMockClientInterface(ctrl)
|
|
|
|
kubeClient.EXPECT().GetDeploymentByName(innerLoopCoreDeploymentName).
|
|
Return(&appsv1.Deployment{}, kerrors.NewNotFound(deploymentRESTMapping.Resource.GroupResource(), innerLoopCoreDeploymentName))
|
|
kubeClient.EXPECT().GetRestMappingFromUnstructured(outerLoopResourceUnstructured).Return(&deploymentRESTMapping, nil)
|
|
kubeClient.EXPECT().
|
|
GetDynamicResource(deploymentRESTMapping.Resource, outerLoopResourceUnstructured.GetName()).
|
|
Return(&labeledOuterloopResource, nil)
|
|
return kubeClient
|
|
},
|
|
},
|
|
args: args{
|
|
devfileObj: odoTestingUtil.GetTestDevfileObjFromFile("devfile-deploy.yaml"),
|
|
appName: appName,
|
|
mode: odolabels.ComponentAnyMode,
|
|
},
|
|
wantIsInnerLoopDeployed: false,
|
|
wantResources: []unstructured.Unstructured{labeledOuterloopResource},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "list uri-referenced outerloop resources",
|
|
fields: fields{
|
|
kubeClient: func(ctrl *gomock.Controller) kclient.ClientInterface {
|
|
kubeClient := kclient.NewMockClientInterface(ctrl)
|
|
kubeClient.EXPECT().GetDeploymentByName(innerLoopCoreDeploymentName).
|
|
Return(&appsv1.Deployment{}, kerrors.NewNotFound(schema.GroupResource{Group: "apps", Resource: "Deployments"}, innerLoopCoreDeploymentName))
|
|
kubeClient.EXPECT().GetRestMappingFromUnstructured(outerLoopResourceUnstructured).Return(&deploymentRESTMapping, nil)
|
|
kubeClient.EXPECT().
|
|
GetDynamicResource(deploymentRESTMapping.Resource, outerLoopResourceUnstructured.GetName()).
|
|
Return(&labeledOuterloopResource, nil)
|
|
return kubeClient
|
|
},
|
|
},
|
|
args: args{
|
|
devfileObj: odoTestingUtil.GetTestDevfileObjFromFile("devfile-deploy-with-k8s-uri.yaml"),
|
|
appName: appName,
|
|
mode: odolabels.ComponentAnyMode,
|
|
},
|
|
wantIsInnerLoopDeployed: false,
|
|
wantResources: []unstructured.Unstructured{labeledOuterloopResource},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "fetching inner loop resource failed due to some error(!NotFoundError)",
|
|
fields: fields{
|
|
kubeClient: func(ctrl *gomock.Controller) kclient.ClientInterface {
|
|
kubeClient := kclient.NewMockClientInterface(ctrl)
|
|
kubeClient.EXPECT().GetDeploymentByName(innerLoopCoreDeploymentName).Return(&appsv1.Deployment{}, errors.New("some error"))
|
|
return kubeClient
|
|
},
|
|
},
|
|
args: args{
|
|
devfileObj: odoTestingUtil.GetTestDevfileObjFromFile("devfile-deploy.yaml"),
|
|
appName: appName,
|
|
mode: odolabels.ComponentAnyMode,
|
|
},
|
|
wantIsInnerLoopDeployed: false,
|
|
wantResources: nil,
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "failed to add outerloop resource to the list because kubeclient.GetRestMappingFromUnstructured() failed",
|
|
fields: fields{
|
|
kubeClient: func(ctrl *gomock.Controller) kclient.ClientInterface {
|
|
kubeClient := kclient.NewMockClientInterface(ctrl)
|
|
kubeClient.EXPECT().GetDeploymentByName(innerLoopCoreDeploymentName).Return(innerLoopCoreDeployment, nil)
|
|
kubeClient.EXPECT().GetRestMappingFromUnstructured(outerLoopResourceUnstructured).Return(nil, errors.New("some error"))
|
|
return kubeClient
|
|
},
|
|
},
|
|
args: args{
|
|
devfileObj: odoTestingUtil.GetTestDevfileObjFromFile("devfile-deploy.yaml"),
|
|
appName: appName,
|
|
mode: odolabels.ComponentAnyMode,
|
|
},
|
|
wantIsInnerLoopDeployed: true,
|
|
wantResources: []unstructured.Unstructured{innerLoopCoreDeploymentUnstructured},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "failed to add outerloop resource to the list because kubeclient.GetDynamicResource() failed",
|
|
fields: fields{
|
|
kubeClient: func(ctrl *gomock.Controller) kclient.ClientInterface {
|
|
kubeClient := kclient.NewMockClientInterface(ctrl)
|
|
kubeClient.EXPECT().GetDeploymentByName(innerLoopCoreDeploymentName).Return(innerLoopCoreDeployment, nil)
|
|
kubeClient.EXPECT().GetRestMappingFromUnstructured(outerLoopResourceUnstructured).Return(&deploymentRESTMapping, nil)
|
|
kubeClient.EXPECT().
|
|
GetDynamicResource(deploymentRESTMapping.Resource, outerLoopResourceUnstructured.GetName()).
|
|
Return(nil, errors.New("some error"))
|
|
return kubeClient
|
|
},
|
|
},
|
|
args: args{
|
|
devfileObj: odoTestingUtil.GetTestDevfileObjFromFile("devfile-deploy.yaml"),
|
|
appName: appName,
|
|
mode: odolabels.ComponentAnyMode,
|
|
},
|
|
wantIsInnerLoopDeployed: true,
|
|
wantResources: []unstructured.Unstructured{innerLoopCoreDeploymentUnstructured},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "do not list outerloop resource if Dev mode is asked",
|
|
fields: fields{
|
|
kubeClient: func(ctrl *gomock.Controller) kclient.ClientInterface {
|
|
kubeClient := kclient.NewMockClientInterface(ctrl)
|
|
|
|
kubeClient.EXPECT().GetDeploymentByName(innerLoopCoreDeploymentName).Return(innerLoopCoreDeployment, nil)
|
|
|
|
kubeClient.EXPECT().GetRestMappingFromUnstructured(outerLoopResourceUnstructured).Return(&deploymentRESTMapping, nil)
|
|
kubeClient.EXPECT().
|
|
GetDynamicResource(deploymentRESTMapping.Resource, outerLoopResourceUnstructured.GetName()).
|
|
Return(&outerLoopResourceUnstructured, nil)
|
|
|
|
return kubeClient
|
|
},
|
|
},
|
|
args: args{
|
|
devfileObj: func() parser.DevfileObj {
|
|
obj := odoTestingUtil.GetTestDevfileObjFromFile("devfile-composite-apply-commands.yaml")
|
|
// change the metadata name to the desired one since devfile.yaml has a different name
|
|
metadata := obj.Data.GetMetadata()
|
|
metadata.Name = compName
|
|
obj.Data.SetMetadata(metadata)
|
|
return obj
|
|
}(),
|
|
appName: appName,
|
|
mode: odolabels.ComponentDevMode,
|
|
},
|
|
wantIsInnerLoopDeployed: true,
|
|
wantResources: []unstructured.Unstructured{innerLoopCoreDeploymentUnstructured},
|
|
wantErr: false,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
ctrl := gomock.NewController(t)
|
|
do := DeleteComponentClient{
|
|
kubeClient: tt.fields.kubeClient(ctrl),
|
|
}
|
|
gotIsInnerLoopDeployed, gotResources, err := do.ListResourcesToDeleteFromDevfile(tt.args.devfileObj, tt.args.appName, tt.args.devfileObj.GetMetadataName(), tt.args.mode)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("ListResourcesToDeleteFromDevfile() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if gotIsInnerLoopDeployed != tt.wantIsInnerLoopDeployed {
|
|
t.Errorf("ListResourcesToDeleteFromDevfile() gotIsInnerLoopDeployed = %v, want %v", gotIsInnerLoopDeployed, tt.wantIsInnerLoopDeployed)
|
|
}
|
|
if diff := cmp.Diff(tt.wantResources, gotResources); diff != "" {
|
|
t.Errorf("DeleteComponentClient.ListResourcesToDeleteFromDevfile() wantResources mismatch (-want +got):\n%s", diff)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDeleteComponentClient_ExecutePreStopEvents(t *testing.T) {
|
|
const componentName = "nodejs-prj1-api-abhz"
|
|
const appName = "app"
|
|
fs := filesystem.NewFakeFs()
|
|
|
|
devfileObjWithPreStopEvents := odoTestingUtil.GetTestDevfileObjWithPreStopEvents(fs, "runtime", "echo \"Hello World!\"")
|
|
metadata := devfileObjWithPreStopEvents.Data.GetMetadata()
|
|
metadata.Name = componentName
|
|
devfileObjWithPreStopEvents.Data.SetMetadata(metadata)
|
|
|
|
type fields struct {
|
|
kubeClient func(ctrl *gomock.Controller) kclient.ClientInterface
|
|
}
|
|
type args struct {
|
|
devfileObj parser.DevfileObj
|
|
appName string
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
args args
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "no preStop event to execute",
|
|
fields: fields{
|
|
kubeClient: func(ctrl *gomock.Controller) kclient.ClientInterface {
|
|
return kclient.NewMockClientInterface(ctrl)
|
|
},
|
|
},
|
|
args: args{
|
|
devfileObj: odoTestingUtil.GetTestDevfileObjFromFile("devfile-deploy.yaml"),
|
|
appName: appName,
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "did not execute preStop event because pod was not found",
|
|
fields: fields{
|
|
kubeClient: func(ctrl *gomock.Controller) kclient.ClientInterface {
|
|
client := kclient.NewMockClientInterface(ctrl)
|
|
|
|
selector := odolabels.GetSelector(componentName, "app", odolabels.ComponentDevMode, false)
|
|
client.EXPECT().GetRunningPodFromSelector(selector).Return(&corev1.Pod{}, &kclient.PodNotFoundError{Selector: selector})
|
|
return client
|
|
},
|
|
},
|
|
args: args{
|
|
devfileObj: devfileObjWithPreStopEvents,
|
|
appName: appName,
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "failed to execute preStop event because of an un-ignorable error",
|
|
fields: fields{
|
|
kubeClient: func(ctrl *gomock.Controller) kclient.ClientInterface {
|
|
client := kclient.NewMockClientInterface(ctrl)
|
|
|
|
selector := odolabels.GetSelector(componentName, "app", odolabels.ComponentDevMode, false)
|
|
client.EXPECT().GetRunningPodFromSelector(selector).Return(nil, errors.New("some un-ignorable error"))
|
|
return client
|
|
},
|
|
},
|
|
args: args{
|
|
devfileObj: devfileObjWithPreStopEvents,
|
|
appName: appName,
|
|
},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "successfully executed preStop events in the running pod",
|
|
fields: fields{
|
|
kubeClient: func(ctrl *gomock.Controller) kclient.ClientInterface {
|
|
client := kclient.NewMockClientInterface(ctrl)
|
|
|
|
selector := odolabels.GetSelector(componentName, "app", odolabels.ComponentDevMode, false)
|
|
client.EXPECT().GetRunningPodFromSelector(selector).Return(odoTestingUtil.CreateFakePod(componentName, "runtime"), nil)
|
|
|
|
cmd := []string{"/bin/sh", "-c", "cd /projects/nodejs-starter && (echo \"Hello World!\") 1>>/proc/1/fd/1 2>>/proc/1/fd/2"}
|
|
client.EXPECT().ExecCMDInContainer("runtime", "runtime", cmd, gomock.Any(), gomock.Any(), nil, false).Return(nil)
|
|
|
|
return client
|
|
},
|
|
},
|
|
args: args{
|
|
devfileObj: devfileObjWithPreStopEvents,
|
|
appName: appName,
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "did not execute PreStopEvents because the pod is not in the running state",
|
|
fields: fields{
|
|
kubeClient: func(ctrl *gomock.Controller) kclient.ClientInterface {
|
|
client := kclient.NewMockClientInterface(ctrl)
|
|
|
|
selector := odolabels.GetSelector(componentName, "app", odolabels.ComponentDevMode, false)
|
|
pod := odoTestingUtil.CreateFakePod(componentName, "runtime")
|
|
pod.Status.Phase = corev1.PodFailed
|
|
client.EXPECT().GetRunningPodFromSelector(selector).Return(pod, nil)
|
|
return client
|
|
},
|
|
},
|
|
args: args{
|
|
devfileObj: devfileObjWithPreStopEvents,
|
|
appName: appName,
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "failed to execute PreStopEvents because it failed to execute the command inside the container, but no error returned",
|
|
fields: fields{
|
|
kubeClient: func(ctrl *gomock.Controller) kclient.ClientInterface {
|
|
client := kclient.NewMockClientInterface(ctrl)
|
|
|
|
selector := odolabels.GetSelector(componentName, "app", odolabels.ComponentDevMode, false)
|
|
fakePod := odoTestingUtil.CreateFakePod(componentName, "runtime")
|
|
// Expecting this method to be called twice because if the command execution fails, we try to get the pod logs by calling GetOnePodFromSelector again.
|
|
client.EXPECT().GetRunningPodFromSelector(selector).Return(fakePod, nil).Times(2)
|
|
|
|
client.EXPECT().GetPodLogs(fakePod.Name, gomock.Any(), gomock.Any()).Return(nil, errors.New("an error"))
|
|
|
|
cmd := []string{"/bin/sh", "-c", "cd /projects/nodejs-starter && (echo \"Hello World!\") 1>>/proc/1/fd/1 2>>/proc/1/fd/2"}
|
|
client.EXPECT().ExecCMDInContainer("runtime", "runtime", cmd, gomock.Any(), gomock.Any(), nil, false).Return(errors.New("some error"))
|
|
|
|
return client
|
|
},
|
|
},
|
|
args: args{
|
|
devfileObj: devfileObjWithPreStopEvents,
|
|
appName: appName,
|
|
},
|
|
wantErr: false,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
ctrl := gomock.NewController(t)
|
|
kubeClient := tt.fields.kubeClient(ctrl)
|
|
execClient := exec.NewExecClient(kubeClient)
|
|
do := NewDeleteComponentClient(kubeClient, execClient)
|
|
if err := do.ExecutePreStopEvents(tt.args.devfileObj, tt.args.appName, tt.args.devfileObj.GetMetadataName()); (err != nil) != tt.wantErr {
|
|
t.Errorf("DeleteComponent() error = %v, wantErr %v", err, tt.wantErr)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// getUnstructured returns an unstructured.Unstructured object
|
|
func getUnstructured(name, kind, apiVersion, namespace string) (u unstructured.Unstructured) {
|
|
u.SetName(name)
|
|
u.SetKind(kind)
|
|
u.SetAPIVersion(apiVersion)
|
|
u.SetNamespace(namespace)
|
|
return
|
|
}
|
|
|
|
func getGVR(group, version, resource string) schema.GroupVersionResource {
|
|
return schema.GroupVersionResource{
|
|
Group: group,
|
|
Version: version,
|
|
Resource: resource,
|
|
}
|
|
}
|