test(e2e): add e2e tests for reverse deletionOrder when progressive sync enabled (#26673)

Signed-off-by: Kanika Rana <krana@redhat.com>
This commit is contained in:
Kanika Rana 2026-04-02 10:23:38 -04:00 committed by GitHub
parent 3eebbcb33b
commit fabbbbe6ee
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 254 additions and 87 deletions

View file

@ -487,7 +487,7 @@ test-e2e:
test-e2e-local: cli-local
# NO_PROXY ensures all tests don't go out through a proxy if one is configured on the test system
export GO111MODULE=off
DIST_DIR=${DIST_DIR} RERUN_FAILS=$(ARGOCD_E2E_RERUN_FAILS) PACKAGES="./test/e2e" ARGOCD_E2E_RECORD=${ARGOCD_E2E_RECORD} ARGOCD_CONFIG_DIR=$(HOME)/.config/argocd-e2e ARGOCD_GPG_ENABLED=true NO_PROXY=* ./hack/test.sh -timeout $(ARGOCD_E2E_TEST_TIMEOUT) -v -args -test.gocoverdir="$(PWD)/test-results"
ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_SYNCS=$${ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_SYNCS:-true} DIST_DIR=${DIST_DIR} RERUN_FAILS=$(ARGOCD_E2E_RERUN_FAILS) PACKAGES="./test/e2e" ARGOCD_E2E_RECORD=${ARGOCD_E2E_RECORD} ARGOCD_CONFIG_DIR=$(HOME)/.config/argocd-e2e ARGOCD_GPG_ENABLED=true NO_PROXY=* ./hack/test.sh -timeout $(ARGOCD_E2E_TEST_TIMEOUT) -v -args -test.gocoverdir="$(PWD)/test-results"
# Spawns a shell in the test server container for debugging purposes
debug-test-server: test-tools-image

View file

@ -10,5 +10,5 @@ git-server: test/fixture/testrepos/start-git.sh
helm-registry: test/fixture/testrepos/start-helm-registry.sh
oci-registry: test/fixture/testrepos/start-authenticated-helm-registry.sh
dev-mounter: [ "$ARGOCD_E2E_TEST" != "true" ] && go run hack/dev-mounter/main.go --configmap argocd-ssh-known-hosts-cm=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} --configmap argocd-tls-certs-cm=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} --configmap argocd-gpg-keys-cm=${ARGOCD_GPG_DATA_PATH:-/tmp/argocd-local/gpg/source}
applicationset-controller: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "GOCOVERDIR=${ARGOCD_COVERAGE_DIR:-/tmp/coverage/applicationset-controller} FORCE_LOG_COLORS=4 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-applicationset-controller $COMMAND --loglevel debug --metrics-addr localhost:12345 --probe-addr localhost:12346 --argocd-repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081}"
applicationset-controller: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "GOCOVERDIR=${ARGOCD_COVERAGE_DIR:-/tmp/coverage/applicationset-controller} FORCE_LOG_COLORS=4 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-applicationset-controller ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_SYNCS=${ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_SYNCS:-true} $COMMAND --loglevel debug --metrics-addr localhost:12345 --probe-addr localhost:12346 --argocd-repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081}"
notification: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "GOCOVERDIR=${ARGOCD_COVERAGE_DIR:-/tmp/coverage/notification} FORCE_LOG_COLORS=4 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_BINARY_NAME=argocd-notifications $COMMAND --loglevel debug --application-namespaces=${ARGOCD_APPLICATION_NAMESPACES:-''} --self-service-notification-enabled=${ARGOCD_NOTIFICATION_CONTROLLER_SELF_SERVICE_NOTIFICATION_ENABLED:-'false'}"

View file

