1/*
2Copyright 2018 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 apiregistration
18
19import (
20	"reflect"
21	"testing"
22)
23
24var (
25	a APIServiceConditionType = "A"
26	b APIServiceConditionType = "B"
27)
28
29func TestGetAPIServiceConditionByType(t *testing.T) {
30	conditionA := makeNewAPIServiceCondition(a, "a reason", "a message", ConditionTrue)
31	conditionB := makeNewAPIServiceCondition(b, "b reason", "b message", ConditionTrue)
32	tests := []*struct {
33		name              string
34		apiService        *APIService
35		conditionType     APIServiceConditionType
36		expectedCondition *APIServiceCondition
37	}{
38		{
39			name:              "Should find a matching condition from apiService",
40			apiService:        makeNewAPIService("v1", 100, conditionA, conditionB),
41			conditionType:     a,
42			expectedCondition: &conditionA,
43		},
44		{
45			name:              "Should not find a matching condition",
46			apiService:        makeNewAPIService("v1", 100, conditionA),
47			conditionType:     b,
48			expectedCondition: nil,
49		},
50	}
51
52	for _, tc := range tests {
53		actual := GetAPIServiceConditionByType(tc.apiService, tc.conditionType)
54		if !reflect.DeepEqual(tc.expectedCondition, actual) {
55			t.Errorf("expected %s, actual %s", tc.expectedCondition, actual)
56		}
57	}
58}
59
60func TestIsAPIServiceConditionTrue(t *testing.T) {
61	conditionATrue := makeNewAPIServiceCondition(a, "a reason", "a message", ConditionTrue)
62	conditionAFalse := makeNewAPIServiceCondition(a, "a reason", "a message", ConditionFalse)
63	tests := []*struct {
64		name          string
65		apiService    *APIService
66		conditionType APIServiceConditionType
67		expected      bool
68	}{
69		{
70			name:          "Should return false when condition of type is not present",
71			apiService:    makeNewAPIService("v1", 100),
72			conditionType: a,
73			expected:      false,
74		},
75		{
76			name:          "Should return false when condition of type is present but status is not ConditionTrue",
77			apiService:    makeNewAPIService("v1", 100, conditionAFalse),
78			conditionType: a,
79			expected:      false,
80		},
81		{
82			name:          "Should return false when condition of type is present but status is not ConditionTrue",
83			apiService:    makeNewAPIService("v1", 100, conditionATrue),
84			conditionType: a,
85			expected:      true,
86		},
87	}
88
89	for _, tc := range tests {
90		if isConditionTrue := IsAPIServiceConditionTrue(tc.apiService, tc.conditionType); isConditionTrue != tc.expected {
91			t.Errorf("expected condition of type %v to be %v, actually was %v",
92				tc.conditionType, isConditionTrue, tc.expected)
93
94		}
95	}
96}
97
98func TestSetAPIServiceCondition(t *testing.T) {
99	conditionA1 := makeNewAPIServiceCondition(a, "a1 reason", "a1 message", ConditionTrue)
100	conditionA2 := makeNewAPIServiceCondition(a, "a2 reason", "a2 message", ConditionTrue)
101	tests := []*struct {
102		name              string
103		apiService        *APIService
104		conditionType     APIServiceConditionType
105		initialCondition  *APIServiceCondition
106		setCondition      APIServiceCondition
107		expectedCondition *APIServiceCondition
108	}{
109		{
110			name:              "Should set a new condition with type where previously there was no condition of that type",
111			apiService:        makeNewAPIService("v1", 100),
112			conditionType:     a,
113			initialCondition:  nil,
114			setCondition:      conditionA1,
115			expectedCondition: &conditionA1,
116		},
117		{
118			name:              "Should override a condition of type, when a condition of that type existed previously",
119			apiService:        makeNewAPIService("v1", 100, conditionA1),
120			conditionType:     a,
121			initialCondition:  &conditionA1,
122			setCondition:      conditionA2,
123			expectedCondition: &conditionA2,
124		},
125	}
126
127	for _, tc := range tests {
128		startingCondition := GetAPIServiceConditionByType(tc.apiService, tc.conditionType)
129		if !reflect.DeepEqual(startingCondition, tc.initialCondition) {
130			t.Errorf("expected to find condition %s initially, actual was %s", tc.initialCondition, startingCondition)
131
132		}
133		SetAPIServiceCondition(tc.apiService, tc.setCondition)
134		actual := GetAPIServiceConditionByType(tc.apiService, tc.setCondition.Type)
135		if !reflect.DeepEqual(actual, tc.expectedCondition) {
136			t.Errorf("expected %s, actual %s", tc.expectedCondition, actual)
137		}
138	}
139}
140
141func TestSortedAPIServicesByVersion(t *testing.T) {
142	tests := []*struct {
143		name     string
144		versions []string
145		expected []string
146	}{
147		{
148			name:     "case1",
149			versions: []string{"v1", "v2"},
150			expected: []string{"v2", "v1"},
151		},
152		{
153			name:     "case2",
154			versions: []string{"v2", "v10"},
155			expected: []string{"v10", "v2"},
156		},
157		{
158			name:     "case3",
159			versions: []string{"v2", "v2beta1", "v10beta2", "v10beta1", "v10alpha1", "v1"},
160			expected: []string{"v2", "v1", "v10beta2", "v10beta1", "v2beta1", "v10alpha1"},
161		},
162		{
163			name:     "case4",
164			versions: []string{"v1", "v2", "test", "foo10", "final", "foo2", "foo1"},
165			expected: []string{"v2", "v1", "final", "foo1", "foo10", "foo2", "test"},
166		},
167		{
168			name:     "case5_from_documentation",
169			versions: []string{"v12alpha1", "v10", "v11beta2", "v10beta3", "v3beta1", "v2", "v11alpha2", "foo1", "v1", "foo10"},
170			expected: []string{"v10", "v2", "v1", "v11beta2", "v10beta3", "v3beta1", "v12alpha1", "v11alpha2", "foo1", "foo10"},
171		},
172	}
173
174	for _, tc := range tests {
175		apiServices := make([]*APIService, 0)
176		for _, v := range tc.versions {
177			apiServices = append(apiServices, makeNewAPIService(v, 100))
178		}
179		sortedServices := SortedByGroupAndVersion(apiServices)
180		actual := make([]string, 0)
181		for _, s := range sortedServices[0] {
182			actual = append(actual, s.Spec.Version)
183		}
184		if !reflect.DeepEqual(tc.expected, actual) {
185			t.Errorf("expected %s, actual %s", tc.expected, actual)
186		}
187	}
188}
189
190func makeNewAPIService(version string, priority int32, conditions ...APIServiceCondition) *APIService {
191	status := APIServiceStatus{Conditions: conditions}
192	return &APIService{Spec: APIServiceSpec{Version: version, VersionPriority: priority}, Status: status}
193}
194
195func makeNewAPIServiceCondition(conditionType APIServiceConditionType, reason string, message string, status ConditionStatus) APIServiceCondition {
196	return APIServiceCondition{Type: conditionType, Reason: reason, Message: message, Status: status}
197}
198