Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion .github/codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,14 @@ comment:

ignore:
- "test/**/*" # ignore folders and all its contents
- "**/zz_generated.*.go" # api generated files
- "**/testutils/**/*" # test helper packages
- "**/fake/**/*" # test fake implementations
- "internal/controller/datadogagent/feature/test/**/*" # feature test harness
- "hack/**/*" # developer tooling
- "marketplaces/**/*" # marketplace packaging/release tooling
- "examples/**/*" # sample manifests
- "docs/**/*" # documentation and generated docs
- "config/**/*" # generated/deployment manifests
- "bundle/**/*" # generated OLM bundle manifests
- "api/datadoghq/**/*_types.go" # CRD schema type declarations
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Narrow the API types ignore

When hand-written helpers live in API type files, this new ignore removes real product logic from the coverage gates, not just schema declarations. For example, api/datadoghq/v1alpha1/datadogslo_types.go contains the executable DatadogSLOType.IsValid() helper, and the same broad api/datadoghq/**/*_types.go pattern was also added to the Datadog coverage config, so changes in these helpers can be reported as fully covered/ignored by both systems. Consider excluding only generated schema files or moving such helpers out of ignored files.

Useful? React with 👍 / 👎.

- "**/zz_generated.*.go" # api generated files
168 changes: 168 additions & 0 deletions cmd/yaml-mapper/utils/maps_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
// 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 2025-present Datadog, Inc.

package utils

import (
"testing"

"github.com/stretchr/testify/require"
"helm.sh/helm/v3/pkg/chartutil"
)

func TestInsertAtPath(t *testing.T) {
values := map[string]any{
"datadog": map[string]any{
"apiKey": "existing",
},
}

InsertAtPath("datadog.logs.enabled", true, values)

require.Equal(t, "existing", values["datadog"].(map[string]any)["apiKey"])
require.Equal(t, true, values["datadog"].(map[string]any)["logs"].(map[string]any)["enabled"])
}

func TestMergeMapDeep(t *testing.T) {
t.Run("deep merges nested maps", func(t *testing.T) {
left := map[string]any{
"datadog": map[string]any{
"apiKey": "existing",
},
}
right := map[string]any{
"datadog": map[string]any{
"logs": map[string]any{"enabled": true},
},
}

got := MergeMapDeep(left, right)

require.Equal(t, "existing", got["datadog"].(map[string]any)["apiKey"])
require.Equal(t, true, got["datadog"].(map[string]any)["logs"].(map[string]any)["enabled"])
})

t.Run("overwrites scalars and ignores nil values", func(t *testing.T) {
got := MergeMapDeep(
map[string]any{"logs": false, "apm": true},
map[string]any{"logs": true, "apm": nil},
)

require.Equal(t, true, got["logs"])
require.Equal(t, true, got["apm"])
})
}

func TestMergeOrSet(t *testing.T) {
t.Run("merges map values", func(t *testing.T) {
values := map[string]any{
"datadog": map[string]any{"apiKey": "existing"},
}

MergeOrSet(values, "datadog", chartutil.Values{"logs": map[string]any{"enabled": true}})

require.Equal(t, "existing", values["datadog"].(map[string]any)["apiKey"])
require.Equal(t, true, values["datadog"].(map[string]any)["logs"].(map[string]any)["enabled"])
})

t.Run("does not write nil values", func(t *testing.T) {
values := map[string]any{}

MergeOrSet(values, "datadog", nil)

require.Empty(t, values)
})
}

func TestGetPathHelpers(t *testing.T) {
values := chartutil.Values{
"datadog": map[string]any{
"apiKey": "abc",
"logs": map[string]any{
"enabled": true,
"items": []any{"first"},
},
},
}

stringValue, ok := GetPathString(values, "datadog", "apiKey")
require.True(t, ok)
require.Equal(t, "abc", stringValue)

boolValue, ok := GetPathBool(values, "datadog", "logs", "enabled")
require.True(t, ok)
require.True(t, boolValue)

sliceValue, ok := GetPathSlice(values, "datadog", "logs", "items")
require.True(t, ok)
require.Equal(t, []any{"first"}, sliceValue)

mapValue, ok := GetPathMap(values, "datadog", "logs")
require.True(t, ok)
require.Equal(t, true, mapValue["enabled"])

_, ok = GetPathString(values, "datadog", "logs", "enabled")
require.False(t, ok)

_, ok = GetPathVal(values, "datadog", "missing")
require.False(t, ok)
}