@ -133,7 +133,7 @@ func TestSimpleGitDirectoryGenerator(t *testing.T) {
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist(expectedAppsNewNamespace))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist(expectedAppsNewNamespace))
}
func TestSimpleGitDirectoryGeneratorGoTemplate(t *testing.T) {
@ -240,7 +240,7 @@ func TestSimpleGitDirectoryGeneratorGoTemplate(t *testing.T) {
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist(expectedAppsNewNamespace))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist(expectedAppsNewNamespace))
}
func TestSimpleGitDirectoryGeneratorGPGEnabledUnsignedCommits(t *testing.T) {
@ -335,7 +335,7 @@ func TestSimpleGitDirectoryGeneratorGPGEnabledUnsignedCommits(t *testing.T) {
// verify the ApplicationSet error status conditions were set correctly
Expect(ApplicationSetHasConditions(expectedConditionsParamsError)).
When().
Delete().Then().Expect(ApplicationsDoNotExist(expectedApps))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist(expectedApps))
}
func TestSimpleGitDirectoryGeneratorGPGEnabledWithoutKnownKeys(t *testing.T) {
@ -438,7 +438,7 @@ func TestSimpleGitDirectoryGeneratorGPGEnabledWithoutKnownKeys(t *testing.T) {
Expect(ApplicationSetHasConditions(expectedConditionsParamsError)).
Expect(ApplicationsDoNotExist(expectedApps)).
When().
Delete().Then().Expect(ApplicationsDoNotExist(expectedApps))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist(expectedApps))
}
func TestSimpleGitFilesGenerator(t *testing.T) {
@ -544,7 +544,7 @@ func TestSimpleGitFilesGenerator(t *testing.T) {
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist(expectedAppsNewNamespace))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist(expectedAppsNewNamespace))
}
func TestSimpleGitFilesGeneratorGPGEnabledUnsignedCommits(t *testing.T) {
@ -639,7 +639,7 @@ func TestSimpleGitFilesGeneratorGPGEnabledUnsignedCommits(t *testing.T) {
// verify the ApplicationSet error status conditions were set correctly
Expect(ApplicationSetHasConditions(expectedConditionsParamsError)).
When().
Delete().Then().Expect(ApplicationsDoNotExist(expectedApps))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist(expectedApps))
}
func TestSimpleGitFilesGeneratorGPGEnabledWithoutKnownKeys(t *testing.T) {
@ -738,7 +738,7 @@ func TestSimpleGitFilesGeneratorGPGEnabledWithoutKnownKeys(t *testing.T) {
Expect(ApplicationSetHasConditions(expectedConditionsParamsError)).
Expect(ApplicationsDoNotExist(expectedApps)).
When().
Delete().Then().Expect(ApplicationsDoNotExist(expectedApps))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist(expectedApps))
}
func TestSimpleGitFilesGeneratorGoTemplate(t *testing.T) {
@ -845,7 +845,7 @@ func TestSimpleGitFilesGeneratorGoTemplate(t *testing.T) {
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist(expectedAppsNewNamespace))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist(expectedAppsNewNamespace))
}
func TestSimpleGitFilesPreserveResourcesOnDeletion(t *testing.T) {
@ -894,7 +894,7 @@ func TestSimpleGitFilesPreserveResourcesOnDeletion(t *testing.T) {
// We use an extra-long duration here, as we might need to wait for image pull.
}).Then().ExpectWithDuration(Pod(t, func(p corev1.Pod) bool { return strings.Contains(p.Name, "guestbook-ui") }), 6*time.Minute).
When().
Delete().
Delete(metav1.DeletePropagationForeground).
And(func() {
t.Log("Waiting 15 seconds to give the cluster a chance to delete the pods.")
// Wait 15 seconds to give the cluster a chance to deletes the pods, if it is going to do so.
@ -952,7 +952,7 @@ func TestSimpleGitFilesPreserveResourcesOnDeletionGoTemplate(t *testing.T) {
// We use an extra-long duration here, as we might need to wait for image pull.
}).Then().ExpectWithDuration(Pod(t, func(p corev1.Pod) bool { return strings.Contains(p.Name, "guestbook-ui") }), 6*time.Minute).
When().
Delete().
Delete(metav1.DeletePropagationForeground).
And(func() {
t.Log("Waiting 15 seconds to give the cluster a chance to delete the pods.")
// Wait 15 seconds to give the cluster a chance to deletes the pods, if it is going to do so.
@ -1034,7 +1034,7 @@ func TestGitGeneratorPrivateRepo(t *testing.T) {
}).Then().Expect(ApplicationsExist(expectedApps)).
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist(expectedAppsNewNamespace))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist(expectedAppsNewNamespace))
}
func TestGitGeneratorPrivateRepoGoTemplate(t *testing.T) {
@ -1108,7 +1108,7 @@ func TestGitGeneratorPrivateRepoGoTemplate(t *testing.T) {
}).Then().Expect(ApplicationsExist(expectedApps)).
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist(expectedAppsNewNamespace))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist(expectedAppsNewNamespace))
}
func TestSimpleGitGeneratorPrivateRepoWithNoRepo(t *testing.T) {
@ -1180,7 +1180,7 @@ func TestSimpleGitGeneratorPrivateRepoWithNoRepo(t *testing.T) {
}).Then().Expect(ApplicationsDoNotExist(expectedApps)).
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist(expectedAppsNewNamespace))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist(expectedAppsNewNamespace))
}
func TestSimpleGitGeneratorPrivateRepoWithMatchingProject(t *testing.T) {
@ -1251,7 +1251,7 @@ func TestSimpleGitGeneratorPrivateRepoWithMatchingProject(t *testing.T) {
}).Then().Expect(ApplicationsExist(expectedApps)).
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist(expectedApps))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist(expectedApps))
}
func TestSimpleGitGeneratorPrivateRepoWithMismatchingProject(t *testing.T) {
@ -1324,7 +1324,7 @@ func TestSimpleGitGeneratorPrivateRepoWithMismatchingProject(t *testing.T) {
}).Then().Expect(ApplicationsDoNotExist(expectedApps)).
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist(expectedAppsNewNamespace))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist(expectedAppsNewNamespace))
}
func TestGitGeneratorPrivateRepoWithTemplatedProject(t *testing.T) {
@ -1400,7 +1400,7 @@ func TestGitGeneratorPrivateRepoWithTemplatedProject(t *testing.T) {
}).Then().Expect(ApplicationsExist(expectedApps)).
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist(expectedAppsNewNamespace))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist(expectedAppsNewNamespace))
}
func TestGitGeneratorPrivateRepoWithTemplatedProjectAndProjectScopedRepo(t *testing.T) {
@ -1484,5 +1484,5 @@ func TestGitGeneratorPrivateRepoWithTemplatedProjectAndProjectScopedRepo(t *test
}).Then().Expect(ApplicationsDoNotExist(expectedApps)).
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist(expectedAppsNewNamespace))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist(expectedAppsNewNamespace))
}

