karmada/pkg/karmadactl/cmdinit/kubernetes/node_test.go

287 lines
7.3 KiB
Go

/*
Copyright 2023 The Karmada 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 kubernetes
import (
"context"
"testing"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/fake"
)
func TestCommandInitOption_getKarmadaAPIServerIP(t *testing.T) {
tests := []struct {
name string
option CommandInitOption
nodes []string
labels map[string]string
wantErr bool
}{
{
name: "KarmadaAPIServerAdvertiseAddress is not empty",
option: CommandInitOption{
KubeClientSet: fake.NewSimpleClientset(),
KarmadaAPIServerAdvertiseAddress: "127.0.0.1",
},
nodes: []string{"node1"},
labels: map[string]string{},
wantErr: false,
},
{
name: "three nodes but they are not master",
option: CommandInitOption{
KubeClientSet: fake.NewSimpleClientset(),
},
nodes: []string{"node1", "node2", "node3"},
labels: map[string]string{},
wantErr: false,
},
{
name: "three master nodes",
option: CommandInitOption{
KubeClientSet: fake.NewSimpleClientset(),
},
nodes: []string{"node1", "node2", "node3"},
labels: map[string]string{"node-role.kubernetes.io/control-plane": ""},
wantErr: false,
},
{
name: "no nodes",
option: CommandInitOption{
KubeClientSet: fake.NewSimpleClientset(),
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
for _, v := range tt.nodes {
_, err := tt.option.KubeClientSet.CoreV1().Nodes().Create(context.Background(), &corev1.Node{
ObjectMeta: metav1.ObjectMeta{
Name: v,
Labels: tt.labels,
},
Status: corev1.NodeStatus{
Addresses: []corev1.NodeAddress{
{Address: "127.0.0.1"},
},
},
}, metav1.CreateOptions{})
if err != nil {
t.Errorf("create node error: %v", err)
}
}
if err := tt.option.getKarmadaAPIServerIP(); (err != nil) != tt.wantErr {
t.Errorf("CommandInitOption.getKarmadaAPIServerIP() = %v, want error:%v", err, tt.wantErr)
}
})
}
}
func Test_nodeStatus(t *testing.T) {
tests := []struct {
name string
nodeConditions []corev1.NodeCondition
isHealth bool
}{
{
name: "node is ready",
nodeConditions: []corev1.NodeCondition{
{Type: corev1.NodeReady, Status: corev1.ConditionTrue},
},
isHealth: true,
},
{
name: "node is unready",
nodeConditions: []corev1.NodeCondition{
{Type: corev1.NodeReady, Status: corev1.ConditionFalse},
},
isHealth: false,
},
{
name: "node's memory pressure is true",
nodeConditions: []corev1.NodeCondition{
{Type: corev1.NodeMemoryPressure, Status: corev1.ConditionTrue},
},
isHealth: false,
},
{
name: "node's memory pressure is false",
nodeConditions: []corev1.NodeCondition{
{Type: corev1.NodeMemoryPressure, Status: corev1.ConditionFalse},
},
isHealth: true,
},
{
name: "node's disk pressure is true",
nodeConditions: []corev1.NodeCondition{
{Type: corev1.NodeDiskPressure, Status: corev1.ConditionTrue},
},
isHealth: false,
},
{
name: "node's disk pressure is false",
nodeConditions: []corev1.NodeCondition{
{Type: corev1.NodeDiskPressure, Status: corev1.ConditionFalse},
},
isHealth: true,
},
{
name: "node's network unavailable is false",
nodeConditions: []corev1.NodeCondition{
{Type: corev1.NodeNetworkUnavailable, Status: corev1.ConditionFalse},
},
isHealth: true,
},
{
name: "node's network unavailable is true",
nodeConditions: []corev1.NodeCondition{
{Type: corev1.NodeNetworkUnavailable, Status: corev1.ConditionTrue},
},
isHealth: false,
},
{
name: "node's pid pressure is false",
nodeConditions: []corev1.NodeCondition{
{Type: corev1.NodePIDPressure, Status: corev1.ConditionFalse},
},
isHealth: true,
},
{
name: "node's pid pressure is true",
nodeConditions: []corev1.NodeCondition{
{Type: corev1.NodePIDPressure, Status: corev1.ConditionTrue},
},
isHealth: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := nodeStatus(tt.nodeConditions); got != tt.isHealth {
t.Errorf("nodeStatus() = %v, want %v", got, tt.isHealth)
}
})
}
}
func TestCommandInitOption_AddNodeSelectorLabels(t *testing.T) {
tests := []struct {
name string
option CommandInitOption
status corev1.ConditionStatus
spec corev1.NodeSpec
wantErr bool
}{
{
name: "there is healthy node",
option: CommandInitOption{
KubeClientSet: fake.NewSimpleClientset(),
},
status: corev1.ConditionTrue,
spec: corev1.NodeSpec{},
wantErr: false,
},
{
name: "there is unhealthy node",
option: CommandInitOption{
KubeClientSet: fake.NewSimpleClientset(),
},
status: corev1.ConditionFalse,
spec: corev1.NodeSpec{},
wantErr: true,
},
{
name: "there is taint node",
option: CommandInitOption{
KubeClientSet: fake.NewSimpleClientset(),
},
status: corev1.ConditionTrue,
spec: corev1.NodeSpec{
Taints: []corev1.Taint{
{
Effect: corev1.TaintEffectNoSchedule,
},
},
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, err := tt.option.KubeClientSet.CoreV1().Nodes().Create(context.Background(), &corev1.Node{
ObjectMeta: metav1.ObjectMeta{Name: "test-node"},
Status: corev1.NodeStatus{
Conditions: []corev1.NodeCondition{
{Type: corev1.NodeReady, Status: tt.status},
},
},
Spec: tt.spec,
}, metav1.CreateOptions{})
if err != nil {
t.Errorf("create node error: %v", err)
}
if err := tt.option.AddNodeSelectorLabels(); (err != nil) != tt.wantErr {
t.Errorf("CommandInitOption.AddNodeSelectorLabels() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
func TestCommandInitOption_isNodeExist(t *testing.T) {
tests := []struct {
name string
option CommandInitOption
nodeName string
labels map[string]string
exists bool
}{
{
name: "there is matched node",
option: CommandInitOption{
KubeClientSet: fake.NewSimpleClientset(),
},
nodeName: "node1",
labels: map[string]string{"foo": "bar"},
exists: true,
},
{
name: "there is no matched node",
option: CommandInitOption{
KubeClientSet: fake.NewSimpleClientset(),
},
nodeName: "node2",
labels: map[string]string{"bar": "foo"},
exists: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, err := tt.option.KubeClientSet.CoreV1().Nodes().Create(context.Background(), &corev1.Node{
ObjectMeta: metav1.ObjectMeta{Name: tt.nodeName, Labels: tt.labels},
}, metav1.CreateOptions{})
if err != nil {
t.Errorf("create node error: %v", err)
}
if got := tt.option.isNodeExist("foo=bar"); got != tt.exists {
t.Errorf("CommandInitOption.isNodeExist() = %v, want %v", got, tt.exists)
}
})
}
}