-
Notifications
You must be signed in to change notification settings - Fork 98
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create unit-test helper functions (#301)
- Loading branch information
1 parent
7f05429
commit 1ded384
Showing
5 changed files
with
367 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package datadogagent | ||
|
||
import ( | ||
"testing" | ||
|
||
datadoghqv1alpha1 "github.com/DataDog/datadog-operator/api/v1alpha1" | ||
test "github.com/DataDog/datadog-operator/api/v1alpha1/test" | ||
assert "github.com/stretchr/testify/require" | ||
logf "sigs.k8s.io/controller-runtime/pkg/log" | ||
"sigs.k8s.io/controller-runtime/pkg/log/zap" | ||
|
||
testutils "github.com/DataDog/datadog-operator/controllers/datadogagent/testutils" | ||
|
||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
) | ||
|
||
type extendeddaemonsetFromInstanceTest struct { | ||
name string | ||
agentdeployment *datadoghqv1alpha1.DatadogAgent | ||
selector *metav1.LabelSelector | ||
checkEDSFuncs []testutils.CheckExtendedDaemonSetFunc | ||
wantErr bool | ||
} | ||
|
||
func (test extendeddaemonsetFromInstanceTest) Run(t *testing.T) { | ||
t.Helper() | ||
logf.SetLogger(zap.New(zap.UseDevMode(true))) | ||
logger := logf.Log.WithName(t.Name()) | ||
got, _, err := newExtendedDaemonSetFromInstance(logger, test.agentdeployment, test.selector) | ||
if test.wantErr { | ||
assert.Error(t, err, "newExtendedDaemonSetFromInstance() expected an error") | ||
} else { | ||
assert.NoError(t, err, "newExtendedDaemonSetFromInstance() unexpected error: %v", err) | ||
} | ||
|
||
// Remove the generated hash before comparison because it is not easy generate it in the test definition. | ||
delete(got.Annotations, datadoghqv1alpha1.MD5AgentDeploymentAnnotationKey) | ||
|
||
for _, checkFunc := range test.checkEDSFuncs { | ||
checkFunc(t, got) | ||
} | ||
} | ||
|
||
func Test_EDSFromDefaultAgent(t *testing.T) { | ||
defaultDatadogAgent := test.NewDefaultedDatadogAgent("bar", "foo", &test.NewDatadogAgentOptions{UseEDS: true, ClusterAgentEnabled: true}) | ||
|
||
test1 := extendeddaemonsetFromInstanceTest{ | ||
name: "defaulted case", | ||
agentdeployment: defaultDatadogAgent, | ||
checkEDSFuncs: []testutils.CheckExtendedDaemonSetFunc{ | ||
testutils.CheckMetadaInEDS(&testutils.CheckNameNamespace{Namespace: "bar", Name: "foo-agent"}), | ||
// check labels | ||
testutils.CheckMetadaInEDS(&testutils.CheckLabelIsPresent{Key: "agent.datadoghq.com/name", Value: "foo"}), | ||
testutils.CheckMetadaInEDS(&testutils.CheckLabelIsPresent{Key: "agent.datadoghq.com/component", Value: "agent"}), | ||
testutils.CheckMetadaInEDS(&testutils.CheckLabelIsPresent{Key: "app.kubernetes.io/instance", Value: "agent"}), | ||
testutils.CheckMetadaInEDS(&testutils.CheckLabelIsPresent{Key: "app.kubernetes.io/managed-by", Value: "datadog-operator"}), | ||
// check containers creation | ||
testutils.CheckPodTemplateInEDS(&testutils.CheckContainerNameIsPresentFunc{Name: "agent"}), | ||
testutils.CheckPodTemplateInEDS(&testutils.CheckContainerNameIsPresentFunc{Name: "process-agent"}), | ||
}, | ||
wantErr: false, | ||
} | ||
test1.Run(t) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
// Unless explicitly stated otherwise all files in this repository are licensed | ||
// under the Apache License Version 2.0. | ||
// This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
// Copyright 2016-present Datadog, Inc. | ||
|
||
// Package testutils_test contains a set of unit-test helper functions | ||
// to ease the creation of unit-test around the DatadogAgent CRD controller | ||
package testutils_test |
35 changes: 35 additions & 0 deletions
35
controllers/datadogagent/testutils/extendeddaemonset_utils.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// Unless explicitly stated otherwise all files in this repository are licensed | ||
// under the Apache License Version 2.0. | ||
// This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
// Copyright 2016-present Datadog, Inc. | ||
|
||
package testutils_test | ||
|
||
import ( | ||
"testing" | ||
|
||
edsdatadoghqv1alpha1 "github.com/DataDog/extendeddaemonset/api/v1alpha1" | ||
) | ||
|
||
// CheckExtendedDaemonSetFunc define the signature of ExtendedDaemonSet's Check function. | ||
type CheckExtendedDaemonSetFunc func(t *testing.T, eds *edsdatadoghqv1alpha1.ExtendedDaemonSet) | ||
|
||
// CheckPodTemplateInEDS used to execute a CheckPodTemplateFunc function on an ExtendedDaemonSet instance | ||
func CheckPodTemplateInEDS(templateCheck PodTemplateSpecCheckInterface) CheckExtendedDaemonSetFunc { | ||
check := func(t *testing.T, eds *edsdatadoghqv1alpha1.ExtendedDaemonSet) { | ||
if err := templateCheck.Check(t, &eds.Spec.Template); err != nil { | ||
t.Error(err) | ||
} | ||
} | ||
return check | ||
} | ||
|
||
// CheckMetadaInEDS used to execute a CheckExtendedDaemonSetFunc function on an ExtendedDaemonSet instance | ||
func CheckMetadaInEDS(metaCheck ObjetMetaCheckInterface) CheckExtendedDaemonSetFunc { | ||
check := func(t *testing.T, eds *edsdatadoghqv1alpha1.ExtendedDaemonSet) { | ||
if err := metaCheck.Check(t, &eds.ObjectMeta); err != nil { | ||
t.Error(err) | ||
} | ||
} | ||
return check | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
// Unless explicitly stated otherwise all files in this repository are licensed | ||
// under the Apache License Version 2.0. | ||
// This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
// Copyright 2016-present Datadog, Inc. | ||
|
||
package testutils_test | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
) | ||
|
||
// CheckObjectMeta define the function signature of a check that runs again a metav1.ObjectMeta object. | ||
type CheckObjectMeta func(t *testing.T, obj *metav1.ObjectMeta) | ||
|
||
// ObjetMetaCheckInterface use as ObjectMeta check interface | ||
type ObjetMetaCheckInterface interface { | ||
Check(t *testing.T, obj *metav1.ObjectMeta) error | ||
} | ||
|
||
// CheckNameNamespace used to check if the namespace and name are the expected value on a metav1.ObjectMeta. | ||
type CheckNameNamespace struct { | ||
Namespace string | ||
Name string | ||
} | ||
|
||
// Check used to check if the namespace and name are the expected value on a metav1.ObjectMeta. | ||
func (c *CheckNameNamespace) Check(t *testing.T, obj *metav1.ObjectMeta) error { | ||
if obj.Namespace != c.Namespace || obj.Name != c.Name { | ||
return fmt.Errorf("wrong object NS/Name, want [%s/%s], got [%s/%s]", c.Namespace, c.Name, obj.Namespace, obj.Name) | ||
} | ||
return nil | ||
} | ||
|
||
// CheckLabelIsPresent used to check if a label (key,value) is present on a metav1.ObjectMeta object. | ||
type CheckLabelIsPresent struct { | ||
Key string | ||
Value string | ||
} | ||
|
||
// Check used to check if a label (key,value) is present on a metav1.ObjectMeta object. | ||
func (c *CheckLabelIsPresent) Check(t *testing.T, obj *metav1.ObjectMeta) error { | ||
return checkIsPresentInMap(t, c.Key, c.Value, obj.Labels, "obj.Labels") | ||
} | ||
|
||
// CheckAnnotationIsPresent used to check if an annotation (key,value) is present on a metav1.ObjectMeta object. | ||
type CheckAnnotationIsPresent struct { | ||
Key string | ||
Value string | ||
} | ||
|
||
// Check used to check if an annotation (key,value) is present on a metav1.ObjectMeta object. | ||
func (c *CheckAnnotationIsPresent) Check(t *testing.T, obj *metav1.ObjectMeta) error { | ||
return checkIsPresentInMap(t, c.Key, c.Value, obj.Annotations, "obj.Annotations") | ||
} | ||
|
||
// CheckLabelIsNotPresent used to check if a label key is not present on a metav1.ObjectMeta object. | ||
type CheckLabelIsNotPresent struct { | ||
Key string | ||
} | ||
|
||
// Check used to check if a label key is not present on a metav1.ObjectMeta object. | ||
func (c *CheckLabelIsNotPresent) Check(t *testing.T, obj *metav1.ObjectMeta) error { | ||
return checkLabelIsNotPresent(t, c.Key, obj.Labels, "obj.Labels") | ||
} | ||
|
||
// CheckAnnotationsIsNotPresent used to check if a annotation key is not present on a metav1.ObjectMeta object. | ||
type CheckAnnotationsIsNotPresent struct { | ||
Key string | ||
} | ||
|
||
// Check used to check if an annotation (key,value) is not present on a metav1.ObjectMeta object. | ||
func (c *CheckAnnotationsIsNotPresent) Check(t *testing.T, obj *metav1.ObjectMeta) error { | ||
return checkLabelIsNotPresent(t, c.Key, obj.Annotations, "obj.Annotations") | ||
} | ||
|
||
func checkIsPresentInMap(t *testing.T, key, value string, entries map[string]string, msgPrefix string) error { | ||
if val, found := entries[key]; found { | ||
if val == value { | ||
t.Logf("[%s] key [%s] founded with value value [%s]", msgPrefix, key, value) | ||
return nil | ||
} | ||
return fmt.Errorf("[%s] key %s founded, but wrong value, got [%s], want [%s]", msgPrefix, key, val, value) | ||
} | ||
return fmt.Errorf("[%s] key %s not founded", msgPrefix, key) | ||
} | ||
|
||
func checkLabelIsNotPresent(_ *testing.T, key string, entries map[string]string, msgPrefix string) error { | ||
if value, found := entries[key]; found { | ||
return fmt.Errorf("[%s] key [%s] founded with value value [%s]", msgPrefix, key, value) | ||
} | ||
return nil | ||
} |
165 changes: 165 additions & 0 deletions
165
controllers/datadogagent/testutils/podtemplate_utils.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
// Unless explicitly stated otherwise all files in this repository are licensed | ||
// under the Apache License Version 2.0. | ||
// This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
// Copyright 2016-present Datadog, Inc. | ||
|
||
package testutils_test | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
corev1 "k8s.io/api/core/v1" | ||
|
||
apiequality "k8s.io/apimachinery/pkg/api/equality" | ||
|
||
"github.com/DataDog/datadog-operator/pkg/testutils" | ||
) | ||
|
||
// ContainerCheckInterface interface used by container checks. | ||
type ContainerCheckInterface interface { | ||
Check(t *testing.T, container *corev1.Container) error | ||
} | ||
|
||
// PodTemplateSpecCheckInterface interface use by PodTemplateSpec checks. | ||
type PodTemplateSpecCheckInterface interface { | ||
Check(t *testing.T, podTemplate *corev1.PodTemplateSpec) error | ||
} | ||
|
||
// CheckPodTemplateFunc define the signature of a check function against a corev1.PodTemplateSpec | ||
type CheckPodTemplateFunc func(t *testing.T, podTemplate *corev1.PodTemplateSpec) | ||
|
||
// CheckContainerInPodTemplate used to execute a ContainerCheckInterface.Check(...) function again a specific container in a corev1.PodTemplateSpec | ||
// object. | ||
func CheckContainerInPodTemplate(containerName string, checkFunc ContainerCheckInterface) CheckPodTemplateFunc { | ||
check := func(t *testing.T, podTemplate *corev1.PodTemplateSpec) { | ||
for _, container := range podTemplate.Spec.Containers { | ||
if container.Name == containerName { | ||
if err := checkFunc.Check(t, &container); err != nil { | ||
t.Error(err) | ||
} | ||
} | ||
} | ||
t.Errorf("Container %s not founded", containerName) | ||
} | ||
return check | ||
} | ||
|
||
// CheckVolumeIsPresent used to check if a corev1.Volume is present in a corev1.PodTemplateSpec object. | ||
type CheckVolumeIsPresent struct { | ||
Volume *corev1.Volume | ||
} | ||
|
||
// Check used to check if a corev1.Volume is present in a corev1.PodTemplateSpec object. | ||
func (c *CheckVolumeIsPresent) Check(t *testing.T, podTemplate *corev1.PodTemplateSpec) error { | ||
for _, volumeIn := range podTemplate.Spec.Volumes { | ||
if apiequality.Semantic.DeepEqual(c.Volume, &volumeIn) { | ||
t.Logf("Volume %s founded", c.Volume.Name) | ||
return nil | ||
} | ||
} | ||
return fmt.Errorf("volume %s not founded", c.Volume.Name) | ||
} | ||
|
||
// CheckVolumeIsNotPresent used to check if a corev1.Volume is not present in a corev1.PodTemplateSpec object. | ||
type CheckVolumeIsNotPresent struct { | ||
Volume *corev1.Volume | ||
} | ||
|
||
// Check used to check if a corev1.Volume is not present in a corev1.PodTemplateSpec object. | ||
func (c *CheckVolumeIsNotPresent) Check(t *testing.T, podTemplate *corev1.PodTemplateSpec) error { | ||
found := false | ||
for _, volumeIn := range podTemplate.Spec.Volumes { | ||
if diff := testutils.CompareKubeResource(c.Volume, &volumeIn); diff == "" { | ||
found = true | ||
break | ||
} | ||
} | ||
if found { | ||
t.Logf("Volume %s founded", c.Volume.Name) | ||
return nil | ||
} | ||
return fmt.Errorf("volume %s not founded", c.Volume.Name) | ||
} | ||
|
||
// CheckContainerDeepEqualIsPresent used to check if corev1.Container is equal to a container inside a corev1.PodTemplateSpec object. | ||
type CheckContainerDeepEqualIsPresent struct { | ||
Container *corev1.Container | ||
} | ||
|
||
// Check used to check if corev1.Container is equal to a container inside a corev1.PodTemplateSpec object. | ||
func (c *CheckContainerDeepEqualIsPresent) Check(t *testing.T, podTemplate *corev1.PodTemplateSpec) error { | ||
for _, containerIn := range podTemplate.Spec.Containers { | ||
if diff := testutils.CompareKubeResource(c.Container, &containerIn); diff != "" { | ||
t.Logf("container %s founded", c.Container.Name) | ||
return nil | ||
} | ||
} | ||
return fmt.Errorf("container %s not founded", c.Container.Name) | ||
} | ||
|
||
// CheckContainerNameIsPresentFunc used to check if container name is equal to a container name | ||
// present in a corev1.PodTemplateSpec object. | ||
type CheckContainerNameIsPresentFunc struct { | ||
Name string | ||
} | ||
|
||
// Check used to check if container name is equal to a container name | ||
// present in a corev1.PodTemplateSpec object. | ||
func (c *CheckContainerNameIsPresentFunc) Check(t *testing.T, podTemplate *corev1.PodTemplateSpec) error { | ||
for _, containerIn := range podTemplate.Spec.Containers { | ||
if containerIn.Name == c.Name { | ||
t.Logf("container %s founded", containerIn.Name) | ||
return nil | ||
} | ||
} | ||
return fmt.Errorf("container %s not founded", c.Name) | ||
} | ||
|
||
// CheckEnvVarIsPresent used to check if an corev1.EnvVar is present in a corev1.Container object | ||
type CheckEnvVarIsPresent struct { | ||
EnvVar *corev1.EnvVar | ||
} | ||
|
||
// Check used to check if an corev1.EnvVar is present in a corev1.Container object | ||
func (c *CheckEnvVarIsPresent) Check(t *testing.T, container *corev1.Container) error { | ||
for _, envVarIn := range container.Env { | ||
if diff := testutils.CompareKubeResource(&envVarIn, c.EnvVar); diff == "" { | ||
t.Logf("EnvVar %s founded in container %s", c.EnvVar.Name, container.Name) | ||
return nil | ||
} | ||
} | ||
return fmt.Errorf("EnvVar %s not founded in container %s", c.EnvVar.Name, container.Name) | ||
} | ||
|
||
// CheckEnvFromIsPresent used to check if an corev1.EnvFromSource is present in a corev1.Container object | ||
type CheckEnvFromIsPresent struct { | ||
EnvFrom *corev1.EnvFromSource | ||
} | ||
|
||
// Check used to check if an corev1.EnvFromSource is present in a corev1.Container object | ||
func (c *CheckEnvFromIsPresent) Check(t *testing.T, container *corev1.Container) error { | ||
for _, envVarIn := range container.EnvFrom { | ||
if diff := testutils.CompareKubeResource(&envVarIn, c.EnvFrom); diff == "" { | ||
t.Logf("EnvVar [%s] founded in container %s", c.EnvFrom.String(), container.Name) | ||
return nil | ||
} | ||
} | ||
return fmt.Errorf("envVar [%s] not founded in container %s", c.EnvFrom.String(), container.Name) | ||
} | ||
|
||
// CheckVolumeMountIsPresent used to check if an corev1.VolumeMount is present in a corev1.Container object | ||
type CheckVolumeMountIsPresent struct { | ||
VolumeMount *corev1.VolumeMount | ||
} | ||
|
||
// Check used to check if an corev1.VolumeMount is present in a corev1.Container object | ||
func (c *CheckVolumeMountIsPresent) Check(t *testing.T, container *corev1.Container) error { | ||
for _, volumeMountIn := range container.VolumeMounts { | ||
if diff := testutils.CompareKubeResource(&volumeMountIn, c.VolumeMount); diff == "" { | ||
t.Logf("VolumeMount [%s] founded in container %s", c.VolumeMount.String(), container.Name) | ||
return nil | ||
} | ||
} | ||
return fmt.Errorf("volumeMount [%s] not founded in container %s", c.VolumeMount.String(), container.Name) | ||
} |