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