func TestApplyDeprecationRules(t *testing.T) {
t.Run("moves deprecated boolean aliases to their standard key", func(t *testing.T) {
values := chartutil.Values{
"datadog": map[string]any{
"apm": map[string]any{
"enabled": false,
},
},
}

got := ApplyDeprecationRules(values)

portEnabled, ok := GetPathBool(got, "datadog", "apm", "portEnabled")
require.True(t, ok)
require.False(t, portEnabled)

_, ok = GetPathBool(got, "datadog", "apm", "enabled")
require.False(t, ok)
})

t.Run("standard key participates in boolean OR mapping", func(t *testing.T) {
values := chartutil.Values{
"datadog": map[string]any{
"apm": map[string]any{
"enabled": false,
"portEnabled": true,
},
},
}

got := ApplyDeprecationRules(values)

portEnabled, ok := GetPathBool(got, "datadog", "apm", "portEnabled")
require.True(t, ok)
require.True(t, portEnabled)
})

t.Run("negates deprecated inverse keys unless the standard key is present", func(t *testing.T) {
values := chartutil.Values{
"datadog": map[string]any{
"systemProbe": map[string]any{
"enableDefaultOsReleasePaths": false,
},
},
}

got := ApplyDeprecationRules(values)

disableDefaultPaths, ok := GetPathBool(got, "datadog", "disableDefaultOsReleasePaths")
require.True(t, ok)
require.True(t, disableDefaultPaths)

_, ok = GetPathBool(got, "datadog", "systemProbe", "enableDefaultOsReleasePaths")
require.False(t, ok)
})
}
10 changes: 10 additions & 0 deletions code-coverage.datadog.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
schema-version: v1
ignore:
- "test/"
- "**/testutils/"
- "**/fake/"
- "internal/controller/datadogagent/feature/test/"
- "hack/"
- "marketplaces/"
- "examples/"
- "docs/"
- "config/"
- "bundle/"
- "api/datadoghq/**/*_types.go"
- "**/zz_generated.*.go"
gates:
- type: patch_coverage_percentage
Expand Down
151 changes: 151 additions & 0 deletions internal/controller/datadogagent/common/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,154 @@
// Copyright 2025-present Datadog, Inc.

package common

import (
"testing"

"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/version"

apicommon "github.com/DataDog/datadog-operator/api/datadoghq/common"
"github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1"
"github.com/DataDog/datadog-operator/pkg/constants"
"github.com/DataDog/datadog-operator/pkg/kubernetes"
)

func TestNewDeploymentUsesDefaultMetadata(t *testing.T) {
dda := testDatadogAgent()

deployment := NewDeployment(dda, constants.DefaultClusterAgentResourceSuffix, "datadog-cluster-agent", "7.77.0", nil)

require.Equal(t, "datadog-cluster-agent", deployment.Name)
require.Equal(t, "agents", deployment.Namespace)
require.Equal(t, "datadog-cluster-agent", deployment.Labels[kubernetes.AppKubernetesInstanceLabelKey])
require.Equal(t, constants.DefaultClusterAgentResourceSuffix, deployment.Labels[apicommon.AgentDeploymentComponentLabelKey])
require.Equal(t, map[string]string{
kubernetes.AppKubernetesInstanceLabelKey: "datadog-cluster-agent",
apicommon.AgentDeploymentComponentLabelKey: constants.DefaultClusterAgentResourceSuffix,
}, deployment.Spec.Selector.MatchLabels)
}

func TestGetDefaultMetadata(t *testing.T) {
t.Run("copies explicit selector labels into object labels", func(t *testing.T) {
selector := &metav1.LabelSelector{MatchLabels: map[string]string{"custom": "selector"}}

labels, _, gotSelector := GetDefaultMetadata(testDatadogAgent(), constants.DefaultAgentResourceSuffix, "datadog-agent", "7.77.0", selector)

require.Equal(t, selector, gotSelector)
require.Equal(t, "selector", labels["custom"])
})

t.Run("uses legacy selector labels when metadata update is disabled", func(t *testing.T) {
dda := testDatadogAgent()
dda.Annotations = map[string]string{apicommon.UpdateMetadataAnnotationKey: "false"}

_, _, selector := GetDefaultMetadata(dda, constants.DefaultAgentResourceSuffix, "datadog-agent", "7.77.0", nil)

require.Equal(t, map[string]string{
apicommon.AgentDeploymentNameLabelKey: "datadog",
apicommon.AgentDeploymentComponentLabelKey: constants.DefaultAgentResourceSuffix,
}, selector.MatchLabels)
})
}

