From 3bc5c87f5eb935a946cfd19a66ac8dc65edf1db2 Mon Sep 17 00:00:00 2001 From: Christoph Deppisch Date: Fri, 21 Apr 2023 11:36:30 +0200 Subject: [PATCH] chore: Add E2E test on max running builds limit --- e2e/global/builder/build_test.go | 161 +++++++++++++++++++++++++------ e2e/support/test_support.go | 31 ++++-- pkg/cmd/kit_create.go | 8 ++ 3 files changed, 165 insertions(+), 35 deletions(-) diff --git a/e2e/global/builder/build_test.go b/e2e/global/builder/build_test.go index b4eb9a5a68..b533a478a3 100644 --- a/e2e/global/builder/build_test.go +++ b/e2e/global/builder/build_test.go @@ -36,16 +36,102 @@ import ( ) type kitOptions struct { + operatorID string dependencies []string traits []string } +func TestKitMaxBuildLimit(t *testing.T) { + WithNewTestNamespace(t, func(ns string) { + createOperator(ns, "500Mi", "8m0s", "--global", "--force") + + pl := Platform(ns)() + // set maximum number of running builds + pl.Spec.Build.MaxRunningBuilds = 2 + if err := TestClient().Update(TestContext, pl); err != nil { + t.Error(err) + t.FailNow() + } + + buildA := "integration-a" + buildB := "integration-b" + buildC := "integration-c" + + doKitBuildInNamespace(buildA, ns, TestTimeoutShort, kitOptions{ + operatorID: fmt.Sprintf("camel-k-%s", ns), + dependencies: []string{ + "camel:timer", "camel:log", + }, + traits: []string{ + "builder.properties=build-property=A", + }, + }, v1.BuildPhaseRunning, v1.IntegrationKitPhaseBuildRunning) + + ns1 := NewTestNamespace(false).GetName() + defer DumpNamespace(t, ns1) + defer DeleteNamespace(t, ns1) + + pl1 := v1.NewIntegrationPlatform(ns1, fmt.Sprintf("camel-k-%s", ns)) + pl.Spec.DeepCopyInto(&pl1.Spec) + pl1.Spec.Build.Maven.Settings = v1.ValueSource{} + pl1.SetOperatorID(fmt.Sprintf("camel-k-%s", ns)) + if err := TestClient().Create(TestContext, &pl1); err != nil { + t.Error(err) + t.FailNow() + } + + doKitBuildInNamespace(buildB, ns1, TestTimeoutShort, kitOptions{ + operatorID: fmt.Sprintf("camel-k-%s", ns), + dependencies: []string{ + "camel:timer", "camel:log", + }, + traits: []string{ + "builder.properties=build-property=B", + }, + }, v1.BuildPhaseRunning, v1.IntegrationKitPhaseBuildRunning) + + ns2 := NewTestNamespace(false).GetName() + defer DumpNamespace(t, ns2) + defer DeleteNamespace(t, ns2) + + pl2 := v1.NewIntegrationPlatform(ns2, fmt.Sprintf("camel-k-%s", ns)) + pl.Spec.DeepCopyInto(&pl2.Spec) + pl2.Spec.Build.Maven.Settings = v1.ValueSource{} + pl2.SetOperatorID(fmt.Sprintf("camel-k-%s", ns)) + if err := TestClient().Create(TestContext, &pl2); err != nil { + t.Error(err) + t.FailNow() + } + + doKitBuildInNamespace(buildC, ns2, TestTimeoutShort, kitOptions{ + operatorID: fmt.Sprintf("camel-k-%s", ns), + dependencies: []string{ + "camel:timer", "camel:log", + }, + traits: []string{ + "builder.properties=build-property=C", + }, + }, v1.BuildPhaseScheduling, v1.IntegrationKitPhaseNone) + + // verify that buildC is allowed to build as soon as buildA has finished + Eventually(BuildPhase(ns, buildA), TestTimeoutLong).Should(Equal(v1.BuildPhaseSucceeded)) + Eventually(BuildPhase(ns2, buildC), TestTimeoutShort).Should(Equal(v1.BuildPhaseRunning)) + Eventually(KitPhase(ns2, buildC), TestTimeoutLong).Should(Equal(v1.IntegrationKitPhaseBuildRunning)) + + // verify that all builds are successful + Eventually(BuildPhase(ns1, buildB), TestTimeoutLong).Should(Equal(v1.BuildPhaseSucceeded)) + Eventually(KitPhase(ns1, buildB), TestTimeoutLong).Should(Equal(v1.IntegrationKitPhaseReady)) + Eventually(BuildPhase(ns2, buildC), TestTimeoutLong).Should(Equal(v1.BuildPhaseSucceeded)) + Eventually(KitPhase(ns2, buildC), TestTimeoutLong).Should(Equal(v1.IntegrationKitPhaseReady)) + }) +} + func TestKitTimerToLogFullBuild(t *testing.T) { doKitFullBuild(t, "timer-to-log", "500Mi", "8m0s", TestTimeoutLong, kitOptions{ dependencies: []string{ "camel:timer", "camel:log", }, - }) + }, v1.BuildPhaseSucceeded, v1.IntegrationKitPhaseReady) } func TestKitKnativeFullBuild(t *testing.T) { @@ -53,7 +139,7 @@ func TestKitKnativeFullBuild(t *testing.T) { dependencies: []string{ "camel-quarkus-knative", }, - }) + }, v1.BuildPhaseSucceeded, v1.IntegrationKitPhaseReady) } func TestKitTimerToLogFullNativeBuild(t *testing.T) { @@ -64,38 +150,59 @@ func TestKitTimerToLogFullNativeBuild(t *testing.T) { traits: []string{ "quarkus.package-type=native", }, - }) + }, v1.BuildPhaseSucceeded, v1.IntegrationKitPhaseReady) } func doKitFullBuild(t *testing.T, name string, memoryLimit string, buildTimeout string, testTimeout time.Duration, - options kitOptions) { + options kitOptions, buildPhase v1.BuildPhase, kitPhase v1.IntegrationKitPhase) { t.Helper() WithNewTestNamespace(t, func(ns string) { - strategy := os.Getenv("KAMEL_INSTALL_BUILD_PUBLISH_STRATEGY") - ocp, err := openshift.IsOpenShift(TestClient()) - Expect(err).To(Succeed()) - - args := []string{"--build-timeout", buildTimeout} - // TODO: configure build Pod resources if applicable - if strategy == "Spectrum" || ocp { - args = append(args, "--operator-resources", "limits.memory="+memoryLimit) - } + createOperator(ns, memoryLimit, buildTimeout) + doKitBuildInNamespace(name, ns, testTimeout, options, buildPhase, kitPhase) + }) +} - operatorID := fmt.Sprintf("camel-k-%s", ns) - Expect(KamelInstallWithID(operatorID, ns, args...).Execute()).To(Succeed()) +func createOperator(ns string, memoryLimit string, buildTimeout string, installArgs ...string) { + strategy := os.Getenv("KAMEL_INSTALL_BUILD_PUBLISH_STRATEGY") + ocp, err := openshift.IsOpenShift(TestClient()) + Expect(err).To(Succeed()) - buildKitArgs := []string{"kit", "create", name, "-n", ns} - for _, dependency := range options.dependencies { - buildKitArgs = append(buildKitArgs, "-d", dependency) - } - for _, trait := range options.traits { - buildKitArgs = append(buildKitArgs, "-t", trait) - } - Expect(Kamel(buildKitArgs...).Execute()).To(Succeed()) + args := []string{"--build-timeout", buildTimeout} + // TODO: configure build Pod resources if applicable + if strategy == "Spectrum" || ocp { + args = append(args, "--operator-resources", "limits.memory="+memoryLimit) + } - Eventually(Build(ns, name), testTimeout).ShouldNot(BeNil()) - Eventually(BuildPhase(ns, name), testTimeout).Should(Equal(v1.BuildPhaseSucceeded)) - Eventually(KitPhase(ns, name), testTimeout).Should(Equal(v1.IntegrationKitPhaseReady)) - }) + args = append(args, installArgs...) + + operatorID := fmt.Sprintf("camel-k-%s", ns) + Expect(KamelInstallWithID(operatorID, ns, args...).Execute()).To(Succeed()) +} + +func doKitBuildInNamespace(name string, ns string, testTimeout time.Duration, options kitOptions, buildPhase v1.BuildPhase, kitPhase v1.IntegrationKitPhase) { + + buildKitArgs := []string{"kit", "create", name, "-n", ns} + for _, dependency := range options.dependencies { + buildKitArgs = append(buildKitArgs, "-d", dependency) + } + for _, trait := range options.traits { + buildKitArgs = append(buildKitArgs, "-t", trait) + } + + if options.operatorID != "" { + buildKitArgs = append(buildKitArgs, "--operator-id", options.operatorID) + } else { + buildKitArgs = append(buildKitArgs, "--operator-id", fmt.Sprintf("camel-k-%s", ns)) + } + + Expect(Kamel(buildKitArgs...).Execute()).To(Succeed()) + + Eventually(Build(ns, name), testTimeout).ShouldNot(BeNil()) + if buildPhase != v1.BuildPhaseNone { + Eventually(BuildPhase(ns, name), testTimeout).Should(Equal(buildPhase)) + } + if kitPhase != v1.IntegrationKitPhaseNone { + Eventually(KitPhase(ns, name), testTimeout).Should(Equal(kitPhase)) + } } diff --git a/e2e/support/test_support.go b/e2e/support/test_support.go index 66a24ed452..e831d8384a 100644 --- a/e2e/support/test_support.go +++ b/e2e/support/test_support.go @@ -2198,7 +2198,7 @@ func Pods(ns string) func() []corev1.Pod { func WithNewTestNamespace(t *testing.T, doRun func(string)) { setTestLocus(t) - ns := newTestNamespace(false) + ns := NewTestNamespace(false) defer deleteTestNamespace(t, ns) defer userCleanup(t) @@ -2220,7 +2220,7 @@ func WithGlobalOperatorNamespace(t *testing.T, test func(string)) { func WithNewTestNamespaceWithKnativeBroker(t *testing.T, doRun func(string)) { setTestLocus(t) - ns := newTestNamespace(true) + ns := NewTestNamespace(true) defer deleteTestNamespace(t, ns) defer deleteKnativeBroker(ns) defer userCleanup(t) @@ -2248,11 +2248,7 @@ func invokeUserTestCode(t *testing.T, ns string, doRun func(string)) { globalTest := os.Getenv("CAMEL_K_FORCE_GLOBAL_TEST") == "true" defer func(isGlobal bool) { - if t.Failed() { - if err := util.Dump(TestContext, TestClient(), ns, t); err != nil { - t.Logf("Error while dumping namespace %s: %v\n", ns, err) - } - } + DumpNamespace(t, ns) // Try to clean up namespace if !isGlobal && HasPlatform(ns)() { @@ -2363,7 +2359,26 @@ func testNamespaceExists(ns string) (bool, error) { return true, nil } -func newTestNamespace(injectKnativeBroker bool) ctrl.Object { +func DumpNamespace(t *testing.T, ns string) { + if t.Failed() { + if err := util.Dump(TestContext, TestClient(), ns, t); err != nil { + t.Logf("Error while dumping namespace %s: %v\n", ns, err) + } + } +} + +func DeleteNamespace(t *testing.T, ns string) error { + nsObj, err := TestClient().CoreV1().Namespaces().Get(TestContext, ns, metav1.GetOptions{}) + if err != nil { + return err + } + + deleteTestNamespace(t, nsObj) + + return nil +} + +func NewTestNamespace(injectKnativeBroker bool) ctrl.Object { brokerLabel := "eventing.knative.dev/injection" name := os.Getenv("CAMEL_K_TEST_NS") if name == "" { diff --git a/pkg/cmd/kit_create.go b/pkg/cmd/kit_create.go index b8eca7f2d4..9e53a1648e 100644 --- a/pkg/cmd/kit_create.go +++ b/pkg/cmd/kit_create.go @@ -54,6 +54,7 @@ func newKitCreateCmd(rootCmdOptions *RootCmdOptions) (*cobra.Command, *kitCreate cmd.Flags().StringArray("configmap", nil, "Add a ConfigMap") cmd.Flags().StringArray("secret", nil, "Add a Secret") cmd.Flags().StringArray("repository", nil, "Add a maven repository") + cmd.Flags().StringP("operator-id", "x", "camel-k", "Operator id selected to manage this kit") cmd.Flags().StringArrayP("trait", "t", nil, "Configure a trait. E.g. \"-t service.enabled=false\"") // completion support @@ -71,6 +72,7 @@ type kitCreateCommandOptions struct { Configmaps []string `mapstructure:"configmaps"` Secrets []string `mapstructure:"secrets"` Repositories []string `mapstructure:"repositories"` + OperatorID string `mapstructure:"operator-id"` Traits []string `mapstructure:"traits"` } @@ -115,6 +117,12 @@ func (command *kitCreateCommandOptions) run(cmd *cobra.Command, args []string) e } kit = v1.NewIntegrationKit(command.Namespace, kubernetes.SanitizeName(args[0])) + + if command.OperatorID != "" { + // --operator-id={id} is a syntax sugar for '--annotation camel.apache.org/operator.id={id}' + kit.SetOperatorID(strings.TrimSpace(command.OperatorID)) + } + kit.Labels = map[string]string{ v1.IntegrationKitTypeLabel: v1.IntegrationKitTypeUser, }