Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more unit-tests to basemanifest renderer #6225

Merged
merged 4 commits into from
Sep 11, 2023
Merged
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
40 changes: 31 additions & 9 deletions pkg/corerp/renderers/container/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,15 +161,6 @@ func getServiceAccountBase(manifest kubeutil.ObjectManifest, appName string, r *
return defaultAccount
}

func getObjectMeta(metaObj metav1.ObjectMeta, appName, resourceName, resourceType string, options renderers.RenderOptions) metav1.ObjectMeta {
return metav1.ObjectMeta{
Name: kubernetes.NormalizeResourceName(resourceName),
Namespace: options.Environment.Namespace,
Labels: labels.Merge(metaObj.Labels, renderers.GetLabels(options, appName, resourceName, resourceType)),
Annotations: labels.Merge(metaObj.Annotations, renderers.GetAnnotations(options)),
}
}

// populateAllBaseResources populates all remaining resources from manifest into outputResources.
// These resources must be deployed before Deployment resource by adding them as a dependency.
func populateAllBaseResources(ctx context.Context, base kubeutil.ObjectManifest, outputResources []rpv1.OutputResource, options renderers.RenderOptions) []rpv1.OutputResource {
Expand Down Expand Up @@ -238,3 +229,34 @@ func patchPodSpec(sourceSpec *corev1.PodSpec, patchSpec []byte) (*corev1.PodSpec

return patched, nil
}

func mergeLabelSelector(base *metav1.LabelSelector, cur *metav1.LabelSelector) *metav1.LabelSelector {
if base == nil {
base = &metav1.LabelSelector{}
}

return &metav1.LabelSelector{
MatchLabels: labels.Merge(base.MatchLabels, cur.MatchLabels),
MatchExpressions: append(base.MatchExpressions, cur.MatchExpressions...),
}
}

func mergeObjectMeta(base metav1.ObjectMeta, cur metav1.ObjectMeta) metav1.ObjectMeta {
return metav1.ObjectMeta{
Name: cur.Name,
Namespace: cur.Namespace,
Labels: labels.Merge(base.Labels, cur.Labels),
Annotations: labels.Merge(base.Annotations, cur.Annotations),
}
}

func getObjectMeta(base metav1.ObjectMeta, appName, resourceName, resourceType string, options renderers.RenderOptions) metav1.ObjectMeta {
cur := metav1.ObjectMeta{
Name: kubernetes.NormalizeResourceName(resourceName),
Namespace: options.Environment.Namespace,
Labels: renderers.GetLabels(options, appName, resourceName, resourceType),
Annotations: renderers.GetAnnotations(options),
}

return mergeObjectMeta(base, cur)
}
154 changes: 154 additions & 0 deletions pkg/corerp/renderers/container/manifest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,160 @@ var (
testOptions = &renderers.RenderOptions{Environment: renderers.EnvironmentOptions{Namespace: "test-ns"}}
)

func TestMergeLabelSelector(t *testing.T) {
labelMergeTests := []struct {
name string
base *metav1.LabelSelector
cur *metav1.LabelSelector
expected *metav1.LabelSelector
}{
{
name: "base is nil",
base: nil,
cur: &metav1.LabelSelector{
MatchLabels: map[string]string{
"key1": "value1",
},
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "key2",
Operator: metav1.LabelSelectorOpIn,
Values: []string{"value2"},
},
},
},
expected: &metav1.LabelSelector{
MatchLabels: map[string]string{
"key1": "value1",
},
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "key2",
Operator: metav1.LabelSelectorOpIn,
Values: []string{"value2"},
},
},
},
},
{
name: "base includes matchLabels",
base: &metav1.LabelSelector{
MatchLabels: map[string]string{
"key1": "value1",
},
},
cur: &metav1.LabelSelector{
MatchLabels: map[string]string{
"key2": "value2",
},
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "key2",
Operator: metav1.LabelSelectorOpIn,
Values: []string{"value2"},
},
},
},
expected: &metav1.LabelSelector{
MatchLabels: map[string]string{
"key1": "value1",
"key2": "value2",
},
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "key2",
Operator: metav1.LabelSelectorOpIn,
Values: []string{"value2"},
},
},
},
},
}

for _, tc := range labelMergeTests {
t.Run(tc.name, func(t *testing.T) {
actual := mergeLabelSelector(tc.base, tc.cur)
require.Equal(t, tc.expected, actual)
})
}
}

func TestMergeObjectMeta(t *testing.T) {
mergeObjectMetaTests := []struct {
name string
base metav1.ObjectMeta
cur metav1.ObjectMeta
expected metav1.ObjectMeta
}{
{
name: "base is empty",
base: metav1.ObjectMeta{},
cur: metav1.ObjectMeta{
Name: "name",
Namespace: "namespace",
Labels: map[string]string{
"key1": "value1",
},
Annotations: map[string]string{
"key2": "value2",
},
},
expected: metav1.ObjectMeta{
Name: "name",
Namespace: "namespace",
Labels: map[string]string{
"key1": "value1",
},
Annotations: map[string]string{
"key2": "value2",
},
},
},
{
name: "override name and namespace",
base: metav1.ObjectMeta{
Name: "base",
Namespace: "base namespace",
Labels: map[string]string{
"key1": "value1",
},
Annotations: map[string]string{
"key1": "value1",
},
},
cur: metav1.ObjectMeta{
Name: "name",
Namespace: "namespace",
Labels: map[string]string{
"key2": "value2",
},
Annotations: map[string]string{
"key2": "value2",
},
},
expected: metav1.ObjectMeta{
Name: "name",
Namespace: "namespace",
Labels: map[string]string{
"key1": "value1",
"key2": "value2",
},
Annotations: map[string]string{
"key1": "value1",
"key2": "value2",
},
},
},
}

for _, tc := range mergeObjectMetaTests {
t.Run(tc.name, func(t *testing.T) {
actual := mergeObjectMeta(tc.base, tc.cur)
require.Equal(t, tc.expected, actual)
})
}
}

