From 820006ec8e2faae02534e3ffee2c7b315a0d071b Mon Sep 17 00:00:00 2001 From: Jordi Gil Date: Wed, 24 Jan 2024 18:54:25 -0500 Subject: [PATCH] [KOGITO-9940] Add E2E test cases for platform configured with Job Service and Data Index in a combination of scenarios with ephemeral and postgreSQL persistence in dev and production profiles (#337) --- .github/workflows/e2e.yml | 6 + controllers/platform/services/services.go | 8 +- test/e2e/helpers.go | 143 +++++++++++ test/e2e/platform_test.go | 123 ++++++++++ test/e2e/workflow_test.go | 224 +++--------------- .../dev/ephemeral/02-sonataflow_platform.yaml | 32 +++ .../services/dev/ephemeral/kustomization.yaml | 20 ++ ...3-sonataflow_callbackstatetimeouts.sw.yaml | 81 +++++++ .../services/dev/postgreSQL/01-postgres.yaml | 86 +++++++ .../postgreSQL/02-sonataflow_platform.yaml | 55 +++++ .../dev/postgreSQL/kustomization.yaml | 32 +++ ...4-sonataflow_callbackstatetimeouts.sw.yaml | 81 +++++++ .../ephemeral/02-sonataflow_platform.yaml | 33 +++ .../prod/ephemeral/kustomization.yaml | 20 ++ ...3-sonataflow_callbackstatetimeouts.sw.yaml | 81 +++++++ .../services/prod/postgreSQL/01-postgres.yaml | 86 +++++++ .../postgreSQL/02-sonataflow_platform.yaml | 55 +++++ .../prod/postgreSQL/kustomization.yaml | 32 +++ ...4-sonataflow_callbackstatetimeouts.sw.yaml | 81 +++++++ test/yaml.go | 4 + 20 files changed, 1084 insertions(+), 199 deletions(-) create mode 100644 test/e2e/helpers.go create mode 100644 test/e2e/platform_test.go create mode 100644 test/testdata/platform/services/dev/ephemeral/02-sonataflow_platform.yaml create mode 100644 test/testdata/platform/services/dev/ephemeral/kustomization.yaml create mode 100644 test/testdata/platform/services/dev/ephemeral/sonataflow/03-sonataflow_callbackstatetimeouts.sw.yaml create mode 100644 test/testdata/platform/services/dev/postgreSQL/01-postgres.yaml create mode 100644 test/testdata/platform/services/dev/postgreSQL/02-sonataflow_platform.yaml create mode 100644 test/testdata/platform/services/dev/postgreSQL/kustomization.yaml create mode 100644 test/testdata/platform/services/dev/postgreSQL/sonataflow/04-sonataflow_callbackstatetimeouts.sw.yaml create mode 100644 test/testdata/platform/services/prod/ephemeral/02-sonataflow_platform.yaml create mode 100644 test/testdata/platform/services/prod/ephemeral/kustomization.yaml create mode 100644 test/testdata/platform/services/prod/ephemeral/sonataflow/03-sonataflow_callbackstatetimeouts.sw.yaml create mode 100644 test/testdata/platform/services/prod/postgreSQL/01-postgres.yaml create mode 100644 test/testdata/platform/services/prod/postgreSQL/02-sonataflow_platform.yaml create mode 100644 test/testdata/platform/services/prod/postgreSQL/kustomization.yaml create mode 100644 test/testdata/platform/services/prod/postgreSQL/sonataflow/04-sonataflow_callbackstatetimeouts.sw.yaml diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 5b8cd0d36..26dc484e7 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -66,6 +66,12 @@ jobs: kubectl get pods -A # TODO: install the operator-sdk first, then cache the installation + + - name: Deploy operator + run: | + make deploy IMG=${{ env.OPERATOR_IMAGE_NAME }} + kubectl wait pod -A -l control-plane=controller-manager --for condition=Ready + - name: Run tests run: | make test-e2e diff --git a/controllers/platform/services/services.go b/controllers/platform/services/services.go index 1e1a94246..3637c2754 100644 --- a/controllers/platform/services/services.go +++ b/controllers/platform/services/services.go @@ -116,9 +116,13 @@ func (d DataIndexHandler) GetEnvironmentVariables() []corev1.EnvVar { func (d DataIndexHandler) GetPodResourceRequirements() corev1.ResourceRequirements { return corev1.ResourceRequirements{ - Limits: corev1.ResourceList{ + Requests: corev1.ResourceList{ corev1.ResourceCPU: resource.MustParse("100m"), - corev1.ResourceMemory: resource.MustParse("256Mi"), + corev1.ResourceMemory: resource.MustParse("1Gi"), + }, + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("200m"), + corev1.ResourceMemory: resource.MustParse("1Gi"), }, } } diff --git a/test/e2e/helpers.go b/test/e2e/helpers.go new file mode 100644 index 000000000..75b03997e --- /dev/null +++ b/test/e2e/helpers.go @@ -0,0 +1,143 @@ +// Copyright 2024 Apache Software Foundation (ASF) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package e2e + +import ( + "encoding/json" + "fmt" + "net/url" + "os" + "os/exec" + "strconv" + "strings" + + "github.com/apache/incubator-kie-kogito-serverless-operator/test" + "github.com/apache/incubator-kie-kogito-serverless-operator/test/utils" + + //nolint:golint + //nolint:revive + . "github.com/onsi/ginkgo/v2" + + //nolint:golint + //nolint:revive + . "github.com/onsi/gomega" +) + +type health struct { + Status string `json:"status"` +} + +var ( + upStatus string = "UP" +) + +func verifyHealthStatusInPod(name string, namespace string) { + // iterate over all containers to find the one that responds to the HTTP health endpoint + Expect(name).NotTo(BeEmpty(), "pod name is empty") + cmd := exec.Command("kubectl", "get", "pod", name, "-n", namespace, "-o", `jsonpath={.spec.containers[*].name}`) + output, err := utils.Run(cmd) + Expect(err).NotTo(HaveOccurred()) + var errs error + for _, cname := range strings.Split(string(output), " ") { + var h *health + h, err = getHealthStatusInContainer(name, cname, namespace) + if err == nil { + Expect(h.Status).To(Equal(upStatus)) + return + } + if len(errs.Error()) > 0 { + errs = fmt.Errorf("%v; %w", err, errs) + } else { + errs = err + } + } + Expect(errs).NotTo(HaveOccurred(), fmt.Sprintf("No container was found that could respond to the health endpoint %v", errs)) + +} + +func getHealthStatusInContainer(podName string, containerName string, ns string) (*health, error) { + h := health{} + cmd := exec.Command("kubectl", "exec", "-t", podName, "-n", ns, "-c", containerName, "--", "curl", "-s", "localhost:8080/q/health") + output, err := utils.Run(cmd) + Expect(err).NotTo(HaveOccurred()) + err = json.Unmarshal(output, &h) + if err != nil { + return nil, fmt.Errorf("failed to execute curl command against health endpoint in container %s:%v with output %s", containerName, err, output) + } + return &h, nil +} +func verifyWorkflowIsInRunningStateInNamespace(workflowName string, ns string) bool { + cmd := exec.Command("kubectl", "get", "workflow", workflowName, "-n", ns, "-o", "jsonpath={.status.conditions[?(@.type=='Running')].status}") + response, err := utils.Run(cmd) + if err != nil { + GinkgoWriter.Println(fmt.Errorf("failed to check if greeting workflow is running: %v", err)) + return false + } + GinkgoWriter.Println(fmt.Sprintf("Got response %s", response)) + + if len(strings.TrimSpace(string(response))) == 0 { + GinkgoWriter.Println(fmt.Errorf("empty response %v", err)) + return false + } + status, err := strconv.ParseBool(string(response)) + if err != nil { + GinkgoWriter.Println(fmt.Errorf("failed to parse result %v", err)) + return false + } + return status +} + +func verifyWorkflowIsInRunningState(workflowName string, targetNamespace string) bool { + return verifyWorkflowIsInRunningStateInNamespace(workflowName, targetNamespace) +} + +func verifyWorkflowIsAddressable(workflowName string, targetNamespace string) bool { + cmd := exec.Command("kubectl", "get", "workflow", workflowName, "-n", targetNamespace, "-o", "jsonpath={.status.address.url}") + if response, err := utils.Run(cmd); err != nil { + GinkgoWriter.Println(fmt.Errorf("failed to check if greeting workflow is running: %v", err)) + return false + } else { + GinkgoWriter.Println(fmt.Sprintf("Got response %s", response)) + if len(strings.TrimSpace(string(response))) > 0 { + _, err := url.ParseRequestURI(string(response)) + if err != nil { + GinkgoWriter.Println(fmt.Errorf("failed to parse result %v", err)) + return false + } + // The response is a valid URL so the test is passed + return true + } + return false + } +} + +const ( + minikubePlatform = "minikube" + openshiftPlatform = "openshift" +) + +func getSonataFlowPlatformFilename() string { + if getClusterPlatform() == openshiftPlatform { + return test.GetPlatformOpenshiftE2eTest() + } + return test.GetPlatformMinikubeE2eTest() +} + +func getClusterPlatform() string { + if v, ok := os.LookupEnv("CLUSTER_PLATFORM"); ok { + return v + } + return minikubePlatform +} diff --git a/test/e2e/platform_test.go b/test/e2e/platform_test.go new file mode 100644 index 000000000..e9b8edf13 --- /dev/null +++ b/test/e2e/platform_test.go @@ -0,0 +1,123 @@ +// Copyright 2024 Apache Software Foundation (ASF) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package e2e + +import ( + //nolint:golint + //nolint:revive + "bytes" + "fmt" + "math/rand" + "os/exec" + "path/filepath" + "strings" + "time" + + "github.com/apache/incubator-kie-kogito-serverless-operator/test" + "github.com/apache/incubator-kie-kogito-serverless-operator/test/utils" + . "github.com/onsi/ginkgo/v2" + + //nolint:golint + //nolint:revive + . "github.com/onsi/gomega" +) + +const ( + ephemeral = "ephemeral" + postgreSQL = "postgreSQL" + dev = "dev" + production = "prod" +) + +var _ = Describe("Validate the persistence", Ordered, func() { + + var ( + projectDir string + targetNamespace string + ) + + BeforeEach(func() { + targetNamespace = fmt.Sprintf("test-%d", rand.Intn(1024)+1) + cmd := exec.Command("kubectl", "create", "namespace", targetNamespace) + _, err := utils.Run(cmd) + Expect(err).NotTo(HaveOccurred()) + }) + AfterEach(func() { + // Remove resources in test namespace with no failure + if !CurrentSpecReport().Failed() && len(targetNamespace) > 0 { + cmd := exec.Command("kubectl", "delete", "namespace", targetNamespace, "--wait") + _, err := utils.Run(cmd) + Expect(err).NotTo(HaveOccurred()) + } + }) + var _ = Context("with platform services", func() { + + DescribeTable("when creating a simple workflow", func(testcaseDir string, profile string, persistenceType string) { + By("Deploy the SonataFlowPlatform CR") + var manifests []byte + EventuallyWithOffset(1, func() error { + var err error + cmd := exec.Command("kubectl", "kustomize", filepath.Join(projectDir, + testcaseDir, profile, persistenceType)) + manifests, err = utils.Run(cmd) + return err + }, time.Minute, time.Second).Should(Succeed()) + cmd := exec.Command("kubectl", "create", "-n", targetNamespace, "-f", "-") + cmd.Stdin = bytes.NewBuffer(manifests) + _, err := utils.Run(cmd) + Expect(err).NotTo(HaveOccurred()) + By("Wait for SonatatFlowPlatform CR to complete deployment") + // wait for service deployments to be ready + EventuallyWithOffset(1, func() error { + cmd = exec.Command("kubectl", "wait", "pod", "-n", targetNamespace, "-l", "app=sonataflow-platform", "--for", "condition=Ready", "--timeout=5s") + _, err = utils.Run(cmd) + return err + }, 10*time.Minute, 5).Should(Succeed()) + By("Evaluate status of service's health endpoint") + cmd = exec.Command("kubectl", "get", "pod", "-l", "app=sonataflow-platform", "-n", targetNamespace, "-ojsonpath={.items[*].metadata.name}") + output, err := utils.Run(cmd) + Expect(err).NotTo(HaveOccurred()) + // remove the last CR that is added by default as the last character of the string. + for _, pn := range strings.Split(string(output), " ") { + verifyHealthStatusInPod(pn, targetNamespace) + } + By("Deploy the SonataFlow CR") + cmd = exec.Command("kubectl", "create", "-n", targetNamespace, "-f", filepath.Join(projectDir, + testcaseDir, profile, persistenceType, "sonataflow")) + manifests, err = utils.Run(cmd) + Expect(err).NotTo(HaveOccurred()) + + By("Retrieve SonataFlow CR name") + cmd = exec.Command("kubectl", "get", "sonataflow", "-n", targetNamespace, `-ojsonpath={.items[*].metadata.name}`) + output, err = utils.Run(cmd) + Expect(err).NotTo(HaveOccurred()) + sfNames := strings.TrimRight(string(output), " ") + + By("Evaluate status of SonataFlow CR") + for _, sf := range strings.Split(string(sfNames), " ") { + Expect(sf).NotTo(BeEmpty(), "sonataflow name is empty") + EventuallyWithOffset(1, func() bool { + return verifyWorkflowIsInRunningStateInNamespace(sf, targetNamespace) + }, 5*time.Minute, 5).Should(BeTrue()) + } + }, + Entry("with both Job Service and Data Index and ephemeral persistence and the workflow in a dev profile", test.GetSonataFlowE2EPlatformServicesDirectory(), dev, ephemeral), + Entry("with both Job Service and Data Index and ephemeral persistence and the workflow in a production profile", test.GetSonataFlowE2EPlatformServicesDirectory(), production, ephemeral), + Entry("with both Job Service and Data Index and postgreSQL persistence and the workflow in a dev profile", test.GetSonataFlowE2EPlatformServicesDirectory(), dev, postgreSQL), + Entry("with both Job Service and Data Index and postgreSQL persistence and the workflow in a production profile", test.GetSonataFlowE2EPlatformServicesDirectory(), production, postgreSQL), + ) + + }) +}) diff --git a/test/e2e/workflow_test.go b/test/e2e/workflow_test.go index a43caedef..b84282e36 100644 --- a/test/e2e/workflow_test.go +++ b/test/e2e/workflow_test.go @@ -21,12 +21,9 @@ package e2e import ( "fmt" - "net/url" - "os" + "math/rand" "os/exec" "path/filepath" - "strconv" - "strings" "time" "github.com/apache/incubator-kie-kogito-serverless-operator/test" @@ -41,136 +38,22 @@ import ( . "github.com/onsi/gomega" ) -// namespace store the ns where the Operator and Operand will be executed -const namespace = "sonataflow-operator-system" +var _ = Describe("SonataFlow Operator", func() { -const ( - minikubePlatform = "minikube" - openshiftPlatform = "openshift" -) - -var _ = Describe("SonataFlow Operator", Ordered, func() { - - BeforeAll(func() { - - // Now, let's ensure that all namespaces can raise a Warn when we apply the manifests - // and that the namespace where the Operator and Operand will run are enforced as - // restricted so that we can ensure that both can be admitted and run with the enforcement - - // See: https://kubernetes.io/docs/tutorials/security/seccomp/ - - /* - TODO: Uncomment to enable when https://issues.redhat.com/browse/KOGITO-9110 will be available - By("labeling all namespaces to warn when we apply the manifest if would violate the PodStandards") - cmd = exec.Command("kubectl", "label", "--overwrite", "ns", "--all", - "pod-security.kubernetes.io/audit=restricted", - "pod-security.kubernetes.io/enforce-version=v1.22", - "pod-security.kubernetes.io/warn=restricted") - _, err := utils.Run(cmd) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - - By("labeling enforce the namespace where the Operator and Operand(s) will run") - cmd = exec.Command("kubectl", "label", "--overwrite", "ns", namespace, - "pod-security.kubernetes.io/audit=restricted", - "pod-security.kubernetes.io/enforce-version=v1.22", - "pod-security.kubernetes.io/enforce=restricted") - _, err = utils.Run(cmd) - Expect(err).To(Not(HaveOccurred())) - - */ - - var controllerPodName string - operatorImageName, err := utils.GetOperatorImageName() - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - - By("deploying the controller-manager") - cmd := exec.Command("make", "deploy", fmt.Sprintf("IMG=%s", operatorImageName)) - - outputMake, err := utils.Run(cmd) - fmt.Println(string(outputMake)) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - - /* // TODO: Uncomment to enable when https://issues.redhat.com/browse/KOGITO-9110 will be available - - By("validating that manager Pod/container(s) are restricted") - // Get Podsecurity violation lines - lines, err := utils.StringToLines(string(outputMake)) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - var violationLines []string - applySeccompProfilePatch := false - for _, line := range lines { - if strings.Contains(line, "Warning: would violate PodSecurity") { - if strings.Contains(line, "must set securityContext.seccompProfile.type to") { - // Ignore this violation as it is expected - applySeccompProfilePatch = true - } else { - violationLines = append(violationLines, line) - } - } - } - Expect(violationLines).To(BeEmpty()) - - if applySeccompProfilePatch { - By("Applying seccompProfile") - cmd = exec.Command("kubectl", "patch", "deployment", "sonataflow-operator-controller-manager", "-p", `{"spec":{"template":{"spec":{"securityContext":{"seccompProfile":{"type":"RuntimeDefault"}}}}}}`, "-n", namespace) + var targetNamespace string + BeforeEach(func() { + targetNamespace = fmt.Sprintf("test-%d", rand.Intn(1024)+1) + cmd := exec.Command("kubectl", "create", "namespace", targetNamespace) + _, err := utils.Run(cmd) + Expect(err).NotTo(HaveOccurred()) + }) + AfterEach(func() { + // Remove resources in test namespace + if !CurrentGinkgoTestDescription().Failed && len(targetNamespace) > 0 { + cmd := exec.Command("kubectl", "delete", "namespace", targetNamespace, "--wait") _, err := utils.Run(cmd) - if utils.IsDebugEnabled() { - err = utils.OutputDeployment(namespace, "sonataflow-operator-controller-manager") - } - ExpectWithOffset(1, err).NotTo(HaveOccurred()) + Expect(err).NotTo(HaveOccurred()) } - */ - - By("validating that the controller-manager pod is running as expected") - verifyControllerUp := func() error { - var podOutput []byte - var err error - - if utils.IsDebugEnabled() { - err = utils.OutputAllPods() - err = utils.OutputAllEvents(namespace) - } - - // Get pod name - cmd = exec.Command("kubectl", "get", - "pods", "-l", "control-plane=controller-manager", - "-o", "go-template={{ range .items }}{{ if not .metadata.deletionTimestamp }}{{ .metadata.name }}"+ - "{{ \"\\n\" }}{{ end }}{{ end }}", - "-n", namespace, - ) - podOutput, err = utils.Run(cmd) - fmt.Println(string(podOutput)) - ExpectWithOffset(2, err).NotTo(HaveOccurred()) - podNames := utils.GetNonEmptyLines(string(podOutput)) - if len(podNames) != 1 { - return fmt.Errorf("expect 1 controller pods running, but got %d", len(podNames)) - } - controllerPodName = podNames[0] - ExpectWithOffset(2, controllerPodName).Should(ContainSubstring("controller-manager")) - - // Validate pod status - cmd = exec.Command("kubectl", "get", - "pods", controllerPodName, "-o", "jsonpath={.status.phase}", - "-n", namespace, - ) - status, err := utils.Run(cmd) - fmt.Println(string(status)) - ExpectWithOffset(2, err).NotTo(HaveOccurred()) - if string(status) != "Running" { - return fmt.Errorf("controller pod in %s status", status) - } - return nil - } - EventuallyWithOffset(1, verifyControllerUp, 2*time.Minute, time.Second).Should(Succeed()) - }) - - AfterAll(func() { - By("removing manager namespace") - cmd := exec.Command("make", "undeploy") - _, _ = utils.Run(cmd) - By("uninstalling CRDs") - cmd = exec.Command("make", "uninstall") - _, _ = utils.Run(cmd) }) Describe("ensure that Operator and Operand(s) can run in restricted namespaces", func() { @@ -180,17 +63,17 @@ var _ = Describe("SonataFlow Operator", Ordered, func() { By("creating an instance of the SonataFlow Operand(CR)") EventuallyWithOffset(1, func() error { cmd := exec.Command("kubectl", "apply", "-f", filepath.Join(projectDir, - "test/testdata/"+test.SonataFlowSimpleOpsYamlCR), "-n", namespace) + "test/testdata/"+test.SonataFlowSimpleOpsYamlCR), "-n", targetNamespace) _, err := utils.Run(cmd) return err }, 2*time.Minute, time.Second).Should(Succeed()) By("check the workflow is in running state") - EventuallyWithOffset(1, func() bool { return verifyWorkflowIsInRunningState("simple") }, 15*time.Minute, 30*time.Second).Should(BeTrue()) + EventuallyWithOffset(1, func() bool { return verifyWorkflowIsInRunningState("simple", targetNamespace) }, 15*time.Minute, 30*time.Second).Should(BeTrue()) EventuallyWithOffset(1, func() error { cmd := exec.Command("kubectl", "delete", "-f", filepath.Join(projectDir, - "test/testdata/"+test.SonataFlowSimpleOpsYamlCR), "-n", namespace) + "test/testdata/"+test.SonataFlowSimpleOpsYamlCR), "-n", targetNamespace) _, err := utils.Run(cmd) return err }, 2*time.Minute, time.Second).Should(Succeed()) @@ -200,7 +83,7 @@ var _ = Describe("SonataFlow Operator", Ordered, func() { By("creating external resources DataInputSchema configMap") EventuallyWithOffset(1, func() error { cmd := exec.Command("kubectl", "apply", "-f", filepath.Join(projectDir, - "test/testdata/"+test.SonataFlowGreetingsDataInputSchemaConfig), "-n", namespace) + "test/testdata/"+test.SonataFlowGreetingsDataInputSchemaConfig), "-n", targetNamespace) _, err := utils.Run(cmd) return err }, 2*time.Minute, time.Second).Should(Succeed()) @@ -208,17 +91,17 @@ var _ = Describe("SonataFlow Operator", Ordered, func() { By("creating an instance of the SonataFlow Operand(CR)") EventuallyWithOffset(1, func() error { cmd := exec.Command("kubectl", "apply", "-f", filepath.Join(projectDir, - "test/testdata/"+test.SonataFlowGreetingsWithDataInputSchemaCR), "-n", namespace) + "test/testdata/"+test.SonataFlowGreetingsWithDataInputSchemaCR), "-n", targetNamespace) _, err := utils.Run(cmd) return err }, 2*time.Minute, time.Second).Should(Succeed()) By("check the workflow is in running state") - EventuallyWithOffset(1, func() bool { return verifyWorkflowIsInRunningState("greeting") }, 15*time.Minute, 30*time.Second).Should(BeTrue()) + EventuallyWithOffset(1, func() bool { return verifyWorkflowIsInRunningState("greeting", targetNamespace) }, 15*time.Minute, 30*time.Second).Should(BeTrue()) EventuallyWithOffset(1, func() error { cmd := exec.Command("kubectl", "delete", "-f", filepath.Join(projectDir, - "test/testdata/"+test.SonataFlowGreetingsWithDataInputSchemaCR), "-n", namespace) + "test/testdata/"+test.SonataFlowGreetingsWithDataInputSchemaCR), "-n", targetNamespace) _, err := utils.Run(cmd) return err }, 2*time.Minute, time.Second).Should(Succeed()) @@ -229,82 +112,29 @@ var _ = Describe("SonataFlow Operator", Ordered, func() { By("creating an instance of the SonataFlow Workflow in DevMode") EventuallyWithOffset(1, func() error { cmd := exec.Command("kubectl", "apply", "-f", filepath.Join(projectDir, - test.GetSonataFlowE2eOrderProcessingFolder()), "-n", namespace) + test.GetSonataFlowE2eOrderProcessingFolder()), "-n", targetNamespace) _, err := utils.Run(cmd) return err }, 2*time.Minute, time.Second).Should(Succeed()) By("check the workflow is in running state") - EventuallyWithOffset(1, func() bool { return verifyWorkflowIsInRunningState("orderprocessing") }, 10*time.Minute, 30*time.Second).Should(BeTrue()) + EventuallyWithOffset(1, func() bool { return verifyWorkflowIsInRunningState("orderprocessing", targetNamespace) }, 10*time.Minute, 30*time.Second).Should(BeTrue()) - cmdLog := exec.Command("kubectl", "logs", "orderprocessing", "-n", namespace) + cmdLog := exec.Command("kubectl", "logs", "orderprocessing", "-n", targetNamespace) if responseLog, errLog := utils.Run(cmdLog); errLog == nil { GinkgoWriter.Println(fmt.Sprintf("devmode podlog %s", responseLog)) } By("check that the workflow is addressable") - EventuallyWithOffset(1, func() bool { return verifyWorkflowIsAddressable("orderprocessing") }, 10*time.Minute, 30*time.Second).Should(BeTrue()) + EventuallyWithOffset(1, func() bool { return verifyWorkflowIsAddressable("orderprocessing", targetNamespace) }, 10*time.Minute, 30*time.Second).Should(BeTrue()) EventuallyWithOffset(1, func() error { cmd := exec.Command("kubectl", "delete", "-f", filepath.Join(projectDir, - test.GetSonataFlowE2eOrderProcessingFolder()), "-n", namespace) + test.GetSonataFlowE2eOrderProcessingFolder()), "-n", targetNamespace) _, err := utils.Run(cmd) return err }, 2*time.Minute, time.Second).Should(Succeed()) }) }) -}) -func verifyWorkflowIsInRunningState(workflowName string) bool { - cmd := exec.Command("kubectl", "get", "workflow", workflowName, "-n", namespace, "-o", "jsonpath={.status.conditions[?(@.type=='Running')].status}") - if response, err := utils.Run(cmd); err != nil { - GinkgoWriter.Println(fmt.Errorf("failed to check if greeting workflow is running: %v", err)) - return false - } else { - GinkgoWriter.Println(fmt.Sprintf("Got response %s", response)) - - if len(strings.TrimSpace(string(response))) > 0 { - status, err := strconv.ParseBool(string(response)) - if err != nil { - GinkgoWriter.Println(fmt.Errorf("failed to parse result %v", err)) - return false - } - return status - } - return false - } -} - -func verifyWorkflowIsAddressable(workflowName string) bool { - cmd := exec.Command("kubectl", "get", "workflow", workflowName, "-n", namespace, "-o", "jsonpath={.status.address.url}") - if response, err := utils.Run(cmd); err != nil { - GinkgoWriter.Println(fmt.Errorf("failed to check if greeting workflow is running: %v", err)) - return false - } else { - GinkgoWriter.Println(fmt.Sprintf("Got response %s", response)) - if len(strings.TrimSpace(string(response))) > 0 { - _, err := url.ParseRequestURI(string(response)) - if err != nil { - GinkgoWriter.Println(fmt.Errorf("failed to parse result %v", err)) - return false - } - // The response is a valid URL so the test is passed - return true - } - return false - } -} - -func getSonataFlowPlatformFilename() string { - if getClusterPlatform() == openshiftPlatform { - return test.GetPlatformOpenshiftE2eTest() - } - return test.GetPlatformMinikubeE2eTest() -} - -func getClusterPlatform() string { - if v, ok := os.LookupEnv("CLUSTER_PLATFORM"); ok { - return v - } - return minikubePlatform -} +}) diff --git a/test/testdata/platform/services/dev/ephemeral/02-sonataflow_platform.yaml b/test/testdata/platform/services/dev/ephemeral/02-sonataflow_platform.yaml new file mode 100644 index 000000000..73d495624 --- /dev/null +++ b/test/testdata/platform/services/dev/ephemeral/02-sonataflow_platform.yaml @@ -0,0 +1,32 @@ +# Copyright 2024 Apache Software Foundation (ASF) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: sonataflow.org/v1alpha08 +kind: SonataFlowPlatform +metadata: + name: sonataflow-platform +spec: + build: + template: + buildArgs: + - name: QUARKUS_EXTENSION + value: org.kie.kogito:kogito-addons-quarkus-jobs-knative-eventing:999-SNAPSHOT + config: + strategyOptions: + KanikoBuildCacheEnabled: "true" + services: + dataIndex: + enabled: false + jobService: + enabled: false diff --git a/test/testdata/platform/services/dev/ephemeral/kustomization.yaml b/test/testdata/platform/services/dev/ephemeral/kustomization.yaml new file mode 100644 index 000000000..5441bfce8 --- /dev/null +++ b/test/testdata/platform/services/dev/ephemeral/kustomization.yaml @@ -0,0 +1,20 @@ +# Copyright 2024 Apache Software Foundation (ASF) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +resources: +- 02-sonataflow_platform.yaml + +sortOptions: + order: fifo + diff --git a/test/testdata/platform/services/dev/ephemeral/sonataflow/03-sonataflow_callbackstatetimeouts.sw.yaml b/test/testdata/platform/services/dev/ephemeral/sonataflow/03-sonataflow_callbackstatetimeouts.sw.yaml new file mode 100644 index 000000000..8bc8a77de --- /dev/null +++ b/test/testdata/platform/services/dev/ephemeral/sonataflow/03-sonataflow_callbackstatetimeouts.sw.yaml @@ -0,0 +1,81 @@ +# Copyright 2024 Apache Software Foundation (ASF) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: sonataflow.org/v1alpha08 +kind: SonataFlow +metadata: + name: callbackstatetimeouts + annotations: + sonataflow.org/description: Callback State Timeouts Example k8s + sonataflow.org/version: 0.0.1 + sonataflow.org/profile: dev +spec: + flow: + start: PrintStartMessage + events: + - name: callbackEvent + source: '' + type: callback_event_type + functions: + - name: systemOut + type: custom + operation: sysout + states: + - name: PrintStartMessage + type: operation + actions: + - name: printSystemOut + functionRef: + refName: systemOut + arguments: + message: "${\"callback-state-timeouts: \" + $WORKFLOW.instanceId + \" has started.\"}" + transition: CallbackState + - name: CallbackState + type: callback + action: + name: callbackAction + functionRef: + refName: systemOut + arguments: + message: "${\"callback-state-timeouts: \" + $WORKFLOW.instanceId + \" has executed the callbackFunction.\"}" + eventRef: callbackEvent + transition: CheckEventArrival + timeouts: + eventTimeout: PT30S + - name: CheckEventArrival + type: switch + dataConditions: + - condition: "${ .eventData != null }" + transition: EventArrived + defaultCondition: + transition: EventNotArrived + - name: EventArrived + type: inject + data: + exitMessage: "The callback event has arrived." + transition: PrintExitMessage + - name: EventNotArrived + type: inject + data: + exitMessage: "The callback event has not arrived, and the timeout has overdue." + transition: PrintExitMessage + - name: PrintExitMessage + type: operation + actions: + - name: printSystemOut + functionRef: + refName: systemOut + arguments: + message: "${\"callback-state-timeouts: \" + $WORKFLOW.instanceId + \" has finalized. \" + .exitMessage + \" eventData: \" + .eventData}" + end: true diff --git a/test/testdata/platform/services/dev/postgreSQL/01-postgres.yaml b/test/testdata/platform/services/dev/postgreSQL/01-postgres.yaml new file mode 100644 index 000000000..662de4c7b --- /dev/null +++ b/test/testdata/platform/services/dev/postgreSQL/01-postgres.yaml @@ -0,0 +1,86 @@ +# Copyright 2024 Apache Software Foundation (ASF) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + labels: + app.kubernetes.io/name: postgres + name: postgres-pvc +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app.kubernetes.io/name: postgres + name: postgres +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: postgres + template: + metadata: + labels: + app.kubernetes.io/name: postgres + spec: + containers: + - name: postgres + image: postgres:13.2-alpine + imagePullPolicy: 'IfNotPresent' + ports: + - containerPort: 5432 + volumeMounts: + - name: storage + mountPath: /var/lib/postgresql/data + envFrom: + - secretRef: + name: postgres-secrets + readinessProbe: + exec: + command: ["pg_isready"] + initialDelaySeconds: 15 + timeoutSeconds: 2 + livenessProbe: + exec: + command: ["pg_isready"] + initialDelaySeconds: 15 + timeoutSeconds: 2 + resources: + limits: + memory: "256Mi" + cpu: "500m" + volumes: + - name: storage + persistentVolumeClaim: + claimName: postgres-pvc +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/name: postgres + name: postgres +spec: + selector: + app.kubernetes.io/name: postgres + ports: + - port: 5432 diff --git a/test/testdata/platform/services/dev/postgreSQL/02-sonataflow_platform.yaml b/test/testdata/platform/services/dev/postgreSQL/02-sonataflow_platform.yaml new file mode 100644 index 000000000..15fd97df9 --- /dev/null +++ b/test/testdata/platform/services/dev/postgreSQL/02-sonataflow_platform.yaml @@ -0,0 +1,55 @@ +# Copyright 2024 Apache Software Foundation (ASF) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: sonataflow.org/v1alpha08 +kind: SonataFlowPlatform +metadata: + name: sonataflow-platform +spec: + build: + template: + buildArgs: + - name: QUARKUS_EXTENSIONS + value: org.kie.kogito:kogito-addons-quarkus-jobs-knative-eventing:999-SNAPSHOT + services: + dataIndex: + enabled: false + persistence: + postgresql: + jdbcUrl: jdbc:postgresql://postgres:5432/sonataflow?currentSchema=data-index-service + secretRef: + name: postgres-secrets + userKey: POSTGRES_USER + passwordKey: POSTGRES_PASSWORD + podTemplate: + initContainers: + - name: init-postgres + image: registry.access.redhat.com/ubi9/ubi-minimal:latest + imagePullPolicy: IfNotPresent + command: [ 'sh', '-c', 'until (echo 1 > /dev/tcp/postgres.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local/5432) >/dev/null 2>&1; do echo "Waiting for postgres server"; sleep 3; done;' ] + jobService: + enabled: false + persistence: + postgresql: + jdbcUrl: jdbc:postgresql://postgres:5432/sonataflow?currentSchema=jobs-service + secretRef: + name: postgres-secrets + userKey: POSTGRES_USER + passwordKey: POSTGRES_PASSWORD + podTemplate: + initContainers: + - name: init-postgres + image: registry.access.redhat.com/ubi9/ubi-minimal:latest + imagePullPolicy: IfNotPresent + command: [ 'sh', '-c', 'until (echo 1 > /dev/tcp/postgres.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local/5432) >/dev/null 2>&1; do echo "Waiting for postgres server"; sleep 3; done;' ] diff --git a/test/testdata/platform/services/dev/postgreSQL/kustomization.yaml b/test/testdata/platform/services/dev/postgreSQL/kustomization.yaml new file mode 100644 index 000000000..d3fd127c7 --- /dev/null +++ b/test/testdata/platform/services/dev/postgreSQL/kustomization.yaml @@ -0,0 +1,32 @@ +# Copyright 2024 Apache Software Foundation (ASF) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +resources: +- 01-postgres.yaml +- 02-sonataflow_platform.yaml + +generatorOptions: + disableNameSuffixHash: true + +secretGenerator: + - name: postgres-secrets + literals: + - POSTGRES_USER=sonataflow + - POSTGRES_PASSWORD=sonataflow + - POSTGRES_DATABASE=sonataflow + - PGDATA=/var/lib/pgsql/data/userdata + +sortOptions: + order: fifo + diff --git a/test/testdata/platform/services/dev/postgreSQL/sonataflow/04-sonataflow_callbackstatetimeouts.sw.yaml b/test/testdata/platform/services/dev/postgreSQL/sonataflow/04-sonataflow_callbackstatetimeouts.sw.yaml new file mode 100644 index 000000000..8bc8a77de --- /dev/null +++ b/test/testdata/platform/services/dev/postgreSQL/sonataflow/04-sonataflow_callbackstatetimeouts.sw.yaml @@ -0,0 +1,81 @@ +# Copyright 2024 Apache Software Foundation (ASF) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: sonataflow.org/v1alpha08 +kind: SonataFlow +metadata: + name: callbackstatetimeouts + annotations: + sonataflow.org/description: Callback State Timeouts Example k8s + sonataflow.org/version: 0.0.1 + sonataflow.org/profile: dev +spec: + flow: + start: PrintStartMessage + events: + - name: callbackEvent + source: '' + type: callback_event_type + functions: + - name: systemOut + type: custom + operation: sysout + states: + - name: PrintStartMessage + type: operation + actions: + - name: printSystemOut + functionRef: + refName: systemOut + arguments: + message: "${\"callback-state-timeouts: \" + $WORKFLOW.instanceId + \" has started.\"}" + transition: CallbackState + - name: CallbackState + type: callback + action: + name: callbackAction + functionRef: + refName: systemOut + arguments: + message: "${\"callback-state-timeouts: \" + $WORKFLOW.instanceId + \" has executed the callbackFunction.\"}" + eventRef: callbackEvent + transition: CheckEventArrival + timeouts: + eventTimeout: PT30S + - name: CheckEventArrival + type: switch + dataConditions: + - condition: "${ .eventData != null }" + transition: EventArrived + defaultCondition: + transition: EventNotArrived + - name: EventArrived + type: inject + data: + exitMessage: "The callback event has arrived." + transition: PrintExitMessage + - name: EventNotArrived + type: inject + data: + exitMessage: "The callback event has not arrived, and the timeout has overdue." + transition: PrintExitMessage + - name: PrintExitMessage + type: operation + actions: + - name: printSystemOut + functionRef: + refName: systemOut + arguments: + message: "${\"callback-state-timeouts: \" + $WORKFLOW.instanceId + \" has finalized. \" + .exitMessage + \" eventData: \" + .eventData}" + end: true diff --git a/test/testdata/platform/services/prod/ephemeral/02-sonataflow_platform.yaml b/test/testdata/platform/services/prod/ephemeral/02-sonataflow_platform.yaml new file mode 100644 index 000000000..8f77082bc --- /dev/null +++ b/test/testdata/platform/services/prod/ephemeral/02-sonataflow_platform.yaml @@ -0,0 +1,33 @@ +# Copyright 2024 Apache Software Foundation (ASF) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: sonataflow.org/v1alpha08 +kind: SonataFlowPlatform +metadata: + name: sonataflow-platform +spec: + build: + template: + buildArgs: + - name: QUARKUS_EXTENSION + value: org.kie.kogito:kogito-addons-quarkus-jobs-knative-eventing:999-SNAPSHOT + config: + strategyOptions: + KanikoBuildCacheEnabled: "true" + services: + dataIndex: + enabled: true + jobService: + enabled: true + diff --git a/test/testdata/platform/services/prod/ephemeral/kustomization.yaml b/test/testdata/platform/services/prod/ephemeral/kustomization.yaml new file mode 100644 index 000000000..5441bfce8 --- /dev/null +++ b/test/testdata/platform/services/prod/ephemeral/kustomization.yaml @@ -0,0 +1,20 @@ +# Copyright 2024 Apache Software Foundation (ASF) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +resources: +- 02-sonataflow_platform.yaml + +sortOptions: + order: fifo + diff --git a/test/testdata/platform/services/prod/ephemeral/sonataflow/03-sonataflow_callbackstatetimeouts.sw.yaml b/test/testdata/platform/services/prod/ephemeral/sonataflow/03-sonataflow_callbackstatetimeouts.sw.yaml new file mode 100644 index 000000000..249ee2c12 --- /dev/null +++ b/test/testdata/platform/services/prod/ephemeral/sonataflow/03-sonataflow_callbackstatetimeouts.sw.yaml @@ -0,0 +1,81 @@ +# Copyright 2024 Apache Software Foundation (ASF) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: sonataflow.org/v1alpha08 +kind: SonataFlow +metadata: + name: callbackstatetimeouts + annotations: + sonataflow.org/description: Callback State Timeouts Example k8s + sonataflow.org/version: 0.0.1 + sonataflow.org/profile: prod +spec: + flow: + start: PrintStartMessage + events: + - name: callbackEvent + source: '' + type: callback_event_type + functions: + - name: systemOut + type: custom + operation: sysout + states: + - name: PrintStartMessage + type: operation + actions: + - name: printSystemOut + functionRef: + refName: systemOut + arguments: + message: "${\"callback-state-timeouts: \" + $WORKFLOW.instanceId + \" has started.\"}" + transition: CallbackState + - name: CallbackState + type: callback + action: + name: callbackAction + functionRef: + refName: systemOut + arguments: + message: "${\"callback-state-timeouts: \" + $WORKFLOW.instanceId + \" has executed the callbackFunction.\"}" + eventRef: callbackEvent + transition: CheckEventArrival + timeouts: + eventTimeout: PT30S + - name: CheckEventArrival + type: switch + dataConditions: + - condition: "${ .eventData != null }" + transition: EventArrived + defaultCondition: + transition: EventNotArrived + - name: EventArrived + type: inject + data: + exitMessage: "The callback event has arrived." + transition: PrintExitMessage + - name: EventNotArrived + type: inject + data: + exitMessage: "The callback event has not arrived, and the timeout has overdue." + transition: PrintExitMessage + - name: PrintExitMessage + type: operation + actions: + - name: printSystemOut + functionRef: + refName: systemOut + arguments: + message: "${\"callback-state-timeouts: \" + $WORKFLOW.instanceId + \" has finalized. \" + .exitMessage + \" eventData: \" + .eventData}" + end: true diff --git a/test/testdata/platform/services/prod/postgreSQL/01-postgres.yaml b/test/testdata/platform/services/prod/postgreSQL/01-postgres.yaml new file mode 100644 index 000000000..662de4c7b --- /dev/null +++ b/test/testdata/platform/services/prod/postgreSQL/01-postgres.yaml @@ -0,0 +1,86 @@ +# Copyright 2024 Apache Software Foundation (ASF) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + labels: + app.kubernetes.io/name: postgres + name: postgres-pvc +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app.kubernetes.io/name: postgres + name: postgres +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: postgres + template: + metadata: + labels: + app.kubernetes.io/name: postgres + spec: + containers: + - name: postgres + image: postgres:13.2-alpine + imagePullPolicy: 'IfNotPresent' + ports: + - containerPort: 5432 + volumeMounts: + - name: storage + mountPath: /var/lib/postgresql/data + envFrom: + - secretRef: + name: postgres-secrets + readinessProbe: + exec: + command: ["pg_isready"] + initialDelaySeconds: 15 + timeoutSeconds: 2 + livenessProbe: + exec: + command: ["pg_isready"] + initialDelaySeconds: 15 + timeoutSeconds: 2 + resources: + limits: + memory: "256Mi" + cpu: "500m" + volumes: + - name: storage + persistentVolumeClaim: + claimName: postgres-pvc +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/name: postgres + name: postgres +spec: + selector: + app.kubernetes.io/name: postgres + ports: + - port: 5432 diff --git a/test/testdata/platform/services/prod/postgreSQL/02-sonataflow_platform.yaml b/test/testdata/platform/services/prod/postgreSQL/02-sonataflow_platform.yaml new file mode 100644 index 000000000..75acb6d7d --- /dev/null +++ b/test/testdata/platform/services/prod/postgreSQL/02-sonataflow_platform.yaml @@ -0,0 +1,55 @@ +# Copyright 2024 Apache Software Foundation (ASF) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: sonataflow.org/v1alpha08 +kind: SonataFlowPlatform +metadata: + name: sonataflow-platform +spec: + build: + template: + buildArgs: + - name: QUARKUS_EXTENSIONS + value: org.kie.kogito:kogito-addons-quarkus-jobs-knative-eventing:999-SNAPSHOT + services: + dataIndex: + enabled: true + persistence: + postgresql: + jdbcUrl: jdbc:postgresql://postgres:5432/sonataflow?currentSchema=data-index-service + secretRef: + name: postgres-secrets + userKey: POSTGRES_USER + passwordKey: POSTGRES_PASSWORD + podTemplate: + initContainers: + - name: init-postgres + image: registry.access.redhat.com/ubi9/ubi-minimal:latest + imagePullPolicy: IfNotPresent + command: [ 'sh', '-c', 'until (echo 1 > /dev/tcp/postgres.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local/5432) >/dev/null 2>&1; do echo "Waiting for postgres server"; sleep 3; done;' ] + jobService: + enabled: true + persistence: + postgresql: + jdbcUrl: jdbc:postgresql://postgres:5432/sonataflow?currentSchema=jobs-service + secretRef: + name: postgres-secrets + userKey: POSTGRES_USER + passwordKey: POSTGRES_PASSWORD + podTemplate: + initContainers: + - name: init-postgres + image: registry.access.redhat.com/ubi9/ubi-minimal:latest + imagePullPolicy: IfNotPresent + command: [ 'sh', '-c', 'until (echo 1 > /dev/tcp/postgres.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local/5432) >/dev/null 2>&1; do echo "Waiting for postgres server"; sleep 3; done;' ] diff --git a/test/testdata/platform/services/prod/postgreSQL/kustomization.yaml b/test/testdata/platform/services/prod/postgreSQL/kustomization.yaml new file mode 100644 index 000000000..d3fd127c7 --- /dev/null +++ b/test/testdata/platform/services/prod/postgreSQL/kustomization.yaml @@ -0,0 +1,32 @@ +# Copyright 2024 Apache Software Foundation (ASF) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +resources: +- 01-postgres.yaml +- 02-sonataflow_platform.yaml + +generatorOptions: + disableNameSuffixHash: true + +secretGenerator: + - name: postgres-secrets + literals: + - POSTGRES_USER=sonataflow + - POSTGRES_PASSWORD=sonataflow + - POSTGRES_DATABASE=sonataflow + - PGDATA=/var/lib/pgsql/data/userdata + +sortOptions: + order: fifo + diff --git a/test/testdata/platform/services/prod/postgreSQL/sonataflow/04-sonataflow_callbackstatetimeouts.sw.yaml b/test/testdata/platform/services/prod/postgreSQL/sonataflow/04-sonataflow_callbackstatetimeouts.sw.yaml new file mode 100644 index 000000000..249ee2c12 --- /dev/null +++ b/test/testdata/platform/services/prod/postgreSQL/sonataflow/04-sonataflow_callbackstatetimeouts.sw.yaml @@ -0,0 +1,81 @@ +# Copyright 2024 Apache Software Foundation (ASF) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: sonataflow.org/v1alpha08 +kind: SonataFlow +metadata: + name: callbackstatetimeouts + annotations: + sonataflow.org/description: Callback State Timeouts Example k8s + sonataflow.org/version: 0.0.1 + sonataflow.org/profile: prod +spec: + flow: + start: PrintStartMessage + events: + - name: callbackEvent + source: '' + type: callback_event_type + functions: + - name: systemOut + type: custom + operation: sysout + states: + - name: PrintStartMessage + type: operation + actions: + - name: printSystemOut + functionRef: + refName: systemOut + arguments: + message: "${\"callback-state-timeouts: \" + $WORKFLOW.instanceId + \" has started.\"}" + transition: CallbackState + - name: CallbackState + type: callback + action: + name: callbackAction + functionRef: + refName: systemOut + arguments: + message: "${\"callback-state-timeouts: \" + $WORKFLOW.instanceId + \" has executed the callbackFunction.\"}" + eventRef: callbackEvent + transition: CheckEventArrival + timeouts: + eventTimeout: PT30S + - name: CheckEventArrival + type: switch + dataConditions: + - condition: "${ .eventData != null }" + transition: EventArrived + defaultCondition: + transition: EventNotArrived + - name: EventArrived + type: inject + data: + exitMessage: "The callback event has arrived." + transition: PrintExitMessage + - name: EventNotArrived + type: inject + data: + exitMessage: "The callback event has not arrived, and the timeout has overdue." + transition: PrintExitMessage + - name: PrintExitMessage + type: operation + actions: + - name: printSystemOut + functionRef: + refName: systemOut + arguments: + message: "${\"callback-state-timeouts: \" + $WORKFLOW.instanceId + \" has finalized. \" + .exitMessage + \" eventData: \" + .eventData}" + end: true diff --git a/test/yaml.go b/test/yaml.go index 812c90541..5edbc605a 100644 --- a/test/yaml.go +++ b/test/yaml.go @@ -218,6 +218,10 @@ func GetSonataFlowE2eOrderProcessingFolder() string { return e2eSamples + sonataFlowOrderProcessingFolder } +func GetSonataFlowE2EPlatformServicesDirectory() string { + return filepath.Join(getTestDataDir(), "platform", "services") +} + // getTestDataDir gets the testdata directory containing every sample out there from test/testdata. // It should be used for every testing unit within the module. func getTestDataDir() string {