func TestComponentVersionHelpers(t *testing.T) {
t.Run("uses the component image tag override", func(t *testing.T) {
dda := testDatadogAgent()
dda.Spec.Override = map[v2alpha1.ComponentName]*v2alpha1.DatadogAgentComponentOverride{
v2alpha1.NodeAgentComponentName: {
Image: &v2alpha1.AgentImageConfig{Tag: "7.76.0"},
},
}

require.Equal(t, "7.76.0", GetComponentVersion(dda, v2alpha1.NodeAgentComponentName))
})

t.Run("extracts a version from image name and removes jmx suffix", func(t *testing.T) {
require.Equal(t, "7.75.1", GetAgentVersionFromImage(v2alpha1.AgentImageConfig{
Name: "gcr.io/datadoghq/agent:7.75.1-jmx",
}))
})

t.Run("image tag takes precedence over image name", func(t *testing.T) {
require.Equal(t, "7.77.0", GetAgentVersionFromImage(v2alpha1.AgentImageConfig{
Name: "gcr.io/datadoghq/agent:7.75.1",
Tag: "7.77.0",
}))
})
}

func TestEnvVarBuilders(t *testing.T) {
source := BuildEnvVarFromSecret("datadog-secret", "api-key")
envVar := BuildEnvVarFromSource("DD_API_KEY", source)

require.Equal(t, "DD_API_KEY", envVar.Name)
require.Equal(t, "datadog-secret", envVar.ValueFrom.SecretKeyRef.Name)
require.Equal(t, "api-key", envVar.ValueFrom.SecretKeyRef.Key)
}

func TestServiceSelectors(t *testing.T) {
dda := testDatadogAgent()

require.Equal(t, map[string]string{
kubernetes.AppKubernetesPartOfLabelKey: "agents-datadog",
apicommon.AgentDeploymentComponentLabelKey: constants.DefaultAgentResourceSuffix,
}, GetAgentLocalServiceSelector(dda))

require.Equal(t, map[string]string{
kubernetes.AppKubernetesPartOfLabelKey: "agents-datadog",
apicommon.AgentDeploymentComponentLabelKey: constants.DefaultOtelAgentGatewayResourceSuffix,
}, GetOtelAgentGatewayServiceSelector(dda))
}

func TestShouldCreateAgentLocalService(t *testing.T) {
require.False(t, ShouldCreateAgentLocalService(nil, true))
require.False(t, ShouldCreateAgentLocalService(&version.Info{}, true))
require.False(t, ShouldCreateAgentLocalService(&version.Info{GitVersion: "v1.21.0"}, false))
require.True(t, ShouldCreateAgentLocalService(&version.Info{GitVersion: "v1.21.0"}, true))
require.True(t, ShouldCreateAgentLocalService(&version.Info{GitVersion: "v1.22.0"}, false))
}

func TestMergeAffinities(t *testing.T) {
first := &corev1.Affinity{
NodeAffinity: &corev1.NodeAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{
NodeSelectorTerms: []corev1.NodeSelectorTerm{
{MatchExpressions: []corev1.NodeSelectorRequirement{{Key: "disk", Operator: corev1.NodeSelectorOpIn, Values: []string{"ssd"}}}},
},
},
},
PodAffinity: &corev1.PodAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: []corev1.PodAffinityTerm{{TopologyKey: "zone-a"}},
},
}
second := &corev1.Affinity{
NodeAffinity: &corev1.NodeAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{
NodeSelectorTerms: []corev1.NodeSelectorTerm{
{MatchExpressions: []corev1.NodeSelectorRequirement{{Key: "arch", Operator: corev1.NodeSelectorOpIn, Values: []string{"arm64"}}}},
},
},
},
PodAffinity: &corev1.PodAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: []corev1.PodAffinityTerm{{TopologyKey: "zone-b"}},
},
}

merged := MergeAffinities(first, second)

require.Len(t, merged.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms, 1)
require.Len(t, merged.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms[0].MatchExpressions, 2)
require.Equal(t, []corev1.PodAffinityTerm{{TopologyKey: "zone-a"}, {TopologyKey: "zone-b"}}, merged.PodAffinity.RequiredDuringSchedulingIgnoredDuringExecution)
}

func testDatadogAgent() *v2alpha1.DatadogAgent {
return &v2alpha1.DatadogAgent{
ObjectMeta: metav1.ObjectMeta{
Name: "datadog",
Namespace: "agents",
},
}
}
Loading
Loading