View file

@ -175,7 +175,7 @@ func TestApplicationSetProgressiveSyncStep(t *testing.T) {
ExpectWithDuration(CheckApplicationInRightSteps("3", []string{"app3-prod"}), time.Second*5).
// cleanup
When().
Delete().
Delete(metav1.DeletePropagationForeground).
Then().
ExpectWithDuration(ApplicationsDoNotExist([]v1alpha1.Application{expectedDevApp, expectedStageApp, expectedProdApp}), time.Minute)
}
@ -184,9 +184,9 @@ func TestProgressiveSyncHealthGating(t *testing.T) {
if os.Getenv("ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_SYNCS") != "true" {
t.Skip("Skipping progressive sync tests - ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_SYNCS not enabled")
}
expectedDevApp := generateExpectedApp("prog-", "progressive-sync/", "dev", "dev")
expectedStageApp := generateExpectedApp("prog-", "progressive-sync/", "staging", "staging")
expectedProdApp := generateExpectedApp("prog-", "progressive-sync/", "prod", "prod")
expectedDevApp := generateExpectedApp("prog-", "progressive-sync/", "dev", "dev", "")
expectedStageApp := generateExpectedApp("prog-", "progressive-sync/", "staging", "staging", "")
expectedProdApp := generateExpectedApp("prog-", "progressive-sync/", "prod", "prod", "")
expectedStatusWave1 := map[string]v1alpha1.ApplicationSetApplicationStatus{
"prog-dev": {
@ -343,7 +343,7 @@ func TestProgressiveSyncHealthGating(t *testing.T) {
}).
// Cleanup
When().
Delete().
Delete(metav1.DeletePropagationForeground).
Then().
ExpectWithDuration(ApplicationsDoNotExist([]v1alpha1.Application{expectedDevApp, expectedStageApp, expectedProdApp}), TransitionTimeout)
}
@ -381,9 +381,9 @@ func TestNoApplicationStatusWhenNoSteps(t *testing.T) {
}
expectedApps := []v1alpha1.Application{
generateExpectedApp("prog-", "progressive-sync/", "dev", "dev"),
generateExpectedApp("prog-", "progressive-sync/", "staging", "staging"),
generateExpectedApp("prog-", "progressive-sync/", "prod", "prod"),
generateExpectedApp("prog-", "progressive-sync/", "dev", "dev", ""),
generateExpectedApp("prog-", "progressive-sync/", "staging", "staging", ""),
generateExpectedApp("prog-", "progressive-sync/", "prod", "prod", ""),
}
Given(t).
When().
@ -393,7 +393,7 @@ func TestNoApplicationStatusWhenNoSteps(t *testing.T) {
Expect(ApplicationSetDoesNotHaveApplicationStatus()).
// Cleanup
When().
Delete().
Delete(metav1.DeletePropagationForeground).
Then().
ExpectWithDuration(ApplicationsDoNotExist(expectedApps), TransitionTimeout)
}
@ -403,9 +403,9 @@ func TestNoApplicationStatusWhenNoApplications(t *testing.T) {
t.Skip("Skipping progressive sync tests - ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_SYNCS not enabled")
}
expectedApps := []v1alpha1.Application{
generateExpectedApp("prog-", "progressive-sync/", "dev", "dev"),
generateExpectedApp("prog-", "progressive-sync/", "staging", "staging"),
generateExpectedApp("prog-", "progressive-sync/", "prod", "prod"),
generateExpectedApp("prog-", "progressive-sync/", "dev", "dev", ""),
generateExpectedApp("prog-", "progressive-sync/", "staging", "staging", ""),
generateExpectedApp("prog-", "progressive-sync/", "prod", "prod", ""),
}
Given(t).
When().
@ -415,37 +415,107 @@ func TestNoApplicationStatusWhenNoApplications(t *testing.T) {
Expect(ApplicationSetDoesNotHaveApplicationStatus()).
// Cleanup
When().
Delete().
Delete(metav1.DeletePropagationForeground).
Then().
Expect(ApplicationsDoNotExist(expectedApps))
}
func TestProgressiveSyncMultipleAppsPerStep(t *testing.T) {
func TestProgressiveSyncMultipleAppsPerStepWithReverseDeletionOrder(t *testing.T) {
if os.Getenv("ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_SYNCS") != "true" {
t.Skip("Skipping progressive sync tests - ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_SYNCS not enabled")
}
expectedApps := []v1alpha1.Application{
generateExpectedApp("prog-", "progressive-sync/multiple-apps-in-step/dev/", "sketch", "dev"),
generateExpectedApp("prog-", "progressive-sync/multiple-apps-in-step/dev/", "build", "dev"),
generateExpectedApp("prog-", "progressive-sync/multiple-apps-in-step/staging/", "verify", "staging"),
generateExpectedApp("prog-", "progressive-sync/multiple-apps-in-step/staging/", "validate", "staging"),
generateExpectedApp("prog-", "progressive-sync/multiple-apps-in-step/prod/", "ship", "prod"),
generateExpectedApp("prog-", "progressive-sync/multiple-apps-in-step/prod/", "run", "prod"),
// Define app groups by step (for reverse deletion: prod -> staging -> dev)
prodApps := []string{"prog-ship", "prog-run"}
stagingApps := []string{"prog-verify", "prog-validate"}
devApps := []string{"prog-sketch", "prog-build"}
testFinalizer := "test.e2e.argoproj.io/wait-for-verification"
// Create expected app definitions for existence checks
expectedProdApps := []v1alpha1.Application{
generateExpectedApp("prog-", "progressive-sync/multiple-apps-in-step/prod/", "ship", "prod", testFinalizer),
generateExpectedApp("prog-", "progressive-sync/multiple-apps-in-step/prod/", "run", "prod", testFinalizer),
}
expectedStagingApps := []v1alpha1.Application{
generateExpectedApp("prog-", "progressive-sync/multiple-apps-in-step/staging/", "verify", "staging", testFinalizer),
generateExpectedApp("prog-", "progressive-sync/multiple-apps-in-step/staging/", "validate", "staging", testFinalizer),
}
expectedDevApps := []v1alpha1.Application{
generateExpectedApp("prog-", "progressive-sync/multiple-apps-in-step/dev/", "sketch", "dev", testFinalizer),
generateExpectedApp("prog-", "progressive-sync/multiple-apps-in-step/dev/", "build", "dev", testFinalizer),
}
var allExpectedApps []v1alpha1.Application
allExpectedApps = append(allExpectedApps, expectedProdApps...)
allExpectedApps = append(allExpectedApps, expectedStagingApps...)
allExpectedApps = append(allExpectedApps, expectedDevApps...)
Given(t).
When().
Create(appSetWithMultipleAppsInEachStep).
Create(appSetWithReverseDeletionOrder).
Then().
Expect(ApplicationsExist(expectedApps)).
And(func() {
t.Log("ApplicationSet with reverse deletion order created")
}).
Expect(ApplicationsExist(allExpectedApps)).
Expect(CheckApplicationInRightSteps("1", []string{"prog-sketch", "prog-build"})).
Expect(CheckApplicationInRightSteps("2", []string{"prog-verify", "prog-validate"})).
Expect(CheckApplicationInRightSteps("3", []string{"prog-ship", "prog-run"})).
ExpectWithDuration(ApplicationSetHasApplicationStatus(6), TransitionTimeout).
// Cleanup
And(func() {
t.Log("All 6 applications exist and are tracked in ApplicationSet status")
}).
// Delete the ApplicationSet
When().
Delete().
Delete(metav1.DeletePropagationBackground).
Then().
Expect(ApplicationsDoNotExist(expectedApps))
And(func() {
t.Log("Starting deletion - should happen in reverse order: prod -> staging -> dev")
t.Log("Wave 1: Verifying prod apps (prog-ship, prog-run) are deleted first")
}).
// Wave 1: Prod apps should be deleted first, others untouched
Expect(ApplicationDeletionStarted(prodApps)).
Expect(ApplicationsExistAndNotBeingDeleted(append(stagingApps, devApps...))).
And(func() {
t.Log("Wave 1 confirmed: prod apps deleting/gone, staging and dev apps still exist and not being deleted")
}).
When().
RemoveFinalizerFromApps(prodApps, testFinalizer).
Then().
And(func() {
t.Log("removed finalizer from prod apps, confirm prod apps deleted")
t.Log("Wave 2: Verifying staging apps (prog-verify, prog-validate) are deleted second")
}).
// Wave 2: Staging apps being deleted, dev untouched
ExpectWithDuration(ApplicationsDoNotExist(expectedProdApps), TransitionTimeout).
Expect(ApplicationDeletionStarted(stagingApps)).
Expect(ApplicationsExistAndNotBeingDeleted(devApps)).
And(func() {
t.Log("Wave 2 confirmed: prod apps gone, staging apps deleting/gone, dev apps still exist and not being deleted")
}).
When().
RemoveFinalizerFromApps(stagingApps, testFinalizer).
Then().
And(func() {
t.Log("removed finalizer from staging apps, confirm staging apps deleted")
t.Log("Wave 3: Verifying dev apps (prog-sketch, prog-build) are deleted last")
}).
// Wave 3: Dev apps deleted last
ExpectWithDuration(ApplicationsDoNotExist(expectedStagingApps), TransitionTimeout).
Expect(ApplicationDeletionStarted(devApps)).
And(func() {
t.Log("Wave 3 confirmed: all prod and staging apps gone, dev apps deleting/gone")
}).
When().
RemoveFinalizerFromApps(devApps, testFinalizer).
Then().
And(func() {
t.Log("removed finalizer from dev apps, confirm dev apps deleted")
t.Log("Waiting for final cleanup - all applications should be deleted")
}).
// Final: All applications should be gone
ExpectWithDuration(ApplicationsDoNotExist(allExpectedApps), time.Minute).
And(func() {
t.Log("Reverse deletion order verified successfully!")
t.Log("Deletion sequence was: prod -> staging -> dev")
})
}
var appSetInvalidStepConfiguration = v1alpha1.ApplicationSet{
@ -556,9 +626,13 @@ var appSetWithEmptyGenerator = v1alpha1.ApplicationSet{
},
}
var appSetWithMultipleAppsInEachStep = v1alpha1.ApplicationSet{
var appSetWithReverseDeletionOrder = v1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "progressive-sync-multi-apps",
Name: "appset-reverse-deletion-order",
},
TypeMeta: metav1.TypeMeta{
Kind: "ApplicationSet",
APIVersion: "argoproj.io/v1alpha1",
},
Spec: v1alpha1.ApplicationSetSpec{
GoTemplate: true,
@ -569,6 +643,10 @@ var appSetWithMultipleAppsInEachStep = v1alpha1.ApplicationSet{
Labels: map[string]string{
"environment": "{{.environment}}",
},
Finalizers: []string{
"resources-finalizer.argocd.argoproj.io",
"test.e2e.argoproj.io/wait-for-verification",
},
},
Spec: v1alpha1.ApplicationSpec{
Project: "default",
@ -605,11 +683,18 @@ var appSetWithMultipleAppsInEachStep = v1alpha1.ApplicationSet{
RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{
Steps: generateStandardRolloutSyncSteps(),
},
DeletionOrder: "Reverse",
},
},
}
func generateExpectedApp(prefix string, path string, name string, envVar string) v1alpha1.Application {
func generateExpectedApp(prefix string, path string, name string, envVar string, testFinalizer string) v1alpha1.Application {
finalizers := []string{
"resources-finalizer.argocd.argoproj.io",
}
if testFinalizer != "" {
finalizers = append(finalizers, testFinalizer)
}
return v1alpha1.Application{
TypeMeta: metav1.TypeMeta{
Kind: "Application",
@ -621,9 +706,7 @@ func generateExpectedApp(prefix string, path string, name string, envVar string)
Labels: map[string]string{
"environment": envVar,
},
Finalizers: []string{
"resources-finalizer.argocd.argoproj.io",
},
Finalizers: finalizers,
},
Spec: v1alpha1.ApplicationSpec{
Project: "default",

View file

@ -147,7 +147,7 @@ func TestSimpleListGeneratorExternalNamespace(t *testing.T) {
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{*expectedAppNewMetadata}))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{*expectedAppNewMetadata}))
}
func TestSimpleListGeneratorExternalNamespaceNoConflict(t *testing.T) {
@ -325,13 +325,13 @@ func TestSimpleListGeneratorExternalNamespaceNoConflict(t *testing.T) {
Then().
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{*expectedAppNewMetadata})).
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{*expectedAppNewMetadata})).
When().
SwitchToExternalNamespace(utils.ArgoCDExternalNamespace2).
Then().
Expect(ApplicationsExist([]v1alpha1.Application{expectedAppExternalNamespace2})).
When().
Delete().Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{expectedAppExternalNamespace2}))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{expectedAppExternalNamespace2}))
}
func TestSimpleListGenerator(t *testing.T) {
@ -420,7 +420,7 @@ func TestSimpleListGenerator(t *testing.T) {
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{*expectedAppNewMetadata}))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{*expectedAppNewMetadata}))
}
func TestSimpleListGeneratorGoTemplate(t *testing.T) {
@ -509,7 +509,7 @@ func TestSimpleListGeneratorGoTemplate(t *testing.T) {
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{*expectedAppNewMetadata}))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{*expectedAppNewMetadata}))
}
func TestRenderHelmValuesObject(t *testing.T) {
@ -581,7 +581,7 @@ func TestRenderHelmValuesObject(t *testing.T) {
}).Then().Expect(ApplicationsExist([]v1alpha1.Application{expectedApp})).
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{expectedApp}))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{expectedApp}))
}
func TestTemplatePatch(t *testing.T) {
@ -705,7 +705,7 @@ func TestTemplatePatch(t *testing.T) {
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{*expectedAppNewMetadata}))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{*expectedAppNewMetadata}))
}
func TestUpdateHelmValuesObject(t *testing.T) {
@ -787,7 +787,7 @@ func TestUpdateHelmValuesObject(t *testing.T) {
Expect(ApplicationsExist([]v1alpha1.Application{expectedApp})).
When().
// Delete the ApplicationSet, and verify it deletes the Applications
Delete().Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{expectedApp}))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{expectedApp}))
}
func TestSyncPolicyCreateUpdate(t *testing.T) {
@ -898,7 +898,7 @@ func TestSyncPolicyCreateUpdate(t *testing.T) {
// As policy is create-update, AppSet controller will remove all generated applications's ownerReferences on delete AppSet
// So AppSet deletion will be reflected, but all the applications it generates will still exist
When().
Delete().Then().Expect(ApplicationsExist([]v1alpha1.Application{*expectedAppNewMetadata}))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsExist([]v1alpha1.Application{*expectedAppNewMetadata}))
}
func TestSyncPolicyCreateDelete(t *testing.T) {
@ -994,7 +994,7 @@ func TestSyncPolicyCreateDelete(t *testing.T) {
// Delete the ApplicationSet
When().
Delete().Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{*expectedAppNewNamespace}))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{*expectedAppNewNamespace}))
}
func TestSyncPolicyCreateOnly(t *testing.T) {
@ -1095,7 +1095,7 @@ func TestSyncPolicyCreateOnly(t *testing.T) {
// As policy is create-update, AppSet controller will remove all generated applications's ownerReferences on delete AppSet
// So AppSet deletion will be reflected, but all the applications it generates will still exist
When().
Delete().Then().Expect(ApplicationsExist([]v1alpha1.Application{*expectedAppNewNamespace}))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsExist([]v1alpha1.Application{*expectedAppNewNamespace}))
}
func githubSCMMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
@ -1582,7 +1582,7 @@ func TestCustomApplicationFinalizers(t *testing.T) {
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{expectedApp}))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{expectedApp}))
}
func TestCustomApplicationFinalizersGoTemplate(t *testing.T) {
@ -1647,7 +1647,7 @@ func TestCustomApplicationFinalizersGoTemplate(t *testing.T) {
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{expectedApp}))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{expectedApp}))
}
func githubPullMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
@ -2174,7 +2174,7 @@ func TestApplicationSetAPIListResourceEvents(t *testing.T) {
// Events list should be returned (may be empty if no events have been generated yet)
assert.NotNil(t, events)
}).
When().Delete().Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{}))
When().Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{}))
}
// TestApplicationSetHealthStatusCLI tests that the CLI commands display the health status field for an ApplicationSet.

