1/* 2Copyright 2021 The Kubernetes Authors. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package v1beta1 18 19import ( 20 "reflect" 21 "strings" 22 "testing" 23 24 "github.com/google/go-cmp/cmp" 25 "k8s.io/api/policy/v1beta1" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/apimachinery/pkg/runtime" 28 "k8s.io/kubernetes/pkg/apis/policy" 29) 30 31func TestConversion(t *testing.T) { 32 testcases := []struct { 33 Name string 34 In runtime.Object 35 Out runtime.Object 36 ExpectOut runtime.Object 37 ExpectErr string 38 }{ 39 { 40 Name: "v1beta1 to internal with empty selector", 41 In: &v1beta1.PodDisruptionBudget{ 42 Spec: v1beta1.PodDisruptionBudgetSpec{ 43 Selector: &metav1.LabelSelector{}, 44 }, 45 }, 46 Out: &policy.PodDisruptionBudget{}, 47 ExpectOut: &policy.PodDisruptionBudget{ 48 Spec: policy.PodDisruptionBudgetSpec{ 49 Selector: &metav1.LabelSelector{ 50 MatchExpressions: []metav1.LabelSelectorRequirement{ 51 { 52 Key: "pdb.kubernetes.io/deprecated-v1beta1-empty-selector-match", 53 Operator: metav1.LabelSelectorOpExists, 54 }, 55 }, 56 }, 57 }, 58 }, 59 }, 60 { 61 Name: "v1beta1 to internal with nil selector", 62 In: &v1beta1.PodDisruptionBudget{}, 63 Out: &policy.PodDisruptionBudget{}, 64 ExpectOut: &policy.PodDisruptionBudget{}, 65 }, 66 { 67 Name: "v1 to internal with existing selector", 68 In: &v1beta1.PodDisruptionBudget{ 69 Spec: v1beta1.PodDisruptionBudgetSpec{ 70 Selector: &metav1.LabelSelector{ 71 MatchLabels: map[string]string{ 72 "foo": "bar", 73 }, 74 }, 75 }, 76 }, 77 Out: &policy.PodDisruptionBudget{}, 78 ExpectOut: &policy.PodDisruptionBudget{ 79 Spec: policy.PodDisruptionBudgetSpec{ 80 Selector: &metav1.LabelSelector{ 81 MatchLabels: map[string]string{ 82 "foo": "bar", 83 }, 84 }, 85 }, 86 }, 87 }, 88 { 89 Name: "v1beta1 to internal with existing pdb selector", 90 In: &v1beta1.PodDisruptionBudget{ 91 Spec: v1beta1.PodDisruptionBudgetSpec{ 92 Selector: &metav1.LabelSelector{ 93 MatchLabels: map[string]string{ 94 "foo": "bar", 95 }, 96 MatchExpressions: []metav1.LabelSelectorRequirement{ 97 { 98 Key: "pdb.kubernetes.io/deprecated-v1beta1-empty-selector-match", 99 Operator: metav1.LabelSelectorOpDoesNotExist, 100 }, 101 }, 102 }, 103 }, 104 }, 105 Out: &policy.PodDisruptionBudget{}, 106 ExpectOut: &policy.PodDisruptionBudget{ 107 Spec: policy.PodDisruptionBudgetSpec{ 108 Selector: &metav1.LabelSelector{ 109 MatchLabels: map[string]string{ 110 "foo": "bar", 111 }, 112 MatchExpressions: []metav1.LabelSelectorRequirement{}, 113 }, 114 }, 115 }, 116 }, 117 { 118 Name: "internal to v1beta1 with empty selector", 119 In: &policy.PodDisruptionBudget{ 120 Spec: policy.PodDisruptionBudgetSpec{ 121 Selector: &metav1.LabelSelector{}, 122 }, 123 }, 124 Out: &v1beta1.PodDisruptionBudget{}, 125 ExpectOut: &v1beta1.PodDisruptionBudget{ 126 Spec: v1beta1.PodDisruptionBudgetSpec{ 127 Selector: &metav1.LabelSelector{ 128 MatchExpressions: []metav1.LabelSelectorRequirement{ 129 { 130 Key: "pdb.kubernetes.io/deprecated-v1beta1-empty-selector-match", 131 Operator: metav1.LabelSelectorOpDoesNotExist, 132 }, 133 }, 134 }, 135 }, 136 }, 137 }, 138 { 139 Name: "internal to v1beta1 with nil selector", 140 In: &policy.PodDisruptionBudget{}, 141 Out: &v1beta1.PodDisruptionBudget{}, 142 ExpectOut: &v1beta1.PodDisruptionBudget{}, 143 }, 144 { 145 Name: "internal to v1beta1 with existing selector", 146 In: &policy.PodDisruptionBudget{ 147 Spec: policy.PodDisruptionBudgetSpec{ 148 Selector: &metav1.LabelSelector{ 149 MatchLabels: map[string]string{ 150 "foo": "bar", 151 }, 152 }, 153 }, 154 }, 155 Out: &v1beta1.PodDisruptionBudget{}, 156 ExpectOut: &v1beta1.PodDisruptionBudget{ 157 Spec: v1beta1.PodDisruptionBudgetSpec{ 158 Selector: &metav1.LabelSelector{ 159 MatchLabels: map[string]string{ 160 "foo": "bar", 161 }, 162 }, 163 }, 164 }, 165 }, 166 } 167 168 scheme := runtime.NewScheme() 169 if err := policy.AddToScheme(scheme); err != nil { 170 t.Fatal(err) 171 } 172 173 if err := AddToScheme(scheme); err != nil { 174 t.Fatal(err) 175 } 176 177 for _, tc := range testcases { 178 t.Run(tc.Name, func(t *testing.T) { 179 err := scheme.Convert(tc.In, tc.Out, nil) 180 if err != nil { 181 if len(tc.ExpectErr) == 0 { 182 t.Fatalf("unexpected error %v", err) 183 } 184 if !strings.Contains(err.Error(), tc.ExpectErr) { 185 t.Fatalf("expected error %s, got %v", tc.ExpectErr, err) 186 } 187 return 188 } 189 if len(tc.ExpectErr) > 0 { 190 t.Fatalf("expected error %s, got none", tc.ExpectErr) 191 } 192 if !reflect.DeepEqual(tc.Out, tc.ExpectOut) { 193 t.Fatalf("unexpected result:\n %s", cmp.Diff(tc.ExpectOut, tc.Out)) 194 } 195 }) 196 } 197} 198