Files
deploy/test/e2e/sync_waves_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

161 lines
5.0 KiB
Go

package e2e
import (
"testing"
"time"
"github.com/hanzoai/cd/gitops-engine/pkg/health"
. "github.com/hanzoai/cd/gitops-engine/pkg/sync/common"
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
. "github.com/hanzoai/cd/pkg/apis/application/v1alpha1"
. "github.com/hanzoai/cd/test/e2e/fixture"
. "github.com/hanzoai/cd/test/e2e/fixture/app"
)
func TestFixingDegradedApp(t *testing.T) {
var lastTransitionTime string
Given(t).
Path("sync-waves").
When().
IgnoreErrors().
CreateApp().
And(func() {
require.NoError(t, SetResourceOverrides(map[string]ResourceOverride{
"ConfigMap": {
HealthLua: `return { status = obj.metadata.annotations and obj.metadata.annotations['health'] or 'Degraded' }`,
},
}))
}).
Sync().
Then().
Expect(OperationPhaseIs(OperationFailed)).
Expect(SyncStatusIs(SyncStatusCodeOutOfSync)).
Expect(HealthIs(health.HealthStatusDegraded)).
Expect(ResourceResultNumbering(1)).
Expect(ResourceSyncStatusIs("ConfigMap", "cm-1", SyncStatusCodeSynced)).
Expect(ResourceHealthIs("ConfigMap", "cm-1", health.HealthStatusDegraded)).
Expect(ResourceSyncStatusIs("ConfigMap", "cm-2", SyncStatusCodeOutOfSync)).
Expect(ResourceHealthIs("ConfigMap", "cm-2", health.HealthStatusMissing)).
When().
Then().
And(func(app *Application) {
lastTransitionTime = app.Status.Health.LastTransitionTime.UTC().Format(time.RFC3339)
}).
When().
PatchFile("cm-1.yaml", `[{"op": "replace", "path": "/metadata/annotations/health", "value": "Healthy"}]`).
PatchFile("cm-2.yaml", `[{"op": "replace", "path": "/metadata/annotations/health", "value": "Healthy"}]`).
// need to force a refresh here
Refresh(RefreshTypeNormal).
Then().
Expect(ResourceSyncStatusIs("ConfigMap", "cm-1", SyncStatusCodeOutOfSync)).
When().
Sync().
Then().
Expect(OperationPhaseIs(OperationSucceeded)).
Expect(SyncStatusIs(SyncStatusCodeSynced)).
Expect(HealthIs(health.HealthStatusHealthy)).
Expect(ResourceResultNumbering(2)).
Expect(ResourceSyncStatusIs("ConfigMap", "cm-1", SyncStatusCodeSynced)).
Expect(ResourceHealthIs("ConfigMap", "cm-1", health.HealthStatusHealthy)).
Expect(ResourceSyncStatusIs("ConfigMap", "cm-2", SyncStatusCodeSynced)).
Expect(ResourceHealthIs("ConfigMap", "cm-2", health.HealthStatusHealthy)).
When().
Then().
And(func(app *Application) {
// check that the last transition time is updated
require.NotEqual(t, lastTransitionTime, app.Status.Health.LastTransitionTime.UTC().Format(time.RFC3339))
})
}
func TestOneProgressingDeploymentIsSucceededAndSynced(t *testing.T) {
Given(t).
Path("one-deployment").
When().
// make this deployment get stuck in progressing due to "invalidimagename"
PatchFile("deployment.yaml", `[
{
"op": "replace",
"path": "/spec/template/spec/containers/0/image",
"value": "alpine:ops!"
}
]`).
CreateApp().
Sync().
Then().
Expect(OperationPhaseIs(OperationSucceeded)).
Expect(HealthIs(health.HealthStatusProgressing)).
Expect(SyncStatusIs(SyncStatusCodeSynced)).
Expect(ResourceResultNumbering(1))
}
func TestDegradedDeploymentIsSucceededAndSynced(t *testing.T) {
Given(t).
Path("one-deployment").
When().
// make this deployment get stuck in progressing due to "invalidimagename"
PatchFile("deployment.yaml", `[
{
"op": "replace",
"path": "/spec/progressDeadlineSeconds",
"value": 1
},
{
"op": "replace",
"path": "/spec/template/spec/containers/0/image",
"value": "alpine:ops!"
}
]`).
CreateApp().
Sync().
Then().
Expect(OperationPhaseIs(OperationSucceeded)).
Expect(HealthIs(health.HealthStatusDegraded)).
Expect(SyncStatusIs(SyncStatusCodeSynced)).
Expect(ResourceResultNumbering(1))
}
// resources should be pruned in reverse of creation order(syncwaves order)
func TestSyncPruneOrderWithSyncWaves(t *testing.T) {
ctx := Given(t).Timeout(60)
// remove finalizer to ensure proper cleanup if test fails at early stage
defer func() {
_, _ = RunCli("app", "patch-resource", ctx.AppQualifiedName(),
"--kind", "Pod",
"--resource-name", "pod-with-finalizers",
"--patch", `[{"op": "remove", "path": "/metadata/finalizers"}]`,
"--patch-type", "application/json-patch+json", "--all",
)
}()
ctx.Path("syncwaves-prune-order").
When().
CreateApp().
// creation order: sa & role -> rolebinding -> pod
Sync().
Wait().
Then().
Expect(SyncStatusIs(SyncStatusCodeSynced)).
Expect(HealthIs(health.HealthStatusHealthy)).
When().
// delete files to remove resources
DeleteFile("pod.yaml").
DeleteFile("rbac.yaml").
Refresh(RefreshTypeHard).
IgnoreErrors().
Then().
Expect(SyncStatusIs(SyncStatusCodeOutOfSync)).
When().
// prune order: pod -> rolebinding -> sa & role
Sync("--prune").
Wait().
Then().
Expect(OperationPhaseIs(OperationSucceeded)).
Expect(SyncStatusIs(SyncStatusCodeSynced)).
Expect(HealthIs(health.HealthStatusHealthy)).
Expect(NotPod(func(p corev1.Pod) bool { return p.Name == "pod-with-finalizers" })).
Expect(ResourceResultNumbering(4))
}