View file

@ -108,7 +108,7 @@ func TestSimpleClusterGeneratorExternalNamespace(t *testing.T) {
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{*expectedAppNewNamespace}))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{*expectedAppNewNamespace}))
}
func TestSimpleClusterGenerator(t *testing.T) {
@ -199,7 +199,7 @@ func TestSimpleClusterGenerator(t *testing.T) {
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{*expectedAppNewNamespace}))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{*expectedAppNewNamespace}))
}
func TestClusterGeneratorWithLocalCluster(t *testing.T) {
@ -311,7 +311,7 @@ func TestClusterGeneratorWithLocalCluster(t *testing.T) {
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{*expectedAppNewNamespace}))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{*expectedAppNewNamespace}))
})
}
}
@ -392,7 +392,7 @@ func TestSimpleClusterGeneratorAddingCluster(t *testing.T) {
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{expectedAppCluster1, expectedAppCluster2}))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{expectedAppCluster1, expectedAppCluster2}))
}
func TestSimpleClusterGeneratorDeletingCluster(t *testing.T) {
@ -473,7 +473,7 @@ func TestSimpleClusterGeneratorDeletingCluster(t *testing.T) {
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{expectedAppCluster1}))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{expectedAppCluster1}))
}
func TestClusterGeneratorWithFlatListMode(t *testing.T) {
@ -574,5 +574,5 @@ func TestClusterGeneratorWithFlatListMode(t *testing.T) {
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{expectedAppCluster2}))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{expectedAppCluster2}))
}

