...

Source file src/github.com/redhat-developer/odo/pkg/kclient/pods_test.go

Documentation: github.com/redhat-developer/odo/pkg/kclient

     1  package kclient
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/golang/mock/gomock"
     9  	"github.com/google/go-cmp/cmp"
    10  	"k8s.io/apimachinery/pkg/api/meta"
    11  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    12  	"k8s.io/apimachinery/pkg/runtime"
    13  	"k8s.io/apimachinery/pkg/runtime/schema"
    14  
    15  	corev1 "k8s.io/api/core/v1"
    16  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    17  
    18  	ktesting "k8s.io/client-go/testing"
    19  )
    20  
    21  func TestGetOnePodFromSelector(t *testing.T) {
    22  	fakePod := FakePodStatus(corev1.PodRunning, "nodejs")
    23  	fakePod.Labels["component"] = "nodejs"
    24  
    25  	fakePodWithDeletionTimeStamp := FakePodStatus(corev1.PodRunning, "nodejs")
    26  	fakePodWithDeletionTimeStamp.Labels["component"] = "nodejs"
    27  	currentTime := metav1.NewTime(time.Now())
    28  	fakePodWithDeletionTimeStamp.DeletionTimestamp = &currentTime
    29  
    30  	type args struct {
    31  		selector string
    32  	}
    33  	tests := []struct {
    34  		name         string
    35  		args         args
    36  		returnedPods *corev1.PodList
    37  		want         *corev1.Pod
    38  		wantErr      bool
    39  	}{
    40  		{
    41  			name: "valid number of pods",
    42  			args: args{selector: fmt.Sprintf("component=%s", "nodejs")},
    43  			returnedPods: &corev1.PodList{
    44  				Items: []corev1.Pod{
    45  					*fakePod,
    46  				},
    47  			},
    48  			want:    fakePod,
    49  			wantErr: false,
    50  		},
    51  		{
    52  			name: "zero pods",
    53  			args: args{selector: fmt.Sprintf("component=%s", "nodejs")},
    54  			returnedPods: &corev1.PodList{
    55  				Items: []corev1.Pod{},
    56  			},
    57  			want:    &corev1.Pod{},
    58  			wantErr: true,
    59  		},
    60  		{
    61  			name: "mutiple pods",
    62  			args: args{selector: fmt.Sprintf("component=%s", "nodejs")},
    63  			returnedPods: &corev1.PodList{
    64  				Items: []corev1.Pod{
    65  					*fakePod,
    66  					*fakePod,
    67  				},
    68  			},
    69  			want:    &corev1.Pod{},
    70  			wantErr: true,
    71  		},
    72  		{
    73  			name: "pod is in the deletion state",
    74  			args: args{selector: fmt.Sprintf("component=%s", "nodejs")},
    75  			returnedPods: &corev1.PodList{
    76  				Items: []corev1.Pod{
    77  					*fakePodWithDeletionTimeStamp,
    78  				},
    79  			},
    80  			want:    &corev1.Pod{},
    81  			wantErr: true,
    82  		},
    83  	}
    84  	for _, tt := range tests {
    85  		t.Run(tt.name, func(t *testing.T) {
    86  
    87  			fkclient, fkclientset := FakeNew()
    88  
    89  			fkclientset.Kubernetes.PrependReactor("list", "pods", func(action ktesting.Action) (handled bool, ret runtime.Object, err error) {
    90  				if action.(ktesting.ListAction).GetListRestrictions().Labels.String() != fmt.Sprintf("component=%s", "nodejs") {
    91  					t.Errorf("list called with different selector want:%s, got:%s", fmt.Sprintf("component=%s", "nodejs"), action.(ktesting.ListAction).GetListRestrictions().Labels.String())
    92  				}
    93  				return true, tt.returnedPods, nil
    94  			})
    95  
    96  			got, err := fkclient.GetRunningPodFromSelector(tt.args.selector)
    97  			if (err != nil) != tt.wantErr {
    98  				t.Errorf("GetOnePodFromSelector() error = %v, wantErr %v", err, tt.wantErr)
    99  				return
   100  			} else if tt.wantErr && err != nil {
   101  				return
   102  			}
   103  			if diff := cmp.Diff(tt.want, got); diff != "" {
   104  				t.Errorf("Client.GetRunningPodFromSelector() mismatch (-want +got):\n%s", diff)
   105  			}
   106  		})
   107  	}
   108  }
   109  
   110  func TestGetPodUsingComponentName(t *testing.T) {
   111  	fakePod := FakePodStatus(corev1.PodRunning, "nodejs")
   112  	fakePod.Labels["component"] = "nodejs"
   113  
   114  	type args struct {
   115  		componentName string
   116  	}
   117  	tests := []struct {
   118  		name    string
   119  		args    args
   120  		want    *corev1.Pod
   121  		wantErr bool
   122  	}{
   123  		{
   124  			name: "list called with same component name",
   125  			args: args{
   126  				componentName: "nodejs",
   127  			},
   128  			want:    fakePod,
   129  			wantErr: false,
   130  		},
   131  	}
   132  	for _, tt := range tests {
   133  		t.Run(tt.name, func(t *testing.T) {
   134  			fkclient, fkclientset := FakeNew()
   135  
   136  			fkclientset.Kubernetes.PrependReactor("list", "pods", func(action ktesting.Action) (handled bool, ret runtime.Object, err error) {
   137  				if action.(ktesting.ListAction).GetListRestrictions().Labels.String() != fmt.Sprintf("component=%s", tt.args.componentName) {
   138  					t.Errorf("list called with different selector want:%s, got:%s", fmt.Sprintf("component=%s", tt.args.componentName), action.(ktesting.ListAction).GetListRestrictions().Labels.String())
   139  				}
   140  				return true, &corev1.PodList{
   141  					Items: []corev1.Pod{
   142  						*fakePod,
   143  					},
   144  				}, nil
   145  			})
   146  
   147  			got, err := fkclient.GetPodUsingComponentName(tt.args.componentName)
   148  			if (err != nil) != tt.wantErr {
   149  				t.Errorf("GetPodUsingComponentName() error = %v, wantErr %v", err, tt.wantErr)
   150  				return
   151  			}
   152  			if diff := cmp.Diff(tt.want, got); diff != "" {
   153  				t.Errorf("Client.GetPodUsingComponentName() mismatch (-want +got):\n%s", diff)
   154  			}
   155  		})
   156  	}
   157  }
   158  
   159  func generateOwnerReference(object unstructured.Unstructured) metav1.OwnerReference {
   160  	return metav1.OwnerReference{
   161  		APIVersion: object.GetAPIVersion(),
   162  		Kind:       object.GetKind(),
   163  		Name:       object.GetName(),
   164  		UID:        object.GetUID(),
   165  	}
   166  }
   167  
   168  func Test_matchOwnerReferenceWithResources_PodsWithOwnerInResources(t *testing.T) {
   169  	type args struct {
   170  		resources func() []unstructured.Unstructured
   171  	}
   172  	tests := []struct {
   173  		name    string
   174  		args    args
   175  		want    bool
   176  		wantErr bool
   177  	}{
   178  		{
   179  			name: "Case 1: pod owned by a deployment",
   180  			args: args{
   181  				resources: func() []unstructured.Unstructured {
   182  					pod := fakePod("pod")
   183  					deployment := fakeDeployment("deployment")
   184  					deployOwnerRef := generateOwnerReference(deployment)
   185  					pod.SetOwnerReferences([]metav1.OwnerReference{deployOwnerRef})
   186  					return []unstructured.Unstructured{pod, deployment}
   187  				},
   188  			},
   189  			want:    true,
   190  			wantErr: false,
   191  		},
   192  	}
   193  	for _, tt := range tests {
   194  		t.Run(tt.name, func(t *testing.T) {
   195  			ctrl := gomock.NewController(t)
   196  			kubernetesClient := NewMockClientInterface(ctrl)
   197  
   198  			got, err := matchOwnerReferenceWithResources(
   199  				kubernetesClient,
   200  				tt.args.resources()[0].GetOwnerReferences()[0],
   201  				tt.args.resources(),
   202  			)
   203  			if (err != nil) != tt.wantErr {
   204  				t.Errorf("matchOwnerReferenceWithResources() error = %v, wantErr %v", err, tt.wantErr)
   205  				return
   206  			}
   207  			if got != tt.want {
   208  				t.Errorf("matchOwnerReferenceWithResources() got = %v, want %v", got, tt.want)
   209  			}
   210  		})
   211  	}
   212  }
   213  
   214  func fakePod(name string) unstructured.Unstructured {
   215  	return unstructured.Unstructured{Object: map[string]interface{}{
   216  		"apiVersion": "v1",
   217  		"kind":       "Pod",
   218  		"metadata": map[string]interface{}{
   219  			"name": fmt.Sprintf("pod-%s", name),
   220  			"uid":  fmt.Sprintf("pod-%s", name),
   221  		},
   222  		"spec": map[string]interface{}{
   223  			"containers": map[string]interface{}{
   224  				"name":  fmt.Sprintf("%s-1", name),
   225  				"image": "image",
   226  			},
   227  		},
   228  	}}
   229  }
   230  
   231  func fakeDeployment(name string) unstructured.Unstructured {
   232  	return unstructured.Unstructured{
   233  		Object: map[string]interface{}{
   234  			"apiVersion": "apps/v1",
   235  			"kind":       "Deployment",
   236  			"metadata": map[string]interface{}{
   237  				"name": fmt.Sprintf("deployment-%s", name),
   238  				"uid":  fmt.Sprintf("deployment-%s", name),
   239  			},
   240  			"spec": map[string]interface{}{
   241  				"selector": map[string]interface{}{
   242  					"matchLabels": map[string]interface{}{
   243  						"app": "test",
   244  					},
   245  				},
   246  				"template": map[string]interface{}{
   247  					"metadata": map[string]interface{}{
   248  						"labels": map[string]interface{}{
   249  							"app": "test",
   250  						},
   251  					},
   252  					"spec": fakePod(name),
   253  				},
   254  			},
   255  		},
   256  	}
   257  }
   258  
   259  func Test_matchOwnerReferenceWithResources_PodsWithNoOwnerInResources(t *testing.T) {
   260  	// pod and deployment that are not a part of args.resources
   261  	independentDeploy := fakeDeployment("independent-deploy")
   262  	independentPod := fakePod("independent-pod")
   263  	independentPod.SetOwnerReferences([]metav1.OwnerReference{generateOwnerReference(independentDeploy)})
   264  
   265  	type args struct {
   266  		resources func() []unstructured.Unstructured
   267  	}
   268  	tests := []struct {
   269  		name     string
   270  		args     args
   271  		gvk      *meta.RESTMapping
   272  		resource *unstructured.Unstructured
   273  		want     bool
   274  		wantErr  bool
   275  	}{
   276  		{
   277  			name: "Case 1: Pod not owned by anything in `resources` slice",
   278  			args: args{
   279  				resources: func() []unstructured.Unstructured {
   280  					pod := fakePod("pod")
   281  					deployment := fakeDeployment("deployment")
   282  					deployOwnerRef := generateOwnerReference(deployment)
   283  					pod.SetOwnerReferences([]metav1.OwnerReference{deployOwnerRef})
   284  					return []unstructured.Unstructured{pod, deployment}
   285  				},
   286  			},
   287  			gvk: &meta.RESTMapping{
   288  				Resource: schema.GroupVersionResource{
   289  					Group:    "apps",
   290  					Version:  "v1",
   291  					Resource: "deployments",
   292  				},
   293  				GroupVersionKind: schema.GroupVersionKind{
   294  					Group:   "apps",
   295  					Version: "v1",
   296  					Kind:    "Deployment",
   297  				},
   298  			},
   299  			resource: &unstructured.Unstructured{Object: map[string]interface{}{
   300  				"apiVersion": "apps/v1",
   301  				"kind":       "Deployment",
   302  				"metadata": map[string]interface{}{
   303  					"namespace": independentDeploy.GetNamespace(),
   304  					"name":      independentDeploy.GetName(),
   305  					"uid":       independentDeploy.GetUID(),
   306  				},
   307  				"spec": map[string]interface{}{
   308  					"selector": map[string]interface{}{
   309  						"matchLabels": map[string]interface{}{
   310  							"app": "test",
   311  						},
   312  					},
   313  					"template": map[string]interface{}{
   314  						"metadata": map[string]interface{}{
   315  							"labels": map[string]interface{}{
   316  								"app": "test",
   317  							},
   318  						},
   319  						"spec": fakePod(independentDeploy.GetName()),
   320  					},
   321  				},
   322  			}},
   323  			want:    false,
   324  			wantErr: false,
   325  		},
   326  	}
   327  	for _, tt := range tests {
   328  		t.Run(tt.name, func(t *testing.T) {
   329  			ctrl := gomock.NewController(t)
   330  			kubernetesClient := NewMockClientInterface(ctrl)
   331  			kubernetesClient.EXPECT().GetRestMappingFromGVK(
   332  				schema.FromAPIVersionAndKind(independentDeploy.GetAPIVersion(), independentDeploy.GetKind())).Return(tt.gvk, nil).AnyTimes()
   333  			kubernetesClient.EXPECT().GetDynamicResource(tt.gvk.Resource, independentDeploy.GetName()).Return(tt.resource, nil).AnyTimes()
   334  
   335  			got, err := matchOwnerReferenceWithResources(kubernetesClient, independentPod.GetOwnerReferences()[0], tt.args.resources())
   336  			if (err != nil) != tt.wantErr {
   337  				t.Errorf("matchOwnerReferenceWithResources() error = %v, wantErr %v", err, tt.wantErr)
   338  				return
   339  			}
   340  			if got != tt.want {
   341  				t.Errorf("matchOwnerReferenceWithResources() got = %v, want %v", got, tt.want)
   342  			}
   343  		})
   344  	}
   345  }
   346  

View as plain text