From f0f47e399e150872ff625f0374a1fee8623bbbf5 Mon Sep 17 00:00:00 2001 From: yanxuean Date: Fri, 10 Nov 2017 15:44:51 +0800 Subject: [PATCH] add unit test for VisitPodConfigmapNames Signed-off-by: yanxuean --- pkg/api/pod/util_test.go | 103 +++++++++++++++++++++++++++++++++------ 1 file changed, 89 insertions(+), 14 deletions(-) diff --git a/pkg/api/pod/util_test.go b/pkg/api/pod/util_test.go index 169e7d116d6..503d5e70570 100644 --- a/pkg/api/pod/util_test.go +++ b/pkg/api/pod/util_test.go @@ -125,7 +125,7 @@ func TestPodSecrets(t *testing.T) { "Spec.Volumes[*].VolumeSource.ISCSI.SecretRef", "Spec.Volumes[*].VolumeSource.StorageOS.SecretRef", ) - secretPaths := collectSecretPaths(t, nil, "", reflect.TypeOf(&api.Pod{})) + secretPaths := collectResourcePaths(t, "secret", nil, "", reflect.TypeOf(&api.Pod{})) secretPaths = secretPaths.Difference(excludedSecretPaths) if missingPaths := expectedSecretPaths.Difference(secretPaths); len(missingPaths) > 0 { t.Logf("Missing expected secret paths:\n%s", strings.Join(missingPaths.List(), "\n")) @@ -146,36 +146,111 @@ func TestPodSecrets(t *testing.T) { } } -// collectSecretPaths traverses the object, computing all the struct paths that lead to fields with "secret" in the name. -func collectSecretPaths(t *testing.T, path *field.Path, name string, tp reflect.Type) sets.String { - secretPaths := sets.NewString() +// collectResourcePaths traverses the object, computing all the struct paths that lead to fields with resourcename in the name. +func collectResourcePaths(t *testing.T, resourcename string, path *field.Path, name string, tp reflect.Type) sets.String { + resourcename = strings.ToLower(resourcename) + resourcePaths := sets.NewString() if tp.Kind() == reflect.Ptr { - secretPaths.Insert(collectSecretPaths(t, path, name, tp.Elem()).List()...) - return secretPaths + resourcePaths.Insert(collectResourcePaths(t, resourcename, path, name, tp.Elem()).List()...) + return resourcePaths } - if strings.Contains(strings.ToLower(name), "secret") { - secretPaths.Insert(path.String()) + if strings.Contains(strings.ToLower(name), resourcename) { + resourcePaths.Insert(path.String()) } switch tp.Kind() { case reflect.Ptr: - secretPaths.Insert(collectSecretPaths(t, path, name, tp.Elem()).List()...) + resourcePaths.Insert(collectResourcePaths(t, resourcename, path, name, tp.Elem()).List()...) case reflect.Struct: for i := 0; i < tp.NumField(); i++ { field := tp.Field(i) - secretPaths.Insert(collectSecretPaths(t, path.Child(field.Name), field.Name, field.Type).List()...) + resourcePaths.Insert(collectResourcePaths(t, resourcename, path.Child(field.Name), field.Name, field.Type).List()...) } case reflect.Interface: - t.Errorf("cannot find secret fields in interface{} field %s", path.String()) + t.Errorf("cannot find %s fields in interface{} field %s", resourcename, path.String()) case reflect.Map: - secretPaths.Insert(collectSecretPaths(t, path.Key("*"), "", tp.Elem()).List()...) + resourcePaths.Insert(collectResourcePaths(t, resourcename, path.Key("*"), "", tp.Elem()).List()...) case reflect.Slice: - secretPaths.Insert(collectSecretPaths(t, path.Key("*"), "", tp.Elem()).List()...) + resourcePaths.Insert(collectResourcePaths(t, resourcename, path.Key("*"), "", tp.Elem()).List()...) default: // all primitive types } - return secretPaths + return resourcePaths +} + +func TestPodConfigmaps(t *testing.T) { + // Stub containing all possible ConfigMap references in a pod. + // The names of the referenced ConfigMaps match struct paths detected by reflection. + pod := &api.Pod{ + Spec: api.PodSpec{ + Containers: []api.Container{{ + EnvFrom: []api.EnvFromSource{{ + ConfigMapRef: &api.ConfigMapEnvSource{ + LocalObjectReference: api.LocalObjectReference{ + Name: "Spec.Containers[*].EnvFrom[*].ConfigMapRef"}}}}, + Env: []api.EnvVar{{ + ValueFrom: &api.EnvVarSource{ + ConfigMapKeyRef: &api.ConfigMapKeySelector{ + LocalObjectReference: api.LocalObjectReference{ + Name: "Spec.Containers[*].Env[*].ValueFrom.ConfigMapKeyRef"}}}}}}}, + InitContainers: []api.Container{{ + EnvFrom: []api.EnvFromSource{{ + ConfigMapRef: &api.ConfigMapEnvSource{ + LocalObjectReference: api.LocalObjectReference{ + Name: "Spec.InitContainers[*].EnvFrom[*].ConfigMapRef"}}}}, + Env: []api.EnvVar{{ + ValueFrom: &api.EnvVarSource{ + ConfigMapKeyRef: &api.ConfigMapKeySelector{ + LocalObjectReference: api.LocalObjectReference{ + Name: "Spec.InitContainers[*].Env[*].ValueFrom.ConfigMapKeyRef"}}}}}}}, + Volumes: []api.Volume{{ + VolumeSource: api.VolumeSource{ + Projected: &api.ProjectedVolumeSource{ + Sources: []api.VolumeProjection{{ + ConfigMap: &api.ConfigMapProjection{ + LocalObjectReference: api.LocalObjectReference{ + Name: "Spec.Volumes[*].VolumeSource.Projected.Sources[*].ConfigMap"}}}}}}}, { + VolumeSource: api.VolumeSource{ + ConfigMap: &api.ConfigMapVolumeSource{ + LocalObjectReference: api.LocalObjectReference{ + Name: "Spec.Volumes[*].VolumeSource.ConfigMap"}}}}}, + }, + } + extractedNames := sets.NewString() + VisitPodConfigmapNames(pod, func(name string) bool { + extractedNames.Insert(name) + return true + }) + + // expectedPaths holds struct paths to fields with "ConfigMap" in the name that are references to ConfigMap API objects. + // every path here should be represented as an example in the Pod stub above, with the ConfigMap name set to the path. + expectedPaths := sets.NewString( + "Spec.Containers[*].EnvFrom[*].ConfigMapRef", + "Spec.Containers[*].Env[*].ValueFrom.ConfigMapKeyRef", + "Spec.InitContainers[*].EnvFrom[*].ConfigMapRef", + "Spec.InitContainers[*].Env[*].ValueFrom.ConfigMapKeyRef", + "Spec.Volumes[*].VolumeSource.Projected.Sources[*].ConfigMap", + "Spec.Volumes[*].VolumeSource.ConfigMap", + ) + collectPaths := collectResourcePaths(t, "ConfigMap", nil, "", reflect.TypeOf(&api.Pod{})) + if missingPaths := expectedPaths.Difference(collectPaths); len(missingPaths) > 0 { + t.Logf("Missing expected paths:\n%s", strings.Join(missingPaths.List(), "\n")) + t.Error("Missing expected paths. Verify VisitPodConfigmapNames() is correctly finding the missing paths, then correct expectedPaths") + } + if extraPaths := collectPaths.Difference(expectedPaths); len(extraPaths) > 0 { + t.Logf("Extra paths:\n%s", strings.Join(extraPaths.List(), "\n")) + t.Error("Extra fields with resource in the name found. Verify VisitPodConfigmapNames() is including these fields if appropriate, then correct expectedPaths") + } + + if missingNames := expectedPaths.Difference(extractedNames); len(missingNames) > 0 { + t.Logf("Missing expected names:\n%s", strings.Join(missingNames.List(), "\n")) + t.Error("Missing expected names. Verify the pod stub above includes these references, then verify VisitPodConfigmapNames() is correctly finding the missing names") + } + if extraNames := extractedNames.Difference(expectedPaths); len(extraNames) > 0 { + t.Logf("Extra names:\n%s", strings.Join(extraNames.List(), "\n")) + t.Error("Extra names extracted. Verify VisitPodConfigmapNames() is correctly extracting resource names") + } }