Skip to content

Commit e086c05

Browse files
authored
Add OS and k8s util tests (#77)
* Add supported nodes validation tests Signed-off-by: Atanas Dinov <[email protected]> * Fix test failures Signed-off-by: Atanas Dinov <[email protected]> * Add OS upgrade check tests Signed-off-by: Atanas Dinov <[email protected]> * Add Kubernetes upgraded check tests Signed-off-by: Atanas Dinov <[email protected]> * Add control plane check tests Signed-off-by: Atanas Dinov <[email protected]> * Add target kubernetes version tests Signed-off-by: Atanas Dinov <[email protected]> --------- Signed-off-by: Atanas Dinov <[email protected]>
1 parent 05331c7 commit e086c05

File tree

4 files changed

+460
-5
lines changed

4 files changed

+460
-5
lines changed
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
package controller
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
"github.com/stretchr/testify/require"
8+
lifecyclev1alpha1 "github.com/suse-edge/upgrade-controller/api/v1alpha1"
9+
10+
corev1 "k8s.io/api/core/v1"
11+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12+
"k8s.io/apimachinery/pkg/labels"
13+
)
14+
15+
func TestIsKubernetesUpgraded(t *testing.T) {
16+
const kubernetesVersion = "v1.30.3+k3s1"
17+
18+
nodeLabels := map[string]string{
19+
"node-x": "z",
20+
}
21+
22+
tests := []struct {
23+
name string
24+
nodes *corev1.NodeList
25+
selector labels.Selector
26+
expectedUpgrade bool
27+
}{
28+
{
29+
name: "All matching nodes upgraded",
30+
nodes: &corev1.NodeList{
31+
Items: []corev1.Node{
32+
{
33+
ObjectMeta: metav1.ObjectMeta{Labels: nodeLabels},
34+
Spec: corev1.NodeSpec{Unschedulable: false},
35+
Status: corev1.NodeStatus{
36+
Conditions: []corev1.NodeCondition{{Type: corev1.NodeReady, Status: corev1.ConditionTrue}},
37+
NodeInfo: corev1.NodeSystemInfo{KubeletVersion: "v1.30.3+k3s1"}},
38+
},
39+
{
40+
ObjectMeta: metav1.ObjectMeta{Labels: nodeLabels},
41+
Spec: corev1.NodeSpec{Unschedulable: false},
42+
Status: corev1.NodeStatus{
43+
Conditions: []corev1.NodeCondition{{Type: corev1.NodeReady, Status: corev1.ConditionTrue}},
44+
NodeInfo: corev1.NodeSystemInfo{KubeletVersion: "v1.30.3+k3s1"}},
45+
},
46+
{
47+
Status: corev1.NodeStatus{
48+
Conditions: []corev1.NodeCondition{{Type: corev1.NodeReady, Status: corev1.ConditionTrue}},
49+
NodeInfo: corev1.NodeSystemInfo{KubeletVersion: "v1.28.12+k3s1"}},
50+
},
51+
},
52+
},
53+
selector: labels.SelectorFromSet(nodeLabels),
54+
expectedUpgrade: true,
55+
},
56+
{
57+
name: "Unschedulable matching node",
58+
nodes: &corev1.NodeList{
59+
Items: []corev1.Node{
60+
{
61+
ObjectMeta: metav1.ObjectMeta{Labels: nodeLabels},
62+
Spec: corev1.NodeSpec{Unschedulable: true},
63+
Status: corev1.NodeStatus{
64+
Conditions: []corev1.NodeCondition{{Type: corev1.NodeReady, Status: corev1.ConditionTrue}},
65+
NodeInfo: corev1.NodeSystemInfo{KubeletVersion: "v1.30.3+k3s1"}},
66+
},
67+
{
68+
ObjectMeta: metav1.ObjectMeta{Labels: nodeLabels},
69+
Spec: corev1.NodeSpec{Unschedulable: false},
70+
Status: corev1.NodeStatus{
71+
Conditions: []corev1.NodeCondition{{Type: corev1.NodeReady, Status: corev1.ConditionTrue}},
72+
NodeInfo: corev1.NodeSystemInfo{KubeletVersion: "v1.30.3+k3s1"}},
73+
},
74+
{
75+
Status: corev1.NodeStatus{
76+
Conditions: []corev1.NodeCondition{{Type: corev1.NodeReady, Status: corev1.ConditionTrue}},
77+
NodeInfo: corev1.NodeSystemInfo{KubeletVersion: "v1.28.12+k3s1"}},
78+
},
79+
},
80+
},
81+
selector: labels.SelectorFromSet(nodeLabels),
82+
expectedUpgrade: false,
83+
},
84+
{
85+
name: "Not ready matching node",
86+
nodes: &corev1.NodeList{
87+
Items: []corev1.Node{
88+
{
89+
ObjectMeta: metav1.ObjectMeta{Labels: nodeLabels},
90+
Spec: corev1.NodeSpec{Unschedulable: false},
91+
Status: corev1.NodeStatus{
92+
Conditions: []corev1.NodeCondition{{Type: corev1.NodeReady, Status: corev1.ConditionFalse}},
93+
NodeInfo: corev1.NodeSystemInfo{KubeletVersion: "v1.30.3+k3s1"}},
94+
},
95+
{
96+
ObjectMeta: metav1.ObjectMeta{Labels: nodeLabels},
97+
Spec: corev1.NodeSpec{Unschedulable: false},
98+
Status: corev1.NodeStatus{
99+
Conditions: []corev1.NodeCondition{{Type: corev1.NodeReady, Status: corev1.ConditionTrue}},
100+
NodeInfo: corev1.NodeSystemInfo{KubeletVersion: "v1.30.3+k3s1"}},
101+
},
102+
{
103+
Status: corev1.NodeStatus{
104+
Conditions: []corev1.NodeCondition{{Type: corev1.NodeReady, Status: corev1.ConditionTrue}},
105+
NodeInfo: corev1.NodeSystemInfo{KubeletVersion: "v1.28.12+k3s1"}},
106+
},
107+
},
108+
},
109+
selector: labels.SelectorFromSet(nodeLabels),
110+
expectedUpgrade: false,
111+
},
112+
{
113+
name: "Matching node on older Kubernetes version",
114+
nodes: &corev1.NodeList{
115+
Items: []corev1.Node{
116+
{
117+
ObjectMeta: metav1.ObjectMeta{Labels: nodeLabels},
118+
Spec: corev1.NodeSpec{Unschedulable: false},
119+
Status: corev1.NodeStatus{
120+
Conditions: []corev1.NodeCondition{{Type: corev1.NodeReady, Status: corev1.ConditionTrue}},
121+
NodeInfo: corev1.NodeSystemInfo{KubeletVersion: "v1.28.12+k3s1"}},
122+
},
123+
{
124+
ObjectMeta: metav1.ObjectMeta{Labels: nodeLabels},
125+
Spec: corev1.NodeSpec{Unschedulable: false},
126+
Status: corev1.NodeStatus{
127+
Conditions: []corev1.NodeCondition{{Type: corev1.NodeReady, Status: corev1.ConditionTrue}},
128+
NodeInfo: corev1.NodeSystemInfo{KubeletVersion: "v1.30.3+k3s1"}},
129+
},
130+
{
131+
Status: corev1.NodeStatus{
132+
Conditions: []corev1.NodeCondition{{Type: corev1.NodeReady, Status: corev1.ConditionTrue}},
133+
NodeInfo: corev1.NodeSystemInfo{KubeletVersion: "v1.28.12+k3s1"}},
134+
},
135+
},
136+
},
137+
selector: labels.SelectorFromSet(nodeLabels),
138+
expectedUpgrade: false,
139+
},
140+
}
141+
142+
for _, test := range tests {
143+
t.Run(test.name, func(t *testing.T) {
144+
assert.Equal(t, test.expectedUpgrade, isKubernetesUpgraded(test.nodes, test.selector, kubernetesVersion))
145+
})
146+
}
147+
}
148+
149+
func TestControlPlaneOnlyCluster(t *testing.T) {
150+
assert.True(t, controlPlaneOnlyCluster(&corev1.NodeList{
151+
Items: []corev1.Node{
152+
{ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"node-role.kubernetes.io/control-plane": "true"}}},
153+
{ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"node-role.kubernetes.io/control-plane": "true"}}},
154+
},
155+
}))
156+
157+
assert.False(t, controlPlaneOnlyCluster(&corev1.NodeList{
158+
Items: []corev1.Node{
159+
{ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"node-role.kubernetes.io/control-plane": "true"}}},
160+
{ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"node-role.kubernetes.io/control-plane": "false"}}},
161+
},
162+
}))
163+
164+
assert.False(t, controlPlaneOnlyCluster(&corev1.NodeList{
165+
Items: []corev1.Node{
166+
{ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"node-role.kubernetes.io/control-plane": "true"}}},
167+
{ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{}}},
168+
},
169+
}))
170+
171+
assert.False(t, controlPlaneOnlyCluster(&corev1.NodeList{
172+
Items: []corev1.Node{
173+
{ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{}}},
174+
},
175+
}))
176+
}
177+
178+
func TestTargetKubernetesVersion(t *testing.T) {
179+
kubernetes := &lifecyclev1alpha1.Kubernetes{
180+
K3S: lifecyclev1alpha1.KubernetesDistribution{
181+
Version: "v1.30.3+k3s1",
182+
},
183+
RKE2: lifecyclev1alpha1.KubernetesDistribution{
184+
Version: "v1.30.3+rke2r1",
185+
},
186+
}
187+
188+
tests := []struct {
189+
name string
190+
nodes *corev1.NodeList
191+
expectedVersion string
192+
expectedError string
193+
}{
194+
{
195+
name: "Empty node list",
196+
nodes: &corev1.NodeList{},
197+
expectedError: "unable to determine current kubernetes version due to empty node list",
198+
},
199+
{
200+
name: "Unsupported Kubernetes version",
201+
nodes: &corev1.NodeList{
202+
Items: []corev1.Node{{Status: corev1.NodeStatus{NodeInfo: corev1.NodeSystemInfo{KubeletVersion: "v1.30.3"}}}},
203+
},
204+
expectedError: "upgrading from kubernetes version v1.30.3 is not supported",
205+
},
206+
{
207+
name: "Target k3s version",
208+
nodes: &corev1.NodeList{
209+
Items: []corev1.Node{{Status: corev1.NodeStatus{NodeInfo: corev1.NodeSystemInfo{KubeletVersion: "v1.28.12+k3s1"}}}},
210+
},
211+
expectedVersion: "v1.30.3+k3s1",
212+
},
213+
{
214+
name: "Target RKE2 version",
215+
nodes: &corev1.NodeList{
216+
Items: []corev1.Node{{Status: corev1.NodeStatus{NodeInfo: corev1.NodeSystemInfo{KubeletVersion: "v1.28.12+rke2r1"}}}},
217+
},
218+
expectedVersion: "v1.30.3+rke2r1",
219+
},
220+
}
221+
222+
for _, test := range tests {
223+
t.Run(test.name, func(t *testing.T) {
224+
version, err := targetKubernetesVersion(test.nodes, kubernetes)
225+
if test.expectedError != "" {
226+
require.Error(t, err)
227+
assert.EqualError(t, err, test.expectedError)
228+
assert.Empty(t, version)
229+
} else {
230+
require.NoError(t, err)
231+
assert.Equal(t, test.expectedVersion, version)
232+
}
233+
})
234+
}
235+
}

internal/controller/reconcile_os.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ func validateOSArch(nodeList *corev1.NodeList, supportedArchs []lifecyclev1alpha
129129
for _, node := range nodeList.Items {
130130
nodeArch := node.Status.NodeInfo.Architecture
131131
if _, ok := supportedArchMap[nodeArch]; !ok {
132-
return fmt.Errorf("unsuported arch '%s' for '%s' node. Supported archs: %s", nodeArch, node.Name, supportedArchs)
132+
return fmt.Errorf("unsupported arch '%s' for '%s' node. Supported archs: %s", nodeArch, node.Name, supportedArchs)
133133
}
134134
}
135135

0 commit comments

Comments
 (0)