320 lines
8.5 KiB
Go
320 lines
8.5 KiB
Go
/*
|
|
Copyright 2020 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 deprecation
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
"k8s.io/apimachinery/pkg/version"
|
|
)
|
|
|
|
func TestMajorMinor(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
v version.Info
|
|
expectMajor int
|
|
expectMinor int
|
|
expectErr bool
|
|
}{
|
|
{
|
|
name: "empty",
|
|
v: version.Info{Major: "", Minor: ""},
|
|
expectMajor: 0,
|
|
expectMinor: 0,
|
|
expectErr: true,
|
|
},
|
|
{
|
|
name: "non-numeric major",
|
|
v: version.Info{Major: "A", Minor: "0"},
|
|
expectMajor: 0,
|
|
expectMinor: 0,
|
|
expectErr: true,
|
|
},
|
|
{
|
|
name: "non-numeric minor",
|
|
v: version.Info{Major: "1", Minor: "A"},
|
|
expectMajor: 0,
|
|
expectMinor: 0,
|
|
expectErr: true,
|
|
},
|
|
{
|
|
name: "valid",
|
|
v: version.Info{Major: "1", Minor: "2"},
|
|
expectMajor: 1,
|
|
expectMinor: 2,
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "valid zero",
|
|
v: version.Info{Major: "0", Minor: "0"},
|
|
expectMajor: 0,
|
|
expectMinor: 0,
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "valid zero decimal",
|
|
v: version.Info{Major: "01", Minor: "02"},
|
|
expectMajor: 1,
|
|
expectMinor: 2,
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "valid with extra minor",
|
|
v: version.Info{Major: "1", Minor: "2+"},
|
|
expectMajor: 1,
|
|
expectMinor: 2,
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "valid with extra minor",
|
|
v: version.Info{Major: "1", Minor: "2.3"},
|
|
expectMajor: 1,
|
|
expectMinor: 2,
|
|
expectErr: false,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
major, minor, err := MajorMinor(tt.v)
|
|
if (err != nil) != tt.expectErr {
|
|
t.Errorf("MajorMinor() error = %v, wantErr %v", err, tt.expectErr)
|
|
return
|
|
}
|
|
if major != tt.expectMajor {
|
|
t.Errorf("MajorMinor() major = %v, want %v", major, tt.expectMajor)
|
|
}
|
|
if minor != tt.expectMinor {
|
|
t.Errorf("MajorMinor() minor = %v, want %v", minor, tt.expectMinor)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestIsDeprecated(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
|
|
obj runtime.Object
|
|
currentMajor int
|
|
currentMinor int
|
|
|
|
want bool
|
|
}{
|
|
{
|
|
name: "no interface",
|
|
obj: &fakeObject{},
|
|
currentMajor: 0,
|
|
currentMinor: 0,
|
|
want: false,
|
|
},
|
|
{
|
|
name: "interface, zero-value",
|
|
obj: &fakeDeprecatedObject{},
|
|
currentMajor: 0,
|
|
currentMinor: 0,
|
|
want: false,
|
|
},
|
|
{
|
|
name: "interface, non-zero-value, no current value",
|
|
obj: &fakeDeprecatedObject{major: 10, minor: 20},
|
|
currentMajor: 0,
|
|
currentMinor: 0,
|
|
want: true,
|
|
},
|
|
{
|
|
name: "interface, non-zero-value matching major, minor",
|
|
obj: &fakeDeprecatedObject{major: 10, minor: 20},
|
|
currentMajor: 10,
|
|
currentMinor: 20,
|
|
want: true,
|
|
},
|
|
{
|
|
name: "interface, non-zero-value after major, after minor",
|
|
obj: &fakeDeprecatedObject{major: 10, minor: 20},
|
|
currentMajor: 9,
|
|
currentMinor: 19,
|
|
want: false,
|
|
},
|
|
{
|
|
name: "interface, non-zero-value after major, before minor",
|
|
obj: &fakeDeprecatedObject{major: 10, minor: 20},
|
|
currentMajor: 9,
|
|
currentMinor: 21,
|
|
want: false,
|
|
},
|
|
{
|
|
name: "interface, non-zero-value before major, after minor",
|
|
obj: &fakeDeprecatedObject{major: 10, minor: 20},
|
|
currentMajor: 11,
|
|
currentMinor: 19,
|
|
want: true,
|
|
},
|
|
{
|
|
name: "interface, non-zero-value before major, before minor",
|
|
obj: &fakeDeprecatedObject{major: 10, minor: 20},
|
|
currentMajor: 11,
|
|
currentMinor: 21,
|
|
want: true,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := IsDeprecated(tt.obj, tt.currentMajor, tt.currentMinor); got != tt.want {
|
|
t.Errorf("IsDeprecated() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRemovedRelease(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
obj runtime.Object
|
|
want string
|
|
}{
|
|
{
|
|
name: "no interface",
|
|
obj: &fakeObject{},
|
|
want: "",
|
|
},
|
|
{
|
|
name: "interface, zero-value",
|
|
obj: &fakeRemovedObject{removedMajor: 0, removedMinor: 0},
|
|
want: "",
|
|
},
|
|
{
|
|
name: "interface, non-zero major",
|
|
obj: &fakeRemovedObject{removedMajor: 1, removedMinor: 0},
|
|
want: "1.0",
|
|
},
|
|
{
|
|
name: "interface, non-zero minor",
|
|
obj: &fakeRemovedObject{removedMajor: 0, removedMinor: 1},
|
|
want: "0.1",
|
|
},
|
|
{
|
|
name: "interface, non-zero",
|
|
obj: &fakeRemovedObject{removedMajor: 1, removedMinor: 2},
|
|
want: "1.2",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := RemovedRelease(tt.obj); got != tt.want {
|
|
t.Errorf("RemovedRelease() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestWarningMessage(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
obj runtime.Object
|
|
gvk schema.GroupVersionKind
|
|
want string
|
|
}{
|
|
{
|
|
name: "no interface, zero-value",
|
|
obj: &fakeObject{},
|
|
want: "",
|
|
},
|
|
{
|
|
name: "deprecated interface, zero-value",
|
|
obj: &fakeDeprecatedObject{major: 0, minor: 0},
|
|
gvk: schema.GroupVersionKind{},
|
|
want: "",
|
|
},
|
|
{
|
|
name: "deprecated interface, non-zero-value",
|
|
obj: &fakeDeprecatedObject{major: 1, minor: 2},
|
|
gvk: schema.GroupVersionKind{Group: "mygroup", Version: "v1", Kind: "MyKind"},
|
|
want: "mygroup/v1 MyKind is deprecated in v1.2+",
|
|
},
|
|
{
|
|
name: "removed interface, zero-value removal version",
|
|
obj: &fakeRemovedObject{major: 1, minor: 2},
|
|
gvk: schema.GroupVersionKind{Group: "mygroup", Version: "v1", Kind: "MyKind"},
|
|
want: "mygroup/v1 MyKind is deprecated in v1.2+",
|
|
},
|
|
{
|
|
name: "removed interface, non-zero-value removal version",
|
|
obj: &fakeRemovedObject{major: 1, minor: 2, removedMajor: 3, removedMinor: 4},
|
|
gvk: schema.GroupVersionKind{Group: "mygroup", Version: "v1", Kind: "MyKind"},
|
|
want: "mygroup/v1 MyKind is deprecated in v1.2+, unavailable in v3.4+",
|
|
},
|
|
{
|
|
name: "replaced interface, zero-value replacement",
|
|
obj: &fakeReplacedObject{major: 1, minor: 2, removedMajor: 3, removedMinor: 4},
|
|
gvk: schema.GroupVersionKind{Group: "mygroup", Version: "v1", Kind: "MyKind"},
|
|
want: "mygroup/v1 MyKind is deprecated in v1.2+, unavailable in v3.4+",
|
|
},
|
|
{
|
|
name: "replaced interface, non-zero-value replacement",
|
|
obj: &fakeReplacedObject{major: 1, minor: 2, removedMajor: 3, removedMinor: 4, replacement: schema.GroupVersionKind{Group: "anothergroup", Version: "v2", Kind: "AnotherKind"}},
|
|
gvk: schema.GroupVersionKind{Group: "mygroup", Version: "v1", Kind: "MyKind"},
|
|
want: "mygroup/v1 MyKind is deprecated in v1.2+, unavailable in v3.4+; use anothergroup/v2 AnotherKind",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
tt.obj.GetObjectKind().SetGroupVersionKind(tt.gvk)
|
|
if got := WarningMessage(tt.obj); got != tt.want {
|
|
t.Errorf("WarningMessage() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
type fakeObject struct {
|
|
unstructured.Unstructured
|
|
}
|
|
type fakeDeprecatedObject struct {
|
|
unstructured.Unstructured
|
|
major int
|
|
minor int
|
|
}
|
|
|
|
func (f *fakeDeprecatedObject) APILifecycleDeprecated() (int, int) { return f.major, f.minor }
|
|
|
|
type fakeRemovedObject struct {
|
|
unstructured.Unstructured
|
|
major int
|
|
minor int
|
|
removedMajor int
|
|
removedMinor int
|
|
}
|
|
|
|
func (f *fakeRemovedObject) APILifecycleDeprecated() (int, int) { return f.major, f.minor }
|
|
func (f *fakeRemovedObject) APILifecycleRemoved() (int, int) { return f.removedMajor, f.removedMinor }
|
|
|
|
type fakeReplacedObject struct {
|
|
unstructured.Unstructured
|
|
major int
|
|
minor int
|
|
replacement schema.GroupVersionKind
|
|
removedMajor int
|
|
removedMinor int
|
|
}
|
|
|
|
func (f *fakeReplacedObject) APILifecycleDeprecated() (int, int) { return f.major, f.minor }
|
|
func (f *fakeReplacedObject) APILifecycleRemoved() (int, int) { return f.removedMajor, f.removedMinor }
|
|
func (f *fakeReplacedObject) APILifecycleReplacement() schema.GroupVersionKind { return f.replacement }
|