2016-08-26 07:21:43 +00:00
/ *
Copyright 2016 The Kubernetes Authors .
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
package kubectl
import (
2017-06-04 22:31:23 +00:00
"fmt"
2016-08-26 07:21:43 +00:00
"testing"
2018-03-20 16:45:19 +00:00
apps "k8s.io/api/apps/v1"
2017-10-24 15:56:54 +00:00
api "k8s.io/api/core/v1"
2017-01-17 03:38:19 +00:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2018-08-24 10:22:26 +00:00
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/kubernetes/pkg/kubectl/scheme"
2016-08-26 07:21:43 +00:00
)
func TestDeploymentStatusViewerStatus ( t * testing . T ) {
tests := [ ] struct {
2018-05-12 09:24:28 +00:00
name string
2017-04-19 12:29:39 +00:00
generation int64
specReplicas int32
2018-03-20 16:45:19 +00:00
status apps . DeploymentStatus
2017-04-19 12:29:39 +00:00
msg string
done bool
2016-08-26 07:21:43 +00:00
} {
{
2018-05-12 09:24:28 +00:00
name : "test1" ,
2016-08-26 07:21:43 +00:00
generation : 0 ,
specReplicas : 1 ,
2018-03-20 16:45:19 +00:00
status : apps . DeploymentStatus {
2016-08-26 07:21:43 +00:00
ObservedGeneration : 1 ,
Replicas : 1 ,
UpdatedReplicas : 0 ,
AvailableReplicas : 1 ,
UnavailableReplicas : 0 ,
} ,
2018-05-29 10:07:41 +00:00
msg : "Waiting for deployment \"foo\" rollout to finish: 0 out of 1 new replicas have been updated...\n" ,
2016-08-26 07:21:43 +00:00
done : false ,
} ,
{
2018-05-12 09:24:28 +00:00
name : "test2" ,
2016-08-26 07:21:43 +00:00
generation : 1 ,
specReplicas : 1 ,
2018-03-20 16:45:19 +00:00
status : apps . DeploymentStatus {
2016-08-26 07:21:43 +00:00
ObservedGeneration : 1 ,
Replicas : 2 ,
UpdatedReplicas : 1 ,
AvailableReplicas : 2 ,
UnavailableReplicas : 0 ,
} ,
2018-05-29 10:07:41 +00:00
msg : "Waiting for deployment \"foo\" rollout to finish: 1 old replicas are pending termination...\n" ,
2016-08-26 07:21:43 +00:00
done : false ,
} ,
{
2018-05-12 09:24:28 +00:00
name : "test3" ,
2017-04-19 12:29:39 +00:00
generation : 1 ,
specReplicas : 2 ,
2018-03-20 16:45:19 +00:00
status : apps . DeploymentStatus {
2016-08-26 07:21:43 +00:00
ObservedGeneration : 1 ,
Replicas : 2 ,
UpdatedReplicas : 2 ,
AvailableReplicas : 1 ,
UnavailableReplicas : 1 ,
} ,
2018-05-29 10:07:41 +00:00
msg : "Waiting for deployment \"foo\" rollout to finish: 1 of 2 updated replicas are available...\n" ,
2016-08-26 07:21:43 +00:00
done : false ,
} ,
{
2018-05-12 09:24:28 +00:00
name : "test4" ,
2016-08-26 07:21:43 +00:00
generation : 1 ,
specReplicas : 2 ,
2018-03-20 16:45:19 +00:00
status : apps . DeploymentStatus {
2016-08-26 07:21:43 +00:00
ObservedGeneration : 1 ,
Replicas : 2 ,
UpdatedReplicas : 2 ,
AvailableReplicas : 2 ,
UnavailableReplicas : 0 ,
} ,
2016-10-10 11:07:38 +00:00
msg : "deployment \"foo\" successfully rolled out\n" ,
2016-08-26 07:21:43 +00:00
done : true ,
} ,
{
2018-05-12 09:24:28 +00:00
name : "test5" ,
2016-08-26 07:21:43 +00:00
generation : 2 ,
specReplicas : 2 ,
2018-03-20 16:45:19 +00:00
status : apps . DeploymentStatus {
2016-08-26 07:21:43 +00:00
ObservedGeneration : 1 ,
Replicas : 2 ,
UpdatedReplicas : 2 ,
AvailableReplicas : 2 ,
UnavailableReplicas : 0 ,
} ,
msg : "Waiting for deployment spec update to be observed...\n" ,
done : false ,
} ,
}
2017-04-19 12:29:39 +00:00
for _ , test := range tests {
2018-05-12 09:24:28 +00:00
t . Run ( test . name , func ( t * testing . T ) {
d := & apps . Deployment {
ObjectMeta : metav1 . ObjectMeta {
Namespace : "bar" ,
Name : "foo" ,
UID : "8764ae47-9092-11e4-8393-42010af018ff" ,
Generation : test . generation ,
} ,
Spec : apps . DeploymentSpec {
Replicas : & test . specReplicas ,
} ,
Status : test . status ,
}
2018-08-24 10:22:26 +00:00
unstructuredD := & unstructured . Unstructured { }
err := scheme . Scheme . Convert ( d , unstructuredD , nil )
if err != nil {
t . Fatal ( err )
}
2018-09-19 19:35:59 +00:00
dsv := & DeploymentStatusViewer { }
2018-08-24 10:22:26 +00:00
msg , done , err := dsv . Status ( unstructuredD , 0 )
2018-05-12 09:24:28 +00:00
if err != nil {
t . Fatalf ( "DeploymentStatusViewer.Status(): %v" , err )
}
if done != test . done || msg != test . msg {
t . Errorf ( "DeploymentStatusViewer.Status() for deployment with generation %d, %d replicas specified, and status %+v returned %q, %t, want %q, %t" ,
test . generation ,
test . specReplicas ,
test . status ,
msg ,
done ,
test . msg ,
test . done ,
)
}
} )
2016-08-26 07:21:43 +00:00
}
}
2017-03-07 12:58:18 +00:00
func TestDaemonSetStatusViewerStatus ( t * testing . T ) {
tests := [ ] struct {
2018-05-12 09:24:28 +00:00
name string
2017-04-19 12:33:34 +00:00
generation int64
2018-03-20 16:45:19 +00:00
status apps . DaemonSetStatus
2017-04-19 12:33:34 +00:00
msg string
done bool
2017-03-07 12:58:18 +00:00
} {
{
2018-05-12 09:24:28 +00:00
name : "test1" ,
2017-03-07 12:58:18 +00:00
generation : 0 ,
2018-03-20 16:45:19 +00:00
status : apps . DaemonSetStatus {
2017-03-07 12:58:18 +00:00
ObservedGeneration : 1 ,
UpdatedNumberScheduled : 0 ,
DesiredNumberScheduled : 1 ,
NumberAvailable : 0 ,
} ,
2018-05-29 10:07:41 +00:00
msg : "Waiting for daemon set \"foo\" rollout to finish: 0 out of 1 new pods have been updated...\n" ,
2017-03-07 12:58:18 +00:00
done : false ,
} ,
{
2018-05-12 09:24:28 +00:00
name : "test2" ,
2017-04-19 12:33:34 +00:00
generation : 1 ,
2018-03-20 16:45:19 +00:00
status : apps . DaemonSetStatus {
2017-03-07 12:58:18 +00:00
ObservedGeneration : 1 ,
UpdatedNumberScheduled : 2 ,
DesiredNumberScheduled : 2 ,
NumberAvailable : 1 ,
} ,
2018-05-29 10:07:41 +00:00
msg : "Waiting for daemon set \"foo\" rollout to finish: 1 of 2 updated pods are available...\n" ,
2017-03-07 12:58:18 +00:00
done : false ,
} ,
{
2018-05-12 09:24:28 +00:00
name : "test3" ,
2017-03-07 12:58:18 +00:00
generation : 1 ,
2018-03-20 16:45:19 +00:00
status : apps . DaemonSetStatus {
2017-03-07 12:58:18 +00:00
ObservedGeneration : 1 ,
UpdatedNumberScheduled : 2 ,
DesiredNumberScheduled : 2 ,
NumberAvailable : 2 ,
} ,
msg : "daemon set \"foo\" successfully rolled out\n" ,
done : true ,
} ,
{
2018-05-12 09:24:28 +00:00
name : "test4" ,
2017-03-07 12:58:18 +00:00
generation : 2 ,
2018-03-20 16:45:19 +00:00
status : apps . DaemonSetStatus {
2017-03-07 12:58:18 +00:00
ObservedGeneration : 1 ,
UpdatedNumberScheduled : 2 ,
DesiredNumberScheduled : 2 ,
NumberAvailable : 2 ,
} ,
msg : "Waiting for daemon set spec update to be observed...\n" ,
done : false ,
} ,
}
2018-05-12 09:24:28 +00:00
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
d := & apps . DaemonSet {
ObjectMeta : metav1 . ObjectMeta {
Namespace : "bar" ,
Name : "foo" ,
UID : "8764ae47-9092-11e4-8393-42010af018ff" ,
Generation : test . generation ,
2017-03-07 12:58:18 +00:00
} ,
2018-05-12 09:24:28 +00:00
Spec : apps . DaemonSetSpec {
UpdateStrategy : apps . DaemonSetUpdateStrategy {
Type : apps . RollingUpdateDaemonSetStrategyType ,
} ,
} ,
Status : test . status ,
}
2018-08-24 10:22:26 +00:00
unstructuredD := & unstructured . Unstructured { }
err := scheme . Scheme . Convert ( d , unstructuredD , nil )
if err != nil {
t . Fatal ( err )
}
2018-09-19 19:35:59 +00:00
dsv := & DaemonSetStatusViewer { }
2018-08-24 10:22:26 +00:00
msg , done , err := dsv . Status ( unstructuredD , 0 )
2018-05-12 09:24:28 +00:00
if err != nil {
t . Fatalf ( "unexpected error: %v" , err )
}
if done != test . done || msg != test . msg {
t . Errorf ( "daemon set with generation %d, %d pods specified, and status:\n%+v\nreturned:\n%q, %t\nwant:\n%q, %t" ,
test . generation ,
d . Status . DesiredNumberScheduled ,
test . status ,
msg ,
done ,
test . msg ,
test . done ,
)
}
} )
2017-03-07 12:58:18 +00:00
}
}
2017-06-04 22:31:23 +00:00
func TestStatefulSetStatusViewerStatus ( t * testing . T ) {
tests := [ ] struct {
name string
generation int64
strategy apps . StatefulSetUpdateStrategy
status apps . StatefulSetStatus
msg string
done bool
err bool
} {
{
name : "on delete returns an error" ,
generation : 1 ,
strategy : apps . StatefulSetUpdateStrategy { Type : apps . OnDeleteStatefulSetStrategyType } ,
status : apps . StatefulSetStatus {
2018-03-20 16:45:19 +00:00
ObservedGeneration : 1 ,
Replicas : 0 ,
ReadyReplicas : 1 ,
CurrentReplicas : 0 ,
UpdatedReplicas : 0 ,
2017-06-04 22:31:23 +00:00
} ,
msg : "" ,
done : true ,
err : true ,
} ,
{
name : "unobserved update is not complete" ,
generation : 2 ,
strategy : apps . StatefulSetUpdateStrategy { Type : apps . RollingUpdateStatefulSetStrategyType } ,
status : apps . StatefulSetStatus {
2018-03-20 16:45:19 +00:00
ObservedGeneration : 1 ,
Replicas : 3 ,
ReadyReplicas : 3 ,
CurrentReplicas : 3 ,
UpdatedReplicas : 0 ,
2017-06-04 22:31:23 +00:00
} ,
msg : "Waiting for statefulset spec update to be observed...\n" ,
done : false ,
err : false ,
} ,
{
name : "if all pods are not ready the update is not complete" ,
generation : 1 ,
strategy : apps . StatefulSetUpdateStrategy { Type : apps . RollingUpdateStatefulSetStrategyType } ,
status : apps . StatefulSetStatus {
2018-03-20 16:45:19 +00:00
ObservedGeneration : 2 ,
Replicas : 3 ,
ReadyReplicas : 2 ,
CurrentReplicas : 3 ,
UpdatedReplicas : 0 ,
2017-06-04 22:31:23 +00:00
} ,
msg : fmt . Sprintf ( "Waiting for %d pods to be ready...\n" , 1 ) ,
done : false ,
err : false ,
} ,
{
name : "partition update completes when all replicas above the partition are updated" ,
generation : 1 ,
2017-06-12 17:07:07 +00:00
strategy : apps . StatefulSetUpdateStrategy { Type : apps . RollingUpdateStatefulSetStrategyType ,
RollingUpdate : func ( ) * apps . RollingUpdateStatefulSetStrategy {
2017-10-24 15:56:54 +00:00
partition := int32 ( 2 )
return & apps . RollingUpdateStatefulSetStrategy { Partition : & partition }
2017-06-04 22:31:23 +00:00
} ( ) } ,
status : apps . StatefulSetStatus {
2018-03-20 16:45:19 +00:00
ObservedGeneration : 2 ,
Replicas : 3 ,
ReadyReplicas : 3 ,
CurrentReplicas : 2 ,
UpdatedReplicas : 1 ,
2017-06-04 22:31:23 +00:00
} ,
msg : fmt . Sprintf ( "partitioned roll out complete: %d new pods have been updated...\n" , 1 ) ,
done : true ,
err : false ,
} ,
{
name : "partition update is in progress if all pods above the partition have not been updated" ,
generation : 1 ,
2017-06-12 17:07:07 +00:00
strategy : apps . StatefulSetUpdateStrategy { Type : apps . RollingUpdateStatefulSetStrategyType ,
RollingUpdate : func ( ) * apps . RollingUpdateStatefulSetStrategy {
2017-10-24 15:56:54 +00:00
partition := int32 ( 2 )
return & apps . RollingUpdateStatefulSetStrategy { Partition : & partition }
2017-06-04 22:31:23 +00:00
} ( ) } ,
status : apps . StatefulSetStatus {
2018-03-20 16:45:19 +00:00
ObservedGeneration : 2 ,
Replicas : 3 ,
ReadyReplicas : 3 ,
CurrentReplicas : 3 ,
UpdatedReplicas : 0 ,
2017-06-04 22:31:23 +00:00
} ,
msg : fmt . Sprintf ( "Waiting for partitioned roll out to finish: %d out of %d new pods have been updated...\n" , 0 , 1 ) ,
done : true ,
err : false ,
} ,
{
name : "update completes when all replicas are current" ,
generation : 1 ,
strategy : apps . StatefulSetUpdateStrategy { Type : apps . RollingUpdateStatefulSetStrategyType } ,
status : apps . StatefulSetStatus {
2018-03-20 16:45:19 +00:00
ObservedGeneration : 2 ,
Replicas : 3 ,
ReadyReplicas : 3 ,
CurrentReplicas : 3 ,
UpdatedReplicas : 3 ,
CurrentRevision : "foo" ,
UpdateRevision : "foo" ,
2017-06-04 22:31:23 +00:00
} ,
msg : fmt . Sprintf ( "statefulset rolling update complete %d pods at revision %s...\n" , 3 , "foo" ) ,
done : true ,
err : false ,
} ,
}
2018-05-12 09:24:28 +00:00
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
s := newStatefulSet ( 3 )
s . Status = test . status
s . Spec . UpdateStrategy = test . strategy
s . Generation = test . generation
2018-08-24 10:22:26 +00:00
unstructuredS := & unstructured . Unstructured { }
err := scheme . Scheme . Convert ( s , unstructuredS , nil )
if err != nil {
t . Fatal ( err )
}
2018-09-19 19:35:59 +00:00
dsv := & StatefulSetStatusViewer { }
2018-08-24 10:22:26 +00:00
msg , done , err := dsv . Status ( unstructuredS , 0 )
2018-05-12 09:24:28 +00:00
if test . err && err == nil {
t . Fatalf ( "%s: expected error" , test . name )
}
if ! test . err && err != nil {
t . Fatalf ( "%s: %s" , test . name , err )
}
if done && ! test . done {
t . Errorf ( "%s: want done %v got %v" , test . name , done , test . done )
}
if msg != test . msg {
t . Errorf ( "%s: want message %s got %s" , test . name , test . msg , msg )
}
} )
2017-06-04 22:31:23 +00:00
}
}
2017-03-07 12:58:18 +00:00
func TestDaemonSetStatusViewerStatusWithWrongUpdateStrategyType ( t * testing . T ) {
2018-03-20 16:45:19 +00:00
d := & apps . DaemonSet {
2017-03-07 12:58:18 +00:00
ObjectMeta : metav1 . ObjectMeta {
Namespace : "bar" ,
Name : "foo" ,
UID : "8764ae47-9092-11e4-8393-42010af018ff" ,
} ,
2018-03-20 16:45:19 +00:00
Spec : apps . DaemonSetSpec {
UpdateStrategy : apps . DaemonSetUpdateStrategy {
Type : apps . OnDeleteDaemonSetStrategyType ,
2017-03-07 12:58:18 +00:00
} ,
} ,
}
2018-08-24 10:22:26 +00:00
unstructuredD := & unstructured . Unstructured { }
err := scheme . Scheme . Convert ( d , unstructuredD , nil )
if err != nil {
t . Fatal ( err )
}
2018-09-19 19:35:59 +00:00
dsv := & DaemonSetStatusViewer { }
2018-08-24 10:22:26 +00:00
msg , done , err := dsv . Status ( unstructuredD , 0 )
2018-08-03 22:59:34 +00:00
errMsg := "rollout status is only available for RollingUpdate strategy type"
2017-03-07 12:58:18 +00:00
if err == nil || err . Error ( ) != errMsg {
t . Errorf ( "Status for daemon sets with UpdateStrategy type different than RollingUpdate should return error. Instead got: msg: %s\ndone: %t\n err: %v" , msg , done , err )
}
}
2017-06-04 22:31:23 +00:00
func newStatefulSet ( replicas int32 ) * apps . StatefulSet {
return & apps . StatefulSet {
ObjectMeta : metav1 . ObjectMeta {
Name : "foo" ,
Namespace : metav1 . NamespaceDefault ,
Labels : map [ string ] string { "a" : "b" } ,
} ,
Spec : apps . StatefulSetSpec {
PodManagementPolicy : apps . OrderedReadyPodManagement ,
Selector : & metav1 . LabelSelector { MatchLabels : map [ string ] string { "a" : "b" } } ,
Template : api . PodTemplateSpec {
ObjectMeta : metav1 . ObjectMeta {
Labels : map [ string ] string { "a" : "b" } ,
} ,
Spec : api . PodSpec {
Containers : [ ] api . Container {
{
Name : "test" ,
Image : "test_image" ,
ImagePullPolicy : api . PullIfNotPresent ,
} ,
} ,
RestartPolicy : api . RestartPolicyAlways ,
DNSPolicy : api . DNSClusterFirst ,
} ,
} ,
2017-10-24 15:56:54 +00:00
Replicas : & replicas ,
2017-06-04 22:31:23 +00:00
UpdateStrategy : apps . StatefulSetUpdateStrategy { Type : apps . RollingUpdateStatefulSetStrategyType } ,
} ,
Status : apps . StatefulSetStatus { } ,
}
}