func TestFetchBaseManifest(t *testing.T) {
manifestTests := []struct {
name string
Expand Down
11 changes: 5 additions & 6 deletions pkg/corerp/renderers/container/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -612,14 +612,13 @@ func (r Renderer) makeDeployment(
outputResources = append(outputResources, *roleBinding)
deps = append(deps, rpv1.LocalIDKubernetesRoleBinding)

deployment.Spec.Template.ObjectMeta = metav1.ObjectMeta{
Labels: podLabels,
Annotations: map[string]string{},
}
deployment.Spec.Template.ObjectMeta = mergeObjectMeta(deployment.Spec.Template.ObjectMeta, metav1.ObjectMeta{
Labels: podLabels,
})

deployment.Spec.Selector = &metav1.LabelSelector{
deployment.Spec.Selector = mergeLabelSelector(deployment.Spec.Selector, &metav1.LabelSelector{
MatchLabels: kubernetes.MakeSelectorLabels(applicationName, resource.Name),
}
})

podSpec.Volumes = append(podSpec.Volumes, volumes...)

Expand Down
85 changes: 85 additions & 0 deletions pkg/corerp/renderers/container/render_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package container

import (
"encoding/json"
"fmt"
"testing"

Expand All @@ -34,6 +35,7 @@ import (
resources_azure "github.com/radius-project/radius/pkg/ucp/resources/azure"
resources_kubernetes "github.com/radius-project/radius/pkg/ucp/resources/kubernetes"
"github.com/radius-project/radius/test/testcontext"
"github.com/radius-project/radius/test/testutil"

"github.com/google/uuid"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -1700,6 +1702,89 @@ func Test_Render_StrategicPatchMerge(t *testing.T) {
require.ElementsMatch(t, expectedContainers, deployment.Spec.Template.Spec.Containers)
}

func Test_Render_BaseManifest(t *testing.T) {
manifestTests := []struct {
name string
inFile string
container datamodel.ContainerProperties
outFile string
}{
{
name: "merge container, envvars, and volumes",
inFile: "basemanifest-input-merge.yaml",
container: datamodel.ContainerProperties{
BasicResourceProperties: rpv1.BasicResourceProperties{
Application: applicationResourceID,
},
Container: datamodel.Container{
Image: "someimage:latest",
Env: map[string]string{
envVarName1: envVarValue1,
envVarName2: envVarValue2,
},
Volumes: map[string]datamodel.VolumeProperties{
"ephemeralVolume": {
Kind: datamodel.Ephemeral,
Ephemeral: &datamodel.EphemeralVolume{
VolumeBase: datamodel.VolumeBase{
MountPath: "/mnt/ephemeral",
},
ManagedStore: datamodel.ManagedStoreMemory,
},
},
},
},
},
outFile: "basemanifest-output-merge.json",
},
{
name: "inject new sidecar",
inFile: "basemanifest-input-addcontainer.yaml",
container: datamodel.ContainerProperties{
BasicResourceProperties: rpv1.BasicResourceProperties{
Application: applicationResourceID,
},
Container: datamodel.Container{
Image: "someimage:latest",
Env: map[string]string{
envVarName1: envVarValue1,
envVarName2: envVarValue2,
},
},
},
outFile: "basemanifest-output-addcontainer.json",
},
}

for _, tc := range manifestTests {
t.Run(tc.name, func(t *testing.T) {
inYAML := testutil.ReadFixture(tc.inFile)
tc.container.Runtimes = &datamodel.RuntimeProperties{
Kubernetes: &datamodel.KubernetesRuntime{
Base: string(inYAML),
},
}

resource := makeResource(t, tc.container)
dependencies := map[string]renderers.RendererDependency{}

ctx := testcontext.New(t)
renderer := Renderer{}
output, err := renderer.Render(ctx, resource, renderers.RenderOptions{Dependencies: dependencies})
require.NoError(t, err)

deployment, _ := kubernetes.FindDeployment(output.Resources)
require.NotNil(t, deployment)

actual, err := json.MarshalIndent(deployment, "", " ")
require.NoError(t, err)

outputYaml := testutil.ReadFixture(tc.outFile)
require.Equal(t, string(outputYaml), string(actual), "actual output: %s", string(actual))
})
}
}

func renderOptionsEnvAndAppKubeMetadata() renderers.RenderOptions {
dependencies := map[string]renderers.RendererDependency{}
option := renderers.RenderOptions{Dependencies: dependencies}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-container
labels:
app: test-container
annotations:
source: base-manifest-test
spec:
replicas: 3
selector:
matchLabels:
app: test-container
basemanifest: default
template:
spec:
containers:
- name: sidecar
image: "sidecar:latest"
ports:
- containerPort: 80
protocol: TCP
env:
- name: KEY
value: VALUE
Loading
Loading