...

Source file src/k8s.io/kubectl/pkg/cmd/rollout/rollout_status_test.go

Documentation: k8s.io/kubectl/pkg/cmd/rollout

     1  /*
     2  Copyright 2022 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package rollout
    18  
    19  import (
    20  	"bytes"
    21  	"io"
    22  	appsv1 "k8s.io/api/apps/v1"
    23  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    24  	"k8s.io/apimachinery/pkg/watch"
    25  	"k8s.io/cli-runtime/pkg/genericiooptions"
    26  	"k8s.io/client-go/rest/fake"
    27  	cgtesting "k8s.io/client-go/testing"
    28  	"k8s.io/kubectl/pkg/scheme"
    29  	"net/http"
    30  	"testing"
    31  
    32  	"k8s.io/apimachinery/pkg/runtime"
    33  	"k8s.io/apimachinery/pkg/runtime/schema"
    34  	cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
    35  )
    36  
    37  var rolloutStatusGroupVersionEncoder = schema.GroupVersion{Group: "apps", Version: "v1"}
    38  
    39  func TestRolloutStatus(t *testing.T) {
    40  	deploymentName := "deployment/nginx-deployment"
    41  	ns := scheme.Codecs.WithoutConversion()
    42  	tf := cmdtesting.NewTestFactory().WithNamespace("test")
    43  	tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
    44  
    45  	info, _ := runtime.SerializerInfoForMediaType(ns.SupportedMediaTypes(), runtime.ContentTypeJSON)
    46  	encoder := ns.EncoderForVersion(info.Serializer, rolloutStatusGroupVersionEncoder)
    47  	tf.Client = &fake.RESTClient{
    48  		GroupVersion:         rolloutStatusGroupVersionEncoder,
    49  		NegotiatedSerializer: ns,
    50  		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
    51  			dep := &appsv1.Deployment{}
    52  			dep.Name = deploymentName
    53  			body := io.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(encoder, dep))))
    54  			return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: body}, nil
    55  		}),
    56  	}
    57  
    58  	tf.FakeDynamicClient.WatchReactionChain = nil
    59  	tf.FakeDynamicClient.AddWatchReactor("*", func(action cgtesting.Action) (handled bool, ret watch.Interface, err error) {
    60  		fw := watch.NewFake()
    61  		dep := &appsv1.Deployment{}
    62  		dep.Name = deploymentName
    63  		dep.Status = appsv1.DeploymentStatus{
    64  			Replicas:            1,
    65  			UpdatedReplicas:     1,
    66  			ReadyReplicas:       1,
    67  			AvailableReplicas:   1,
    68  			UnavailableReplicas: 0,
    69  			Conditions: []appsv1.DeploymentCondition{{
    70  				Type: appsv1.DeploymentAvailable,
    71  			}},
    72  		}
    73  		c, err := runtime.DefaultUnstructuredConverter.ToUnstructured(dep.DeepCopyObject())
    74  		if err != nil {
    75  			t.Errorf("unexpected err %s", err)
    76  		}
    77  		u := &unstructured.Unstructured{}
    78  		u.SetUnstructuredContent(c)
    79  		go fw.Add(u)
    80  		return true, fw, nil
    81  	})
    82  
    83  	streams, _, buf, _ := genericiooptions.NewTestIOStreams()
    84  	cmd := NewCmdRolloutStatus(tf, streams)
    85  	cmd.Run(cmd, []string{deploymentName})
    86  
    87  	expectedMsg := "deployment \"deployment/nginx-deployment\" successfully rolled out\n"
    88  	if buf.String() != expectedMsg {
    89  		t.Errorf("expected output: %s, but got: %s", expectedMsg, buf.String())
    90  	}
    91  }
    92  
    93  func TestRolloutStatusWithSelector(t *testing.T) {
    94  	deploymentName := "deployment"
    95  	ns := scheme.Codecs.WithoutConversion()
    96  	tf := cmdtesting.NewTestFactory().WithNamespace("test")
    97  	tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
    98  
    99  	info, _ := runtime.SerializerInfoForMediaType(ns.SupportedMediaTypes(), runtime.ContentTypeJSON)
   100  	encoder := ns.EncoderForVersion(info.Serializer, rolloutStatusGroupVersionEncoder)
   101  	tf.Client = &fake.RESTClient{
   102  		GroupVersion:         rolloutStatusGroupVersionEncoder,
   103  		NegotiatedSerializer: ns,
   104  		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
   105  			dep := &appsv1.Deployment{}
   106  			dep.Name = deploymentName
   107  			dep.Labels = make(map[string]string)
   108  			dep.Labels["app"] = "api"
   109  			body := io.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(encoder, dep))))
   110  			return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: body}, nil
   111  		}),
   112  	}
   113  
   114  	tf.FakeDynamicClient.WatchReactionChain = nil
   115  	tf.FakeDynamicClient.AddWatchReactor("*", func(action cgtesting.Action) (handled bool, ret watch.Interface, err error) {
   116  		fw := watch.NewFake()
   117  		dep := &appsv1.Deployment{}
   118  		dep.Name = deploymentName
   119  		dep.Status = appsv1.DeploymentStatus{
   120  			Replicas:            1,
   121  			UpdatedReplicas:     1,
   122  			ReadyReplicas:       1,
   123  			AvailableReplicas:   1,
   124  			UnavailableReplicas: 0,
   125  			Conditions: []appsv1.DeploymentCondition{{
   126  				Type: appsv1.DeploymentAvailable,
   127  			}},
   128  		}
   129  		dep.Labels = make(map[string]string)
   130  		dep.Labels["app"] = "api"
   131  		c, err := runtime.DefaultUnstructuredConverter.ToUnstructured(dep.DeepCopyObject())
   132  		if err != nil {
   133  			t.Errorf("unexpected err %s", err)
   134  		}
   135  		u := &unstructured.Unstructured{}
   136  		u.SetUnstructuredContent(c)
   137  		go fw.Add(u)
   138  		return true, fw, nil
   139  	})
   140  
   141  	streams, _, buf, _ := genericiooptions.NewTestIOStreams()
   142  	cmd := NewCmdRolloutStatus(tf, streams)
   143  	cmd.Flags().Set("selector", "app=api")
   144  	cmd.Run(cmd, []string{deploymentName})
   145  
   146  	expectedMsg := "deployment \"deployment\" successfully rolled out\n"
   147  	if buf.String() != expectedMsg {
   148  		t.Errorf("expected output: %s, but got: %s", expectedMsg, buf.String())
   149  	}
   150  }
   151  
   152  func TestRolloutStatusWatchDisabled(t *testing.T) {
   153  	deploymentName := "deployment/nginx-deployment"
   154  	ns := scheme.Codecs.WithoutConversion()
   155  	tf := cmdtesting.NewTestFactory().WithNamespace("test")
   156  	tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
   157  
   158  	info, _ := runtime.SerializerInfoForMediaType(ns.SupportedMediaTypes(), runtime.ContentTypeJSON)
   159  	encoder := ns.EncoderForVersion(info.Serializer, rolloutStatusGroupVersionEncoder)
   160  	tf.Client = &fake.RESTClient{
   161  		GroupVersion:         rolloutStatusGroupVersionEncoder,
   162  		NegotiatedSerializer: ns,
   163  		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
   164  			dep := &appsv1.Deployment{}
   165  			dep.Name = deploymentName
   166  			body := io.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(encoder, dep))))
   167  			return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: body}, nil
   168  		}),
   169  	}
   170  
   171  	tf.FakeDynamicClient.WatchReactionChain = nil
   172  	tf.FakeDynamicClient.AddWatchReactor("*", func(action cgtesting.Action) (handled bool, ret watch.Interface, err error) {
   173  		fw := watch.NewFake()
   174  		dep := &appsv1.Deployment{}
   175  		dep.Name = deploymentName
   176  		dep.Status = appsv1.DeploymentStatus{
   177  			Replicas:            1,
   178  			UpdatedReplicas:     1,
   179  			ReadyReplicas:       1,
   180  			AvailableReplicas:   1,
   181  			UnavailableReplicas: 0,
   182  			Conditions: []appsv1.DeploymentCondition{{
   183  				Type: appsv1.DeploymentAvailable,
   184  			}},
   185  		}
   186  		c, err := runtime.DefaultUnstructuredConverter.ToUnstructured(dep.DeepCopyObject())
   187  		if err != nil {
   188  			t.Errorf("unexpected err %s", err)
   189  		}
   190  		u := &unstructured.Unstructured{}
   191  		u.SetUnstructuredContent(c)
   192  		go fw.Add(u)
   193  		return true, fw, nil
   194  	})
   195  
   196  	streams, _, buf, _ := genericiooptions.NewTestIOStreams()
   197  	cmd := NewCmdRolloutStatus(tf, streams)
   198  	cmd.Flags().Set("watch", "false")
   199  	cmd.Run(cmd, []string{deploymentName})
   200  
   201  	expectedMsg := "deployment \"deployment/nginx-deployment\" successfully rolled out\n"
   202  	if buf.String() != expectedMsg {
   203  		t.Errorf("expected output: %s, but got: %s", expectedMsg, buf.String())
   204  	}
   205  }
   206  
   207  func TestRolloutStatusWatchDisabledUnavailable(t *testing.T) {
   208  	deploymentName := "deployment/nginx-deployment"
   209  	ns := scheme.Codecs.WithoutConversion()
   210  	tf := cmdtesting.NewTestFactory().WithNamespace("test")
   211  	tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
   212  
   213  	info, _ := runtime.SerializerInfoForMediaType(ns.SupportedMediaTypes(), runtime.ContentTypeJSON)
   214  	encoder := ns.EncoderForVersion(info.Serializer, rolloutStatusGroupVersionEncoder)
   215  	tf.Client = &fake.RESTClient{
   216  		GroupVersion:         rolloutStatusGroupVersionEncoder,
   217  		NegotiatedSerializer: ns,
   218  		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
   219  			dep := &appsv1.Deployment{}
   220  			dep.Name = deploymentName
   221  			body := io.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(encoder, dep))))
   222  			return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: body}, nil
   223  		}),
   224  	}
   225  
   226  	tf.FakeDynamicClient.WatchReactionChain = nil
   227  	tf.FakeDynamicClient.AddWatchReactor("*", func(action cgtesting.Action) (handled bool, ret watch.Interface, err error) {
   228  		fw := watch.NewFake()
   229  		dep := &appsv1.Deployment{}
   230  		dep.Name = deploymentName
   231  		dep.Status = appsv1.DeploymentStatus{
   232  			Replicas:            1,
   233  			UpdatedReplicas:     1,
   234  			ReadyReplicas:       1,
   235  			AvailableReplicas:   0,
   236  			UnavailableReplicas: 0,
   237  			Conditions: []appsv1.DeploymentCondition{{
   238  				Type: appsv1.DeploymentAvailable,
   239  			}},
   240  		}
   241  		c, err := runtime.DefaultUnstructuredConverter.ToUnstructured(dep.DeepCopyObject())
   242  		if err != nil {
   243  			t.Errorf("unexpected err %s", err)
   244  		}
   245  		u := &unstructured.Unstructured{}
   246  		u.SetUnstructuredContent(c)
   247  		go fw.Add(u)
   248  		return true, fw, nil
   249  	})
   250  
   251  	streams, _, buf, _ := genericiooptions.NewTestIOStreams()
   252  	cmd := NewCmdRolloutStatus(tf, streams)
   253  	cmd.Flags().Set("watch", "false")
   254  	cmd.Run(cmd, []string{deploymentName})
   255  
   256  	expectedMsg := "Waiting for deployment \"deployment/nginx-deployment\" rollout to finish: 0 of 1 updated replicas are available...\n"
   257  	if buf.String() != expectedMsg {
   258  		t.Errorf("expected output: %s, but got: %s", expectedMsg, buf.String())
   259  	}
   260  }
   261  
   262  func TestRolloutStatusEmptyList(t *testing.T) {
   263  	ns := scheme.Codecs.WithoutConversion()
   264  	tf := cmdtesting.NewTestFactory().WithNamespace("test")
   265  	tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
   266  
   267  	info, _ := runtime.SerializerInfoForMediaType(ns.SupportedMediaTypes(), runtime.ContentTypeJSON)
   268  	encoder := ns.EncoderForVersion(info.Serializer, rolloutStatusGroupVersionEncoder)
   269  	tf.Client = &fake.RESTClient{
   270  		GroupVersion:         rolloutStatusGroupVersionEncoder,
   271  		NegotiatedSerializer: ns,
   272  		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
   273  			dep := &appsv1.DeploymentList{}
   274  			body := io.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(encoder, dep))))
   275  			return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: body}, nil
   276  		}),
   277  	}
   278  	streams, _, _, err := genericiooptions.NewTestIOStreams()
   279  	cmd := NewCmdRolloutStatus(tf, streams)
   280  	cmd.Run(cmd, []string{"deployment"})
   281  
   282  	expectedMsg := "No resources found in test namespace.\n"
   283  	if err.String() != expectedMsg {
   284  		t.Errorf("expected output: %s, but got: %s", expectedMsg, err.String())
   285  	}
   286  }
   287  

View as plain text