View file

@ -119,7 +119,7 @@ func TestSimpleClusterDecisionResourceGeneratorExternalNamespace(t *testing.T) {
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{*expectedAppNewNamespace}))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{*expectedAppNewNamespace}))
}
func TestSimpleClusterDecisionResourceGenerator(t *testing.T) {
@ -218,7 +218,7 @@ func TestSimpleClusterDecisionResourceGenerator(t *testing.T) {
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{*expectedAppNewNamespace}))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{*expectedAppNewNamespace}))
}
func TestSimpleClusterDecisionResourceGeneratorAddingCluster(t *testing.T) {
@ -310,7 +310,7 @@ func TestSimpleClusterDecisionResourceGeneratorAddingCluster(t *testing.T) {
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{expectedAppCluster1, expectedAppCluster2}))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{expectedAppCluster1, expectedAppCluster2}))
}
func TestSimpleClusterDecisionResourceGeneratorDeletingClusterSecret(t *testing.T) {
@ -404,7 +404,7 @@ func TestSimpleClusterDecisionResourceGeneratorDeletingClusterSecret(t *testing.
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{expectedAppCluster1}))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{expectedAppCluster1}))
}
func TestSimpleClusterDecisionResourceGeneratorDeletingClusterFromResource(t *testing.T) {
@ -505,5 +505,5 @@ func TestSimpleClusterDecisionResourceGeneratorDeletingClusterFromResource(t *te
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{expectedAppCluster1}))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist([]v1alpha1.Application{expectedAppCluster1}))
}

