1
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