karmada/pkg/util/helper/pod_test.go

754 lines
17 KiB
Go

package helper
import (
"reflect"
"testing"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/sets"
configv1alpha1 "github.com/karmada-io/karmada/pkg/apis/config/v1alpha1"
"github.com/karmada-io/karmada/test/helper"
)
var (
namespace = "karmada-test"
podName = "fake-pod"
)
func TestGetPodCondition(t *testing.T) {
type args struct {
status *corev1.PodStatus
conditionType corev1.PodConditionType
}
tests := []struct {
name string
args args
wantedOrder int
wantCondition *corev1.PodCondition
}{
{
name: "empty status",
args: args{
status: nil,
conditionType: corev1.ContainersReady,
},
wantedOrder: -1,
wantCondition: nil,
},
{
name: "empty condition",
args: args{
status: &corev1.PodStatus{Conditions: nil},
conditionType: corev1.ContainersReady,
},
wantedOrder: -1,
wantCondition: nil,
},
{
name: "doesn't have objective condition",
args: args{
status: &corev1.PodStatus{
Conditions: []corev1.PodCondition{
{
Type: corev1.PodInitialized,
},
},
},
conditionType: corev1.ContainersReady,
},
wantedOrder: -1,
wantCondition: nil,
},
{
name: "have objective condition",
args: args{
status: &corev1.PodStatus{
Conditions: []corev1.PodCondition{
{
Type: corev1.PodInitialized,
},
{
Type: corev1.ContainersReady,
},
},
},
conditionType: corev1.ContainersReady,
},
wantedOrder: 1,
wantCondition: &corev1.PodCondition{
Type: corev1.ContainersReady,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, got1 := GetPodCondition(tt.args.status, tt.args.conditionType)
if got != tt.wantedOrder {
t.Errorf("GetPodCondition() got = %v, wantedOrder %v", got, tt.wantedOrder)
}
if !reflect.DeepEqual(got1, tt.wantCondition) {
t.Errorf("GetPodCondition() got1 = %v, wantedOrder %v", got1, tt.wantCondition)
}
})
}
}
func TestGetPodConditionFromList(t *testing.T) {
type args struct {
conditions []corev1.PodCondition
conditionType corev1.PodConditionType
}
var tests = []struct {
name string
args args
wantedOrder int
wantCondition *corev1.PodCondition
}{
{
name: "empty condition",
args: args{
conditions: nil,
conditionType: corev1.ContainersReady,
},
wantedOrder: -1,
wantCondition: nil,
},
{
name: "doesn't have objective condition",
args: args{
conditions: []corev1.PodCondition{
{
Type: corev1.PodInitialized,
},
},
conditionType: corev1.ContainersReady,
},
wantedOrder: -1,
wantCondition: nil,
},
{
name: "have objective condition",
args: args{
conditions: []corev1.PodCondition{
{
Type: corev1.PodInitialized,
},
{
Type: corev1.ContainersReady,
},
},
conditionType: corev1.ContainersReady,
},
wantedOrder: 1,
wantCondition: &corev1.PodCondition{
Type: corev1.ContainersReady,
},
},
{
name: "PodReady condition",
args: args{
conditions: []corev1.PodCondition{
{
Type: corev1.PodInitialized,
},
{
Type: corev1.PodReady,
},
},
conditionType: corev1.ContainersReady,
},
wantedOrder: -1,
wantCondition: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, got1 := GetPodConditionFromList(tt.args.conditions, tt.args.conditionType)
if got != tt.wantedOrder {
t.Errorf("GetPodConditionFromList() got = %v, wantedOrder %v", got, tt.wantedOrder)
}
if !reflect.DeepEqual(got1, tt.wantCondition) {
t.Errorf("GetPodConditionFromList() got1 = %v, wantedOrder %v", got1, tt.wantCondition)
}
})
}
}
func TestGeneratePodFromTemplateAndNamespace(t *testing.T) {
pod1 := helper.NewPod(namespace, podName)
pod2 := helper.NewPod(namespace, podName)
pod2.Spec.ServiceAccountName = "fake-sa"
type args struct {
template *corev1.PodTemplateSpec
namespace string
}
tests := []struct {
name string
args args
expected corev1.Pod
}{
{
name: "generate a simple pod from template and namespace without dependency",
args: args{
template: &corev1.PodTemplateSpec{Spec: pod1.Spec},
namespace: "test1",
},
expected: corev1.Pod{
ObjectMeta: metav1.ObjectMeta{Namespace: "test1"},
Spec: *pod1.Spec.DeepCopy(),
},
},
{
name: "generate a simple pod from template and namespace",
args: args{
template: &corev1.PodTemplateSpec{Spec: pod2.Spec},
namespace: "test2",
},
expected: corev1.Pod{
ObjectMeta: metav1.ObjectMeta{Namespace: "test2"},
Spec: *pod2.Spec.DeepCopy(),
},
},
}
for i := range tests {
tt := tests[i]
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
if got := GeneratePodFromTemplateAndNamespace(tt.args.template, tt.args.namespace); !reflect.DeepEqual(*got, tt.expected) {
t.Errorf("GeneratePodFromTemplateAndNamespace() = %v,\n want %v", got, tt.expected)
}
})
}
}
func TestGetSecretNames(t *testing.T) {
emptySecretsPod := helper.NewPod(namespace, podName)
secretsPod := helper.NewPod(namespace, podName)
secretsPod.Spec.ImagePullSecrets = []corev1.LocalObjectReference{
{
Name: "image-secret",
},
}
secretsPod.Spec.InitContainers = []corev1.Container{
{
EnvFrom: []corev1.EnvFromSource{
{
SecretRef: &corev1.SecretEnvSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: "initcontainer-envfrom-secret",
},
},
},
},
Env: []corev1.EnvVar{
{
ValueFrom: &corev1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "initcontainer-env-secret",
},
},
},
},
},
},
}
secretsPod.Spec.Containers = []corev1.Container{
{
EnvFrom: []corev1.EnvFromSource{
{
SecretRef: &corev1.SecretEnvSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: "container-envfrom-secret",
},
},
},
},
Env: []corev1.EnvVar{
{
ValueFrom: &corev1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "container-env-secret",
},
},
},
},
},
},
}
secretsPod.Spec.EphemeralContainers = []corev1.EphemeralContainer{
{
EphemeralContainerCommon: corev1.EphemeralContainerCommon{
EnvFrom: []corev1.EnvFromSource{
{
SecretRef: &corev1.SecretEnvSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: "ephemeralcontainer-envfrom-secret",
},
},
},
},
Env: []corev1.EnvVar{
{
ValueFrom: &corev1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "ephemeralcontainer-env-secret",
},
},
},
},
},
},
},
}
secretsPod.Spec.Volumes = []corev1.Volume{
{
VolumeSource: corev1.VolumeSource{
AzureFile: &corev1.AzureFileVolumeSource{
SecretName: "azure-secret",
},
},
},
{
VolumeSource: corev1.VolumeSource{
CephFS: &corev1.CephFSVolumeSource{
SecretRef: &corev1.LocalObjectReference{
Name: "cephfs-secret",
},
},
},
},
{
VolumeSource: corev1.VolumeSource{
Cinder: &corev1.CinderVolumeSource{
SecretRef: &corev1.LocalObjectReference{
Name: "cinder-secret",
},
},
},
},
{
VolumeSource: corev1.VolumeSource{
FlexVolume: &corev1.FlexVolumeSource{
SecretRef: &corev1.LocalObjectReference{
Name: "flex-secret",
},
},
},
},
{
VolumeSource: corev1.VolumeSource{
Projected: &corev1.ProjectedVolumeSource{
Sources: []corev1.VolumeProjection{
{
Secret: &corev1.SecretProjection{
LocalObjectReference: corev1.LocalObjectReference{
Name: "projected-secret",
},
},
},
},
},
},
},
{
VolumeSource: corev1.VolumeSource{
RBD: &corev1.RBDVolumeSource{
SecretRef: &corev1.LocalObjectReference{
Name: "rbd-secret",
},
},
},
},
{
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: "secret-config",
},
},
},
{
VolumeSource: corev1.VolumeSource{
ScaleIO: &corev1.ScaleIOVolumeSource{
SecretRef: &corev1.LocalObjectReference{
Name: "scaleio-secret",
},
},
},
},
{
VolumeSource: corev1.VolumeSource{
ISCSI: &corev1.ISCSIVolumeSource{
SecretRef: &corev1.LocalObjectReference{
Name: "iscsi-secret",
},
},
},
},
{
VolumeSource: corev1.VolumeSource{
StorageOS: &corev1.StorageOSVolumeSource{
SecretRef: &corev1.LocalObjectReference{
Name: "storageos-secret",
},
},
},
},
{
VolumeSource: corev1.VolumeSource{
CSI: &corev1.CSIVolumeSource{
NodePublishSecretRef: &corev1.LocalObjectReference{
Name: "csi-secret",
},
},
},
},
}
tests := []struct {
name string
pod *corev1.Pod
expected sets.Set[string]
}{
{
name: "get secret names from pod without secrets",
pod: emptySecretsPod,
expected: make(sets.Set[string], 0),
},
{
name: "get secret names from pod with secrets",
pod: secretsPod,
expected: sets.New("image-secret", "initcontainer-envfrom-secret", "initcontainer-env-secret", "container-envfrom-secret", "container-env-secret",
"ephemeralcontainer-envfrom-secret", "ephemeralcontainer-env-secret", "azure-secret", "cephfs-secret", "cinder-secret", "flex-secret", "projected-secret",
"rbd-secret", "secret-config", "scaleio-secret", "iscsi-secret", "storageos-secret", "csi-secret"),
},
}
for i := range tests {
tt := tests[i]
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
res := getSecretNames(tt.pod)
if !res.Equal(tt.expected) {
t.Errorf("getSecretNames() = %v, want %v", res, tt.expected)
}
})
}
}
func TestGetConfigMapNames(t *testing.T) {
emptyConfigMapsPod := helper.NewPod(namespace, podName)
configMapsPod := helper.NewPod(namespace, podName)
configMapsPod.Spec.InitContainers = []corev1.Container{
{
EnvFrom: []corev1.EnvFromSource{
{
ConfigMapRef: &corev1.ConfigMapEnvSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: "initcontainer-envfrom-configmap",
},
},
},
},
Env: []corev1.EnvVar{
{
ValueFrom: &corev1.EnvVarSource{
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "initcontainer-env-configmap",
},
},
},
},
},
},
}
configMapsPod.Spec.Containers = []corev1.Container{
{
EnvFrom: []corev1.EnvFromSource{
{
ConfigMapRef: &corev1.ConfigMapEnvSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: "container-envfrom-configmap",
},
},
},
},
Env: []corev1.EnvVar{
{
ValueFrom: &corev1.EnvVarSource{
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "container-env-configmap",
},
},
},
},
},
},
}
configMapsPod.Spec.EphemeralContainers = []corev1.EphemeralContainer{
{
EphemeralContainerCommon: corev1.EphemeralContainerCommon{
EnvFrom: []corev1.EnvFromSource{
{
ConfigMapRef: &corev1.ConfigMapEnvSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: "ephemeralcontainer-envfrom-configmap",
},
},
},
},
Env: []corev1.EnvVar{
{
ValueFrom: &corev1.EnvVarSource{
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "ephemeralcontainer-env-configmap",
},
},
},
},
},
},
},
}
configMapsPod.Spec.Volumes = []corev1.Volume{
{
VolumeSource: corev1.VolumeSource{
Projected: &corev1.ProjectedVolumeSource{
Sources: []corev1.VolumeProjection{
{
ConfigMap: &corev1.ConfigMapProjection{
LocalObjectReference: corev1.LocalObjectReference{
Name: "projected-configmap",
},
},
},
},
},
},
},
{
VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: "configmap-config",
},
},
},
},
}
tests := []struct {
name string
pod *corev1.Pod
expected sets.Set[string]
}{
{
name: "get configMap names from pod without configMaps",
pod: emptyConfigMapsPod,
expected: make(sets.Set[string], 0),
},
{
name: "get configMap names from pod with configMaps",
pod: configMapsPod,
expected: sets.New("initcontainer-envfrom-configmap", "initcontainer-env-configmap", "container-envfrom-configmap", "container-env-configmap",
"ephemeralcontainer-envfrom-configmap", "ephemeralcontainer-env-configmap", "projected-configmap", "configmap-config"),
},
}
for i := range tests {
tt := tests[i]
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
res := getConfigMapNames(tt.pod)
if !res.Equal(tt.expected) {
t.Errorf("getConfigMapNames() = %v, want %v", res, tt.expected)
}
})
}
}
func TestGetPVCNames(t *testing.T) {
emptyPvcsPod := helper.NewPod(namespace, podName)
pvcsPod := helper.NewPod(namespace, podName)
pvcsPod.Spec.Volumes = []corev1.Volume{
{
Name: "foo-name",
VolumeSource: corev1.VolumeSource{
PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
ClaimName: "fake-foo",
ReadOnly: true,
},
},
},
{
Name: "bar-name",
VolumeSource: corev1.VolumeSource{
PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
ClaimName: "fake-bar",
ReadOnly: true,
},
},
},
}
tests := []struct {
name string
pod *corev1.Pod
expected sets.Set[string]
}{
{
name: "get pvc names from pod without pvcs",
pod: emptyPvcsPod,
expected: make(sets.Set[string], 0),
},
{
name: "get pvc names from pod with pvcs",
pod: pvcsPod,
expected: sets.New("fake-foo", "fake-bar"),
},
}
for i := range tests {
tt := tests[i]
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
res := getPVCNames(tt.pod)
if !res.Equal(tt.expected) {
t.Errorf("getPVCNames() = %v, want %v", res, tt.expected)
}
})
}
}
func TestGetDependenciesFromPodTemplate(t *testing.T) {
emptyDependenciesPod := helper.NewPod(namespace, podName)
dependenciesPod := helper.NewPod(namespace, podName)
dependenciesPod.Spec.Volumes = []corev1.Volume{
{
Name: "foo-name",
VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: "fake-foo",
},
},
},
},
{
Name: "bar-name",
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: "fake-bar",
},
},
},
{
Name: "pvc-name",
VolumeSource: corev1.VolumeSource{
PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
ClaimName: "fake-pvc",
},
},
},
}
dependenciesPod.Spec.ServiceAccountName = "fake-sa"
tests := []struct {
name string
pod *corev1.Pod
expected []configv1alpha1.DependentObjectReference
}{
{
name: "get dependencies from PodTemplate without dependencies",
pod: emptyDependenciesPod,
expected: nil,
},
{
name: "get dependencies from PodTemplate with dependencies",
pod: dependenciesPod,
expected: []configv1alpha1.DependentObjectReference{
{
APIVersion: "v1",
Kind: "ConfigMap",
Namespace: namespace,
Name: "fake-foo",
},
{
APIVersion: "v1",
Kind: "Secret",
Namespace: namespace,
Name: "fake-bar",
},
{
APIVersion: "v1",
Kind: "ServiceAccount",
Namespace: namespace,
Name: "fake-sa",
},
{
APIVersion: "v1",
Kind: "PersistentVolumeClaim",
Namespace: namespace,
Name: "fake-pvc",
},
},
},
}
for i := range tests {
tt := tests[i]
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
res, _ := GetDependenciesFromPodTemplate(tt.pod)
if len(res) == 0 {
res = nil
}
if !reflect.DeepEqual(res, tt.expected) {
t.Errorf("getDependenciesFromPodTemplate() = %v, want %v", res, tt.expected)
}
})
}
}
func Test_getServiceAccountNames(t *testing.T) {
type args struct {
pod *corev1.Pod
}
tests := []struct {
name string
args args
want sets.Set[string]
}{
{
name: "get ServiceAccountName from pod ",
args: args{pod: &corev1.Pod{Spec: corev1.PodSpec{ServiceAccountName: "test"}}},
want: sets.New("test"),
},
{
name: "get default ServiceAccountName from pod ",
args: args{pod: &corev1.Pod{Spec: corev1.PodSpec{ServiceAccountName: "default"}}},
want: sets.New[string](),
},
}
for i := range tests {
tt := tests[i]
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
if got := getServiceAccountNames(tt.args.pod); !got.Equal(tt.want) {
t.Errorf("getServiceAccountNames() = %v, want %v", got, tt.want)
}
})
}
}