istio.io/istio@v0.0.0-20240520182934-d79c90f27776/operator/pkg/verifier/verify_test.go (about) 1 // Copyright Istio Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package verifier 16 17 import ( 18 "fmt" 19 "testing" 20 21 appsv1 "k8s.io/api/apps/v1" 22 "k8s.io/apimachinery/pkg/runtime/schema" 23 24 "istio.io/istio/pkg/config/schema/gvk" 25 ) 26 27 var ( 28 availableDeployment = appsv1.Deployment{ 29 Status: appsv1.DeploymentStatus{ 30 Conditions: []appsv1.DeploymentCondition{ 31 { 32 Type: appsv1.DeploymentAvailable, 33 }, 34 }, 35 }, 36 } 37 38 scaleUpRollingDeployment = appsv1.Deployment{ 39 Spec: appsv1.DeploymentSpec{ 40 Replicas: &[]int32{3}[0], 41 }, 42 Status: appsv1.DeploymentStatus{ 43 Conditions: []appsv1.DeploymentCondition{ 44 { 45 Type: appsv1.DeploymentProgressing, 46 }, 47 { 48 Type: appsv1.DeploymentAvailable, 49 }, 50 }, 51 UpdatedReplicas: 2, 52 }, 53 } 54 55 deletingOldRollingDeployment = appsv1.Deployment{ 56 Spec: appsv1.DeploymentSpec{ 57 Replicas: &[]int32{2}[0], 58 }, 59 Status: appsv1.DeploymentStatus{ 60 Conditions: []appsv1.DeploymentCondition{ 61 { 62 Type: appsv1.DeploymentProgressing, 63 }, 64 { 65 Type: appsv1.DeploymentAvailable, 66 }, 67 }, 68 UpdatedReplicas: 2, 69 AvailableReplicas: 2, 70 Replicas: 3, 71 }, 72 } 73 74 failedDeployment = appsv1.Deployment{ 75 Spec: appsv1.DeploymentSpec{ 76 Replicas: &[]int32{2}[0], 77 }, 78 Status: appsv1.DeploymentStatus{ 79 Conditions: []appsv1.DeploymentCondition{ 80 { 81 Type: appsv1.DeploymentReplicaFailure, 82 }, 83 }, 84 UpdatedReplicas: 2, 85 AvailableReplicas: 0, 86 Replicas: 3, 87 }, 88 } 89 90 deadlineExceededDeployment = appsv1.Deployment{ 91 Status: appsv1.DeploymentStatus{ 92 Conditions: []appsv1.DeploymentCondition{ 93 { 94 Type: appsv1.DeploymentProgressing, 95 Reason: "ProgressDeadlineExceeded", 96 }, 97 }, 98 }, 99 } 100 ) 101 102 func TestGetDeploymentStatus(t *testing.T) { 103 errCases := []*appsv1.Deployment{ 104 &scaleUpRollingDeployment, 105 &deletingOldRollingDeployment, 106 &failedDeployment, 107 &deadlineExceededDeployment, 108 } 109 for i, c := range errCases { 110 t.Run(fmt.Sprintf("[err-%v] ", i), func(tt *testing.T) { 111 if err := verifyDeploymentStatus(c); err == nil { 112 tt.Fatalf("unexpected nil error") 113 } 114 }) 115 } 116 117 okCases := []*appsv1.Deployment{ 118 &availableDeployment, 119 } 120 for i, c := range okCases { 121 t.Run(fmt.Sprintf("[ok-%v] ", i), func(tt *testing.T) { 122 if err := verifyDeploymentStatus(c); err != nil { 123 tt.Fatalf("unexpected error: %v", err) 124 } 125 }) 126 } 127 } 128 129 func TestGetDeploymentCondition(t *testing.T) { 130 cases := []struct { 131 status appsv1.DeploymentStatus 132 condType appsv1.DeploymentConditionType 133 shouldFind bool 134 }{ 135 { 136 // Simple "find Available in Available" 137 status: availableDeployment.Status, 138 condType: appsv1.DeploymentAvailable, 139 shouldFind: true, 140 }, 141 { 142 // find Available in Progressing,Available 143 // valid in e.g. RollingUpdate 144 status: scaleUpRollingDeployment.Status, 145 condType: appsv1.DeploymentAvailable, 146 shouldFind: true, 147 }, 148 { 149 // find Available in ReplicaFailure 150 status: failedDeployment.Status, 151 condType: appsv1.DeploymentAvailable, 152 shouldFind: false, 153 }, 154 } 155 156 for i, c := range cases { 157 t.Run(fmt.Sprintf("[%v] ", i), func(tt *testing.T) { 158 dc := getDeploymentCondition(c.status, c.condType) 159 if !c.shouldFind { 160 if dc != nil { 161 tt.Fatalf("unexpected condition: got %v want nil", dc) 162 } 163 } else { 164 if dc.Type != c.condType { 165 tt.Fatalf("unexpected condition: got %v want %v", dc, c.condType) 166 } 167 } 168 }) 169 } 170 } 171 172 func TestFindResourceInSpec(t *testing.T) { 173 cases := []struct { 174 kind schema.GroupVersionKind 175 plural string 176 }{ 177 { 178 // Should find Kubernetes resourcespecs 179 kind: gvk.Service.Kubernetes(), 180 plural: "services", 181 }, 182 { 183 // Should be empty for not-found 184 kind: schema.GroupVersionKind{Kind: "fake"}, 185 plural: "", 186 }, 187 { 188 // Should be empty for empty input 189 kind: schema.GroupVersionKind{}, 190 plural: "", 191 }, 192 } 193 194 for i, c := range cases { 195 t.Run(fmt.Sprintf("[%v] %v ", i, c.kind), func(tt *testing.T) { 196 plural := findResourceInSpec(c.kind) 197 if plural != c.plural { 198 tt.Fatalf("unexpected plural from kind: got %v want %v", plural, c.plural) 199 } 200 }) 201 } 202 }