View file

@ -7,6 +7,9 @@ import (
"strings"
"time"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/util/retry"
"github.com/argoproj/argo-cd/v3/test/e2e/fixture"
log "github.com/sirupsen/logrus"
@ -391,7 +394,7 @@ func (a *Actions) StatusUpdatePlacementDecision(placementDecisionName string, cl
}
// Delete deletes the ApplicationSet within the context
func (a *Actions) Delete() *Actions {
func (a *Actions) Delete(propagationPolicy metav1.DeletionPropagation) *Actions {
a.context.T().Helper()
fixtureClient := utils.GetE2EFixtureK8sClient(a.context.T())
@ -408,9 +411,7 @@ func (a *Actions) Delete() *Actions {
} else {
appSetClientSet = fixtureClient.AppSetClientset
}
deleteProp := metav1.DeletePropagationForeground
err := appSetClientSet.Delete(context.Background(), a.context.GetName(), metav1.DeleteOptions{PropagationPolicy: &deleteProp})
err := appSetClientSet.Delete(context.Background(), a.context.GetName(), metav1.DeleteOptions{PropagationPolicy: &propagationPolicy})
a.describeAction = fmt.Sprintf("Deleting ApplicationSet '%s/%s' %v", a.context.namespace, a.context.GetName(), err)
a.lastOutput, a.lastError = "", err
a.verifyAction()
@ -566,3 +567,48 @@ func (a *Actions) AddSignedFile(fileName, fileContents string) *Actions {
fixture.AddSignedFile(a.context.T(), a.context.path+"/"+fileName, fileContents)
return a
}
func (a *Actions) RemoveFinalizerFromApps(appNames []string, finalizer string) *Actions {
a.context.T().Helper()
fixtureClient := utils.GetE2EFixtureK8sClient(a.context.T())
var namespace string
if a.context.switchToNamespace != "" {
namespace = string(a.context.switchToNamespace)
} else {
namespace = fixture.TestNamespace()
}
for _, appName := range appNames {
err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
app, err := fixtureClient.AppClientset.ArgoprojV1alpha1().Applications(namespace).Get(
a.context.T().Context(), appName, metav1.GetOptions{})
if err != nil {
return err
}
// Remove provided finalizer
finalizers := []string{}
for _, f := range app.Finalizers {
if f != finalizer {
finalizers = append(finalizers, f)
}
}
patch, _ := json.Marshal(map[string]any{
"metadata": map[string]any{
"finalizers": finalizers,
},
})
_, err = fixtureClient.AppClientset.ArgoprojV1alpha1().Applications(namespace).Patch(
a.context.T().Context(), app.Name, types.MergePatchType, patch, metav1.PatchOptions{})
if err != nil {
return err
}
return nil
})
if err != nil {
a.lastError = err
}
}
a.describeAction = fmt.Sprintf("removing finalizer '%s' from apps %v", finalizer, appNames)
a.verifyAction()
return a
}

View file

@ -336,3 +336,41 @@ func ApplicationSetHasApplicationStatus(expectedApplicationStatusLength int) Exp
return succeeded, fmt.Sprintf("All Applications in ApplicationSet: '%s' are Healthy ", c.context.GetName())
}
}
// ApplicationDeletionStarted verifies at least one application from provided list of appNames has DeletionTimestamp set,
// indicating deletion has begun for this step. Returns failed if any application doesn't exist, does not expect completion of deletion.
func ApplicationDeletionStarted(appNames []string) Expectation {
return func(c *Consequences) (state, string) {
anyapp := false
for _, appName := range appNames {
app := c.app(appName)
if app == nil {
// with test finalizer explicitly added, application should not be deleted
return failed, fmt.Sprintf("no application found with name '%s'", c.context.GetName())
}
if app.DeletionTimestamp != nil {
anyapp = true
}
}
if !anyapp {
return pending, "no app in this step is being deleted yet"
}
return succeeded, fmt.Sprintf("at least one app in %v is being deleted or gone", appNames)
}
}
// ApplicationsExistAndNotBeingDeleted checks that specified apps exist and do NOT have DeletionTimestamp set
func ApplicationsExistAndNotBeingDeleted(appNames []string) Expectation {
return func(c *Consequences) (state, string) {
for _, appName := range appNames {
app := c.app(appName)
if app == nil {
return failed, fmt.Sprintf("app '%s' does not exist but should", appName)
}
if app.DeletionTimestamp != nil {
return failed, fmt.Sprintf("app '%s' is being deleted but should not be yet", appName)
}
}
return succeeded, fmt.Sprintf("all apps %v exist and are not being deleted", appNames)
}
}

