Files
deploy/util/kube/kube_test.go
zeekayandHanzo Dev 1ab6e799c1 cd: the module is github.com/hanzoai/cd, where it is actually hosted
go.mod still declared `module github.com/hanzoai/deploy` after the repo was
renamed. A Go module path is not cosmetic — it is the resolvable location. So
`go get github.com/hanzoai/cd` could not work, and anything importing this
module had to spell a name that no longer exists at that address. The build log
of v3.6.0 is where it surfaced: the compiler was still emitting
github.com/hanzoai/deploy/cmd/cd/commands.

3541 import paths across 690 .go, 19 .proto, 4 .yaml, 3 .sh, 2 .mod, Procfile
and Makefile. Plus the 62 ghcr.io/hanzoai/deploy image references, moved to
ghcr.io/hanzoai/cd to match hanzo.yml's build target — a distinct string from
the module path, replaced separately so neither could clobber the other.

go mod tidy clean, CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build ./... clean.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-28 21:16:24 -07:00

284 lines
8.9 KiB
Go

package kube
import (
"encoding/json"
"log"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
extv1beta1 "k8s.io/api/extensions/v1beta1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/yaml"
"github.com/hanzoai/cd/common"
)
const depWithoutSelector = `
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-deployment
spec:
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx:1.7.9
name: nginx
ports:
- containerPort: 80
`
const depWithSelector = `
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx:1.7.9
name: nginx
ports:
- containerPort: 80
`
func TestSetLabels(t *testing.T) {
t.Parallel()
for _, yamlStr := range []string{depWithoutSelector, depWithSelector} {
var obj unstructured.Unstructured
err := yaml.Unmarshal([]byte(yamlStr), &obj)
require.NoError(t, err)
err = SetAppInstanceLabel(&obj, common.LabelKeyAppInstance, "my-app")
require.NoError(t, err)
manifestBytes, err := json.MarshalIndent(obj.Object, "", " ")
require.NoError(t, err)
log.Println(string(manifestBytes))
var depV1Beta1 extv1beta1.Deployment
err = json.Unmarshal(manifestBytes, &depV1Beta1)
require.NoError(t, err)
// the following makes sure we are not falling into legacy code which injects labels
switch yamlStr {
case depWithoutSelector:
assert.Nil(t, depV1Beta1.Spec.Selector)
case depWithSelector:
assert.Len(t, depV1Beta1.Spec.Selector.MatchLabels, 1)
assert.Equal(t, "nginx", depV1Beta1.Spec.Selector.MatchLabels["app"])
}
assert.Len(t, depV1Beta1.Spec.Template.Labels, 1)
assert.Equal(t, "nginx", depV1Beta1.Spec.Template.Labels["app"])
}
}
func TestSetLegacyLabels(t *testing.T) {
t.Parallel()
for _, yamlStr := range []string{depWithoutSelector, depWithSelector} {
var obj unstructured.Unstructured
err := yaml.Unmarshal([]byte(yamlStr), &obj)
require.NoError(t, err)
err = SetAppInstanceLabel(&obj, common.LabelKeyLegacyApplicationName, "my-app")
require.NoError(t, err)
manifestBytes, err := json.MarshalIndent(obj.Object, "", " ")
require.NoError(t, err)
log.Println(string(manifestBytes))
var depV1Beta1 extv1beta1.Deployment
err = json.Unmarshal(manifestBytes, &depV1Beta1)
require.NoError(t, err)
assert.Len(t, depV1Beta1.Spec.Selector.MatchLabels, 1)
assert.Equal(t, "nginx", depV1Beta1.Spec.Selector.MatchLabels["app"])
assert.Len(t, depV1Beta1.Spec.Template.Labels, 2)
assert.Equal(t, "nginx", depV1Beta1.Spec.Template.Labels["app"])
assert.Equal(t, "my-app", depV1Beta1.Spec.Template.Labels[common.LabelKeyLegacyApplicationName])
}
}
func TestSetLegacyJobLabel(t *testing.T) {
t.Parallel()
yamlBytes, err := os.ReadFile("testdata/job.yaml")
require.NoError(t, err)
var obj unstructured.Unstructured
err = yaml.Unmarshal(yamlBytes, &obj)
require.NoError(t, err)
err = SetAppInstanceLabel(&obj, common.LabelKeyLegacyApplicationName, "my-app")
require.NoError(t, err)
manifestBytes, err := json.MarshalIndent(obj.Object, "", " ")
require.NoError(t, err)
log.Println(string(manifestBytes))
job := unstructured.Unstructured{}
err = json.Unmarshal(manifestBytes, &job)
require.NoError(t, err)
labels := job.GetLabels()
assert.Equal(t, "my-app", labels[common.LabelKeyLegacyApplicationName])
templateLabels, ok, err := unstructured.NestedMap(job.UnstructuredContent(), "spec", "template", "metadata", "labels")
assert.True(t, ok)
require.NoError(t, err)
assert.Equal(t, "my-app", templateLabels[common.LabelKeyLegacyApplicationName])
}
func TestSetSvcLabel(t *testing.T) {
t.Parallel()
yamlBytes, err := os.ReadFile("testdata/svc.yaml")
require.NoError(t, err)
var obj unstructured.Unstructured
err = yaml.Unmarshal(yamlBytes, &obj)
require.NoError(t, err)
err = SetAppInstanceLabel(&obj, common.LabelKeyAppInstance, "my-app")
require.NoError(t, err)
manifestBytes, err := json.MarshalIndent(obj.Object, "", " ")
require.NoError(t, err)
log.Println(string(manifestBytes))
var s corev1.Service
err = json.Unmarshal(manifestBytes, &s)
require.NoError(t, err)
log.Println(s.Name)
log.Println(s.ObjectMeta)
assert.Equal(t, "my-app", s.Labels[common.LabelKeyAppInstance])
}
func TestIsValidResourceName(t *testing.T) {
t.Parallel()
assert.True(t, IsValidResourceName("guestbook-ui"))
assert.True(t, IsValidResourceName("guestbook-ui1"))
assert.False(t, IsValidResourceName("Guestbook-ui"))
assert.False(t, IsValidResourceName("-guestbook-ui"))
}
func TestSetAppInstanceAnnotation(t *testing.T) {
t.Parallel()
yamlBytes, err := os.ReadFile("testdata/svc.yaml")
require.NoError(t, err)
var obj unstructured.Unstructured
err = yaml.Unmarshal(yamlBytes, &obj)
require.NoError(t, err)
err = SetAppInstanceAnnotation(&obj, common.LabelKeyAppInstance, "my-app")
require.NoError(t, err)
manifestBytes, err := json.MarshalIndent(obj.Object, "", " ")
require.NoError(t, err)
log.Println(string(manifestBytes))
var s corev1.Service
err = json.Unmarshal(manifestBytes, &s)
require.NoError(t, err)
log.Println(s.Name)
log.Println(s.ObjectMeta)
assert.Equal(t, "my-app", s.Annotations[common.LabelKeyAppInstance])
}
func TestSetAppInstanceAnnotationWithInvalidData(t *testing.T) {
t.Parallel()
yamlBytes, err := os.ReadFile("testdata/svc-with-invalid-data.yaml")
require.NoError(t, err)
var obj unstructured.Unstructured
err = yaml.Unmarshal(yamlBytes, &obj)
require.NoError(t, err)
err = SetAppInstanceAnnotation(&obj, common.LabelKeyAppInstance, "my-app")
assert.EqualError(t, err, "failed to get annotations from target object /v1, Kind=Service /my-service: .metadata.annotations accessor error: contains non-string value in the map under key \"invalid-annotation\": <nil> is of the type <nil>, expected string")
}
func TestGetAppInstanceAnnotation(t *testing.T) {
t.Parallel()
yamlBytes, err := os.ReadFile("testdata/svc.yaml")
require.NoError(t, err)
var obj unstructured.Unstructured
err = yaml.Unmarshal(yamlBytes, &obj)
require.NoError(t, err)
err = SetAppInstanceAnnotation(&obj, common.LabelKeyAppInstance, "my-app")
require.NoError(t, err)
annotation, err := GetAppInstanceAnnotation(&obj, common.LabelKeyAppInstance)
require.NoError(t, err)
assert.Equal(t, "my-app", annotation)
}
func TestGetAppInstanceAnnotationWithInvalidData(t *testing.T) {
t.Parallel()
yamlBytes, err := os.ReadFile("testdata/svc-with-invalid-data.yaml")
require.NoError(t, err)
var obj unstructured.Unstructured
err = yaml.Unmarshal(yamlBytes, &obj)
require.NoError(t, err)
_, err = GetAppInstanceAnnotation(&obj, "valid-annotation")
assert.EqualError(t, err, "failed to get annotations from target object /v1, Kind=Service /my-service: .metadata.annotations accessor error: contains non-string value in the map under key \"invalid-annotation\": <nil> is of the type <nil>, expected string")
}
func TestGetAppInstanceLabel(t *testing.T) {
t.Parallel()
yamlBytes, err := os.ReadFile("testdata/svc.yaml")
require.NoError(t, err)
var obj unstructured.Unstructured
err = yaml.Unmarshal(yamlBytes, &obj)
require.NoError(t, err)
err = SetAppInstanceLabel(&obj, common.LabelKeyAppInstance, "my-app")
require.NoError(t, err)
label, err := GetAppInstanceLabel(&obj, common.LabelKeyAppInstance)
require.NoError(t, err)
assert.Equal(t, "my-app", label)
}
func TestGetAppInstanceLabelWithInvalidData(t *testing.T) {
t.Parallel()
yamlBytes, err := os.ReadFile("testdata/svc-with-invalid-data.yaml")
require.NoError(t, err)
var obj unstructured.Unstructured
err = yaml.Unmarshal(yamlBytes, &obj)
require.NoError(t, err)
_, err = GetAppInstanceLabel(&obj, "valid-label")
assert.EqualError(t, err, "failed to get labels for /v1, Kind=Service /my-service: .metadata.labels accessor error: contains non-string value in the map under key \"invalid-label\": <nil> is of the type <nil>, expected string")
}
func TestRemoveLabel(t *testing.T) {
t.Parallel()
yamlBytes, err := os.ReadFile("testdata/svc.yaml")
require.NoError(t, err)
var obj unstructured.Unstructured
err = yaml.Unmarshal(yamlBytes, &obj)
require.NoError(t, err)
obj.SetLabels(map[string]string{"test": "value"})
err = RemoveLabel(&obj, "test")
require.NoError(t, err)
assert.Nil(t, obj.GetLabels())
}
func TestRemoveLabelWithInvalidData(t *testing.T) {
t.Parallel()
yamlBytes, err := os.ReadFile("testdata/svc-with-invalid-data.yaml")
require.NoError(t, err)
var obj unstructured.Unstructured
err = yaml.Unmarshal(yamlBytes, &obj)
require.NoError(t, err)
err = RemoveLabel(&obj, "valid-label")
assert.EqualError(t, err, "failed to get labels for /v1, Kind=Service /my-service: .metadata.labels accessor error: contains non-string value in the map under key \"invalid-label\": <nil> is of the type <nil>, expected string")
}