From 0f6bb91289d0966633d9a1e2f46590712e48118d Mon Sep 17 00:00:00 2001 From: Marek Aufart Date: Wed, 26 Aug 2026 16:15:18 +0200 Subject: [PATCH 1/2] Add E2E tests for export GK filtering Adding E2E tests for crane export with GK filtering feature. Related to https://github.com/migtools/crane/pull/863 and https://github.com/migtools/crane/pull/864 Signed-off-by: Marek Aufart --- e2e-tests/framework/crane.go | 4 + e2e-tests/tests/tier1/mta_gk_filter_test.go | 147 ++++++++++++++++++++ 2 files changed, 151 insertions(+) create mode 100644 e2e-tests/tests/tier1/mta_gk_filter_test.go diff --git a/e2e-tests/framework/crane.go b/e2e-tests/framework/crane.go index a530ddac..4a4616f5 100644 --- a/e2e-tests/framework/crane.go +++ b/e2e-tests/framework/crane.go @@ -48,6 +48,7 @@ type ExportOptions struct { QPS float32 Burst int Overwrite bool + ExtraArgs []string } type TransformOptions struct { @@ -104,6 +105,9 @@ func (c CraneRunner) Export(opts ExportOptions) error { if opts.Overwrite { args = append(args, "--overwrite") } + if len(opts.ExtraArgs) > 0 { + args = append(args, opts.ExtraArgs...) + } logVerboseCommand(c.Bin, args) cmd := exec.Command(c.Bin, args...) cmd.Dir = c.WorkDir diff --git a/e2e-tests/tests/tier1/mta_gk_filter_test.go b/e2e-tests/tests/tier1/mta_gk_filter_test.go new file mode 100644 index 00000000..f5f335f8 --- /dev/null +++ b/e2e-tests/tests/tier1/mta_gk_filter_test.go @@ -0,0 +1,147 @@ +package e2e + +import ( + "log" + "path/filepath" + + "github.com/konveyor/crane/e2e-tests/config" + . "github.com/konveyor/crane/e2e-tests/framework" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +// TODO: rename this file to mta__gk_filter_test.go and prefix the It +// descriptions with [MTA-] once the test plan / tracking issue for the +// Group/Kind export filter is created, to match the rest of the tier1 suite. +var _ = Describe("Crane export: filter resources by Group/Kind", func() { + const ( + appName = "gk-filter-test" + namespace = "gk-filter-test" + ) + + var ( + scenario MigrationScenario + srcApp K8sDeployApp + tgtApp K8sDeployApp + kubectlSrc KubectlRunner + paths ScenarioPaths + ) + + // resourceGlob builds a glob for exported manifests of a given Kind. Exported + // files are named "____.yaml", so the + // "_" prefix reliably selects resources of that Kind. + resourceGlob := func(kind string) string { + return filepath.Join(paths.ExportDir, "resources", namespace, kind+"_*") + } + + BeforeEach(func() { + scenario = NewMigrationScenario( + appName, + namespace, + config.K8sDeployBin, + config.CraneBin, + config.SourceContext, + config.TargetContext, + ) + srcApp = scenario.SrcApp + tgtApp = scenario.TgtApp + kubectlSrc = scenario.KubectlSrc + + By("Prepare source app with multiple resource types") + log.Printf("Preparing source app %s in namespace %s\n", srcApp.Name, srcApp.Namespace) + Expect(PrepareSourceApp(srcApp, kubectlSrc)).NotTo(HaveOccurred()) + log.Printf("Source app %s prepared successfully\n", srcApp.Name) + + configMapYAML := `apiVersion: v1 +kind: ConfigMap +metadata: + name: test-cm + namespace: ` + namespace + ` +data: + key: value +` + By("Create test ConfigMap") + Expect(kubectlSrc.ApplyYAMLSpec(configMapYAML, namespace)).NotTo(HaveOccurred()) + + secretYAML := `apiVersion: v1 +kind: Secret +metadata: + name: test-secret + namespace: ` + namespace + ` +type: Opaque +data: + password: c2VjcmV0 +` + By("Create test Secret") + Expect(kubectlSrc.ApplyYAMLSpec(secretYAML, namespace)).NotTo(HaveOccurred()) + }) + + AfterEach(func() { + By("Cleanup source and target resources") + // CleanupScenario removes the temp dir and the source/target apps + // (including the ConfigMap and Secret created in the app namespace). + if err := CleanupScenario(paths.TempDir, srcApp, tgtApp); err != nil { + log.Printf("cleanup: %v", err) + } + }) + + It("should export only the included Group/Kinds with --include-gk", Label("tier1"), func() { + var err error + paths, err = NewScenarioPaths("crane-export-gk-include-*") + Expect(err).NotTo(HaveOccurred()) + + runner := scenario.Crane + runner.WorkDir = paths.TempDir + + By("Export with --include-gk to only export Deployments and ConfigMaps") + exportOpts := ExportOptions{ + Namespace: srcApp.Namespace, + ExportDir: paths.ExportDir, + ExtraArgs: []string{"--include-gk", "Deployment", "--include-gk", "ConfigMap"}, + } + transformOpts := TransformOptions{ExportDir: paths.ExportDir, TransformDir: paths.TransformDir} + applyOpts := ApplyOptions{TransformDir: paths.TransformDir, OutputDir: paths.OutputDir} + + log.Printf("Running crane export with --include-gk Deployment,ConfigMap for namespace %s\n", srcApp.Namespace) + Expect(RunCranePipelineWithChecks(runner, exportOpts, transformOpts, applyOpts)).NotTo(HaveOccurred()) + + By("Verify Deployments and ConfigMaps were exported") + Expect(filepath.Glob(resourceGlob("Deployment"))).NotTo(BeEmpty(), "should have exported at least one Deployment") + Expect(filepath.Glob(resourceGlob("ConfigMap"))).NotTo(BeEmpty(), "should have exported at least one ConfigMap") + + By("Verify Secrets and Services were not exported") + Expect(filepath.Glob(resourceGlob("Secret"))).To(BeEmpty(), "should not export Secrets with --include-gk Deployment,ConfigMap") + Expect(filepath.Glob(resourceGlob("Service"))).To(BeEmpty(), "should not export Services with --include-gk Deployment,ConfigMap") + }) + + It("should skip the excluded Group/Kinds with --exclude-gk", Label("tier1"), func() { + var err error + paths, err = NewScenarioPaths("crane-export-gk-exclude-*") + Expect(err).NotTo(HaveOccurred()) + + runner := scenario.Crane + runner.WorkDir = paths.TempDir + + By("Export with --exclude-gk to skip Secrets") + exportOpts := ExportOptions{ + Namespace: srcApp.Namespace, + ExportDir: paths.ExportDir, + ExtraArgs: []string{"--exclude-gk", "Secret"}, + } + transformOpts := TransformOptions{ExportDir: paths.ExportDir, TransformDir: paths.TransformDir} + applyOpts := ApplyOptions{TransformDir: paths.TransformDir, OutputDir: paths.OutputDir} + + log.Printf("Running crane export with --exclude-gk Secret for namespace %s\n", srcApp.Namespace) + Expect(RunCranePipelineWithChecks(runner, exportOpts, transformOpts, applyOpts)).NotTo(HaveOccurred()) + + By("Verify Secrets were excluded") + Expect(filepath.Glob(resourceGlob("Secret"))).To(BeEmpty(), "should not export Secrets with --exclude-gk Secret") + + By("Verify other resources were still exported") + deployments, err := filepath.Glob(resourceGlob("Deployment")) + Expect(err).NotTo(HaveOccurred()) + configMaps, err := filepath.Glob(resourceGlob("ConfigMap")) + Expect(err).NotTo(HaveOccurred()) + Expect(append(deployments, configMaps...)).NotTo(BeEmpty(), "should have exported non-Secret resources") + }) +}) From 7652fc9790bc7630a0d12bd6e9872b15a6d5aadb Mon Sep 17 00:00:00 2001 From: Marek Aufart Date: Wed, 26 Aug 2026 17:21:26 +0200 Subject: [PATCH 2/2] Fix app name Signed-off-by: Marek Aufart --- e2e-tests/tests/tier1/mta_gk_filter_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-tests/tests/tier1/mta_gk_filter_test.go b/e2e-tests/tests/tier1/mta_gk_filter_test.go index f5f335f8..79241f11 100644 --- a/e2e-tests/tests/tier1/mta_gk_filter_test.go +++ b/e2e-tests/tests/tier1/mta_gk_filter_test.go @@ -15,7 +15,7 @@ import ( // Group/Kind export filter is created, to match the rest of the tier1 suite. var _ = Describe("Crane export: filter resources by Group/Kind", func() { const ( - appName = "gk-filter-test" + appName = "simple-nginx-nopv" namespace = "gk-filter-test" )