View file

@ -131,7 +131,7 @@ func TestListMatrixGenerator(t *testing.T) {
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist(expectedAppsNewNamespace))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist(expectedAppsNewNamespace))
}
func TestClusterMatrixGenerator(t *testing.T) {
@ -254,7 +254,7 @@ func TestClusterMatrixGenerator(t *testing.T) {
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist(expectedAppsNewNamespace))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist(expectedAppsNewNamespace))
}
func TestMatrixTerminalMatrixGeneratorSelector(t *testing.T) {
@ -392,7 +392,7 @@ func TestMatrixTerminalMatrixGeneratorSelector(t *testing.T) {
})
}).Then().Expect(ApplicationsExist(expectedApps)).Expect(ApplicationsDoNotExist(excludedApps)).
When().
Delete().Then().Expect(ApplicationsDoNotExist(excludedApps)).Expect(ApplicationsDoNotExist(expectedApps))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist(excludedApps)).Expect(ApplicationsDoNotExist(expectedApps))
}
func TestMatrixTerminalMergeGeneratorSelector(t *testing.T) {
@ -530,5 +530,5 @@ func TestMatrixTerminalMergeGeneratorSelector(t *testing.T) {
})
}).Then().Expect(ApplicationsExist(expectedApps)).Expect(ApplicationsDoNotExist(excludedApps)).
When().
Delete().Then().Expect(ApplicationsDoNotExist(excludedApps)).Expect(ApplicationsDoNotExist(expectedApps))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist(excludedApps)).Expect(ApplicationsDoNotExist(expectedApps))
}

View file

@ -130,7 +130,7 @@ func TestListMergeGenerator(t *testing.T) {
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist(expectedAppsNewNamespace))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist(expectedAppsNewNamespace))
}
func TestClusterMergeGenerator(t *testing.T) {
@ -271,7 +271,7 @@ func TestClusterMergeGenerator(t *testing.T) {
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist(expectedAppsNewNamespace))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist(expectedAppsNewNamespace))
}
func TestMergeTerminalMergeGeneratorSelector(t *testing.T) {
@ -410,7 +410,7 @@ func TestMergeTerminalMergeGeneratorSelector(t *testing.T) {
})
}).Then().Expect(ApplicationsExist(expectedApps)).Expect(ApplicationsDoNotExist(excludedApps)).
When().
Delete().Then().Expect(ApplicationsDoNotExist(excludedApps)).Expect(ApplicationsDoNotExist(expectedApps))
Delete(metav1.DeletePropagationForeground).Then().Expect(ApplicationsDoNotExist(excludedApps)).Expect(ApplicationsDoNotExist(expectedApps))
}
func toAPIExtensionsJSON(t *testing.T, g any) *apiextensionsv1.JSON {