Repository: apache/camel-k
Pull request #3821 (2022-11-17 03:05:07)

fix(controller): Ready condition message not always taken from Camel Health Checks (1.10.x)
<!-- Description -->

Backport #3814


<!--
Enter your extended release note in the below block. If the PR requires
additional action from users switching to the new release, include the string
"action required". If no release note is required, write "NONE". 

You can (optionally) mark this PR with labels "kind/bug" or "kind/feature" to make sure
the text is added to the right section of the release notes. 
-->

**Release Note**
```release-note
fix(controller): Ready condition message not always taken from Camel Health Checks
```



Patch:
diff --git a/docs/antora.yml b/docs/antora.yml
index ada153ce1..d27285883 100644
--- a/docs/antora.yml
+++ b/docs/antora.yml
@@ -29,7 +29,8 @@ nav:
 asciidoc:
   attributes:
     requires: "'util=camel-website-util,ck=xref:js/ck.js'"
-    prerelease: true
+    lts: LTS
+    prerelease: false
     camel-kamelets-version: 0.9.1 # Makefile KAMELET_CATALOG_REPO_BRANCH
     camel-kamelets-docs-version: 0.9.x # Makefile KAMELET_CATALOG_REPO_BRANCH
     camel-k-runtime-version: 1.15.1 # Makefile RUNTIME_VERSION
diff --git a/pkg/controller/integration/health.go b/pkg/controller/integration/health.go
index 731e2eacb..351a3c7c2 100644
--- a/pkg/controller/integration/health.go
+++ b/pkg/controller/integration/health.go
@@ -30,28 +30,31 @@ import (
 	"k8s.io/client-go/kubernetes"
 )
 
-type HealthCheckState string
+type HealthCheckStatus string
 
 const (
-	HealthCheckStateDown HealthCheckState = "DOWN"
-	HealthCheckStateUp   HealthCheckState = "UP"
+	HealthCheckStatusDown HealthCheckStatus = "DOWN"
+	HealthCheckStatusUp   HealthCheckStatus = "UP"
+
+	// The key used for propagating error details from Camel health to MicroProfile Health
+	// (See CAMEL-17138).
+	HealthCheckErrorMessage = "error.message"
 )
 
 type HealthCheck struct {
-	Status HealthCheckState      `json:"status,omitempty"`
+	Status HealthCheckStatus     `json:"status,omitempty"`
 	Checks []HealthCheckResponse `json:"checks,omitempty"`
 }
 
 type HealthCheckResponse struct {
 	Name   string                 `json:"name,omitempty"`
-	Status HealthCheckState       `json:"status,omitempty"`
+	Status HealthCheckStatus      `json:"status,omitempty"`
 	Data   map[string]interface{} `json:"data,omitempty"`
 }
 
 func NewHealthCheck(body []byte) (*HealthCheck, error) {
 	health := HealthCheck{}
-	err := json.Unmarshal(body, &health)
-	if err != nil {
+	if err := json.Unmarshal(body, &health); err != nil {
 		return nil, err
 	}
 
diff --git a/pkg/controller/integration/monitor.go b/pkg/controller/integration/monitor.go
index df8f426f3..e97580fef 100644
--- a/pkg/controller/integration/monitor.go
+++ b/pkg/controller/integration/monitor.go
@@ -23,6 +23,7 @@ import (
 	"fmt"
 	"reflect"
 	"strconv"
+	"strings"
 
 	appsv1 "k8s.io/api/apps/v1"
 	batchv1 "k8s.io/api/batch/v1"
@@ -41,9 +42,6 @@ import (
 	"github.com/apache/camel-k/pkg/util/kubernetes"
 )
 
-// The key used for propagating error details from Camel health to MicroProfile Health (See CAMEL-17138).
-const runtimeHealthCheckErrorMessage = "error.message"
-
 func NewMonitorAction() Action {
 	return &monitorAction{}
 }
@@ -99,7 +97,8 @@ func (action *monitorAction) Handle(ctx context.Context, integration *v1.Integra
 	if !ok {
 		priority = "0"
 	}
-	withHigherPriority, err := labels.NewRequirement(v1.IntegrationKitPriorityLabel, selection.GreaterThan, []string{priority})
+	withHigherPriority, err := labels.NewRequirement(v1.IntegrationKitPriorityLabel,
+		selection.GreaterThan, []string{priority})
 	if err != nil {
 		return nil, err
 	}
@@ -159,8 +158,9 @@ func (action *monitorAction) Handle(ctx context.Context, integration *v1.Integra
 	if integration.Status.Phase == v1.IntegrationPhaseDeploying {
 		integration.Status.Phase = v1.IntegrationPhaseRunning
 	}
-	err = action.updateIntegrationPhaseAndReadyCondition(ctx, environment, integration, pendingPods.Items, runningPods.Items)
-	if err != nil {
+	if err = action.updateIntegrationPhaseAndReadyCondition(
+		ctx, environment, integration, pendingPods.Items, runningPods.Items,
+	); err != nil {
 		return nil, err
 	}
 
@@ -226,13 +226,21 @@ func getUpdatedController(env *trait.Environment, obj ctrl.Object) ctrl.Object {
 	})
 }
 
-func (action *monitorAction) updateIntegrationPhaseAndReadyCondition(ctx context.Context, environment *trait.Environment, integration *v1.Integration, pendingPods []corev1.Pod, runningPods []corev1.Pod) error {
+func (action *monitorAction) updateIntegrationPhaseAndReadyCondition(
+	ctx context.Context, environment *trait.Environment, integration *v1.Integration,
+	pendingPods []corev1.Pod, runningPods []corev1.Pod,
+) error {
 	controller, err := action.newController(environment, integration)
 	if err != nil {
 		return err
 	}
 
+	readyPods, unreadyPods := filterPodsByReadyStatus(runningPods, controller.getPodSpec())
+
 	if done, err := controller.checkReadyCondition(ctx); done || err != nil {
+		// There may be pods that are not ready but still probable for getting error messages.
+		// Ignore returned error from probing as it's expected when the ctrl obj is not ready.
+		_ = action.probeReadiness(ctx, environment, integration, unreadyPods)
 		return err
 	}
 	if done := checkPodStatuses(integration, pendingPods, runningPods); done {
@@ -240,7 +248,6 @@ func (action *monitorAction) updateIntegrationPhaseAndReadyCondition(ctx context
 	}
 	integration.Status.Phase = v1.IntegrationPhaseRunning
 
-	readyPods, unreadyPods := filterPodsByReadyStatus(runningPods, controller.getPodSpec())
 	if done := controller.updateReadyCondition(readyPods); done {
 		return nil
 	}
@@ -255,7 +262,9 @@ func checkPodStatuses(integration *v1.Integration, pendingPods []corev1.Pod, run
 	// Check Pods statuses
 	for _, pod := range pendingPods {
 		// Check the scheduled condition
-		if scheduled := kubernetes.GetPodCondition(pod, corev1.PodScheduled); scheduled != nil && scheduled.Status == corev1.ConditionFalse && scheduled.Reason == "Unschedulable" {
+		if scheduled := kubernetes.GetPodCondition(pod, corev1.PodScheduled); scheduled != nil &&
+			scheduled.Status == corev1.ConditionFalse &&
+			scheduled.Reason == "Unschedulable" {
 			integration.Status.Phase = v1.IntegrationPhaseError
 			setReadyConditionError(integration, scheduled.Message)
 			return true
@@ -372,7 +381,10 @@ func findIntegrationContainer(spec corev1.PodSpec) *corev1.Container {
 }
 
 // probeReadiness calls the readiness probes of the non-ready Pods directly to retrieve insights from the Camel runtime.
-func (action *monitorAction) probeReadiness(ctx context.Context, environment *trait.Environment, integration *v1.Integration, unreadyPods []corev1.Pod) error {
+func (action *monitorAction) probeReadiness(
+	ctx context.Context, environment *trait.Environment, integration *v1.Integration,
+	unreadyPods []corev1.Pod,
+) error {
 	var runtimeNotReadyMessages []string
 	for i := range unreadyPods {
 		pod := &unreadyPods[i]
@@ -389,11 +401,13 @@ func (action *monitorAction) probeReadiness(ctx context.Context, environment *tr
 				continue
 			}
 			if errors.Is(err, context.DeadlineExceeded) {
-				runtimeNotReadyMessages = append(runtimeNotReadyMessages, fmt.Sprintf("readiness probe timed out for Pod %s/%s", pod.Namespace, pod.Name))
+				runtimeNotReadyMessages = append(runtimeNotReadyMessages,
+					fmt.Sprintf("readiness probe timed out for Pod %s/%s", pod.Namespace, pod.Name))
 				continue
 			}
 			if !k8serrors.IsServiceUnavailable(err) {
-				runtimeNotReadyMessages = append(runtimeNotReadyMessages, fmt.Sprintf("readiness probe failed for Pod %s/%s: %s", pod.Namespace, pod.Name, err.Error()))
+				runtimeNotReadyMessages = append(runtimeNotReadyMessages,
+					fmt.Sprintf("readiness probe failed for Pod %s/%s: %s", pod.Namespace, pod.Name, err.Error()))
 				continue
 			}
 			health, err := NewHealthCheck(body)
@@ -401,13 +415,14 @@ func (action *monitorAction) probeReadiness(ctx context.Context, environment *tr
 				return err
 			}
 			for _, check := range health.Checks {
-				if check.Status == HealthCheckStateUp {
+				if check.Status == HealthCheckStatusUp {
 					continue
 				}
-				if _, ok := check.Data[runtimeHealthCheckErrorMessage]; ok {
+				if _, ok := check.Data[HealthCheckErrorMessage]; ok {
 					integration.Status.Phase = v1.IntegrationPhaseError
 				}
-				runtimeNotReadyMessages = append(runtimeNotReadyMessages, fmt.Sprintf("Pod %s runtime is not ready: %s", pod.Name, check.Data))
+				runtimeNotReadyMessages = append(runtimeNotReadyMessages,
+					fmt.Sprintf("Pod %s runtime is not ready: %s", pod.Name, check.Data))
 			}
 		}
 	}
@@ -416,7 +431,8 @@ func (action *monitorAction) probeReadiness(ctx context.Context, environment *tr
 		if integration.Status.Phase == v1.IntegrationPhaseError {
 			reason = v1.IntegrationConditionErrorReason
 		}
-		setReadyCondition(integration, corev1.ConditionFalse, reason, fmt.Sprintf("%s", runtimeNotReadyMessages))
+		message := fmt.Sprintf("[%s]", strings.Join(runtimeNotReadyMessages, ", "))
+		setReadyCondition(integration, corev1.ConditionFalse, reason, message)
 	}
 
 	return nil
diff --git a/pkg/controller/integration/monitor_cronjob.go b/pkg/controller/integration/monitor_cronjob.go
index 203938943..fed9dadd1 100644
--- a/pkg/controller/integration/monitor_cronjob.go
+++ b/pkg/controller/integration/monitor_cronjob.go
@@ -59,8 +59,11 @@ func (c *cronJobController) checkReadyCondition(ctx context.Context) (bool, erro
 			t = c.lastCompletedJob.CreationTimestamp.Time
 		}
 		if c.lastCompletedJob != nil {
-			if failed := kubernetes.GetJobCondition(*c.lastCompletedJob, batchv1.JobFailed); failed != nil && failed.Status == corev1.ConditionTrue {
-				setReadyCondition(c.integration, corev1.ConditionFalse, v1.IntegrationConditionLastJobFailedReason, fmt.Sprintf("last job %s failed: %s", c.lastCompletedJob.Name, failed.Message))
+			if failed := kubernetes.GetJobCondition(*c.lastCompletedJob, batchv1.JobFailed); failed != nil &&
+				failed.Status == corev1.ConditionTrue {
+				setReadyCondition(c.integration, corev1.ConditionFalse,
+					v1.IntegrationConditionLastJobFailedReason,
+					fmt.Sprintf("last job %s failed: %s", c.lastCompletedJob.Name, failed.Message))
 				c.integration.Status.Phase = v1.IntegrationPhaseError
 				return true, nil
 			}
@@ -77,20 +80,27 @@ func (c *cronJobController) getPodSpec() corev1.PodSpec {
 func (c *cronJobController) updateReadyCondition(readyPods []corev1.Pod) bool {
 	switch {
 	case c.obj.Status.LastScheduleTime == nil:
-		setReadyCondition(c.integration, corev1.ConditionTrue, v1.IntegrationConditionCronJobCreatedReason, "cronjob created")
+		setReadyCondition(c.integration, corev1.ConditionTrue,
+			v1.IntegrationConditionCronJobCreatedReason, "cronjob created")
 		return true
 
 	case len(c.obj.Status.Active) > 0:
-		setReadyCondition(c.integration, corev1.ConditionTrue, v1.IntegrationConditionCronJobActiveReason, "cronjob active")
+		setReadyCondition(c.integration, corev1.ConditionTrue,
+			v1.IntegrationConditionCronJobActiveReason, "cronjob active")
 		return true
 
-	case c.obj.Spec.SuccessfulJobsHistoryLimit != nil && *c.obj.Spec.SuccessfulJobsHistoryLimit == 0 && c.obj.Spec.FailedJobsHistoryLimit != nil && *c.obj.Spec.FailedJobsHistoryLimit == 0:
-		setReadyCondition(c.integration, corev1.ConditionTrue, v1.IntegrationConditionCronJobCreatedReason, "no jobs history available")
+	case c.obj.Spec.SuccessfulJobsHistoryLimit != nil && *c.obj.Spec.SuccessfulJobsHistoryLimit == 0 &&
+		c.obj.Spec.FailedJobsHistoryLimit != nil && *c.obj.Spec.FailedJobsHistoryLimit == 0:
+		setReadyCondition(c.integration, corev1.ConditionTrue,
+			v1.IntegrationConditionCronJobCreatedReason, "no jobs history available")
 		return true
 
 	case c.lastCompletedJob != nil:
-		if complete := kubernetes.GetJobCondition(*c.lastCompletedJob, batchv1.JobComplete); complete != nil && complete.Status == corev1.ConditionTrue {
-			setReadyCondition(c.integration, corev1.ConditionTrue, v1.IntegrationConditionLastJobSucceededReason, fmt.Sprintf("last job %s completed successfully", c.lastCompletedJob.Name))
+		if complete := kubernetes.GetJobCondition(*c.lastCompletedJob, batchv1.JobComplete); complete != nil &&
+			complete.Status == corev1.ConditionTrue {
+			setReadyCondition(c.integration, corev1.ConditionTrue,
+				v1.IntegrationConditionLastJobSucceededReason,
+				fmt.Sprintf("last job %s completed successfully", c.lastCompletedJob.Name))
 			return true
 		}
 
diff --git a/pkg/controller/integration/monitor_deployment.go b/pkg/controller/integration/monitor_deployment.go
index 097fa73d5..adf154799 100644
--- a/pkg/controller/integration/monitor_deployment.go
+++ b/pkg/controller/integration/monitor_deployment.go
@@ -37,7 +37,9 @@ var _ controller = &deploymentController{}
 
 func (c *deploymentController) checkReadyCondition(ctx context.Context) (bool, error) {
 	// Check the Deployment progression
-	if progressing := kubernetes.GetDeploymentCondition(*c.obj, appsv1.DeploymentProgressing); progressing != nil && progressing.Status == corev1.ConditionFalse && progressing.Reason == "ProgressDeadlineExceeded" {
+	if progressing := kubernetes.GetDeploymentCondition(*c.obj, appsv1.DeploymentProgressing); progressing != nil &&
+		progressing.Status == corev1.ConditionFalse &&
+		progressing.Reason == "ProgressDeadlineExceeded" {
 		c.integration.Status.Phase = v1.IntegrationPhaseError
 		setReadyConditionError(c.integration, progressing.Message)
 		return true, nil
diff --git a/pkg/controller/integration/monitor_knative.go b/pkg/controller/integration/monitor_knative.go
index c8182266e..d95f0d1b0 100644
--- a/pkg/controller/integration/monitor_knative.go
+++ b/pkg/controller/integration/monitor_knative.go
@@ -37,7 +37,8 @@ var _ controller = &knativeServiceController{}
 
 func (c *knativeServiceController) checkReadyCondition(ctx context.Context) (bool, error) {
 	// Check the KnativeService conditions
-	if ready := kubernetes.GetKnativeServiceCondition(*c.obj, servingv1.ServiceConditionReady); ready.IsFalse() && ready.GetReason() == "RevisionFailed" {
+	if ready := kubernetes.GetKnativeServiceCondition(*c.obj, servingv1.ServiceConditionReady); ready.IsFalse() &&
+		ready.GetReason() == "RevisionFailed" {
 		c.integration.Status.Phase = v1.IntegrationPhaseError
 		setReadyConditionError(c.integration, ready.Message)
 		return true, nil
diff --git a/script/Makefile b/script/Makefile
index 63bec7622..e5996b028 100644
--- a/script/Makefile
+++ b/script/Makefile
@@ -75,7 +75,7 @@ OPM := opm
 # Used to push pre-release artifacts
 STAGING_IMAGE_NAME := docker.io/camelk/camel-k
 
-STAGING_RUNTIME_REPO := https://repository.apache.org/content/repositories/orgapachecamel-1495
+STAGING_RUNTIME_REPO :=
 
 # Define here the repo containing the default Kamelet catalog (if any)
 KAMELET_CATALOG_REPO := https://github.com/apache/camel-kamelets.git


Test patch:
diff --git a/e2e/global/common/traits/files/NeverReady.java b/e2e/global/common/traits/files/NeverReady.java
new file mode 100644
index 000000000..957641457
--- /dev/null
+++ b/e2e/global/common/traits/files/NeverReady.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+import org.apache.camel.builder.RouteBuilder;
+
+public class NeverReady extends RouteBuilder {
+    @Override
+    public void configure() throws Exception {
+        from("timer:tick").id("never-ready")
+            .to("controlbus:route?routeId=never-ready&action=stop&async=true")
+            .setHeader("m").constant("string!")
+            .setBody().simple("Magic${header.m}")
+            .log("${body}");
+    }
+}
diff --git a/e2e/global/common/traits/health_test.go b/e2e/global/common/traits/health_test.go
index e69d84c35..20d398652 100644
--- a/e2e/global/common/traits/health_test.go
+++ b/e2e/global/common/traits/health_test.go
@@ -27,6 +27,7 @@ import (
 	"fmt"
 	"os"
 	"testing"
+	"time"
 
 	. "github.com/onsi/gomega"
 
@@ -52,6 +53,7 @@ func TestHealthTrait(t *testing.T) {
 		Expect(KamelInstallWithID(operatorID, ns).Execute()).To(Succeed())
 
 		t.Run("Readiness condition with stopped route", func(t *testing.T) {
+			name := "java"
 			Expect(KamelRunWithID(operatorID, ns, "files/Java.java",
 				"-t", "health.enabled=true",
 				// Enable Jolokia for the test to stop the Camel route
@@ -60,12 +62,13 @@ func TestHealthTrait(t *testing.T) {
 				"-t", "jolokia.protocol=http",
 			).Execute()).To(Succeed())
 
-			Eventually(IntegrationPodPhase(ns, "java"), TestTimeoutLong).Should(Equal(corev1.PodRunning))
-			Eventually(IntegrationPhase(ns, "java"), TestTimeoutShort).Should(Equal(v1.IntegrationPhaseRunning))
-			Eventually(IntegrationConditionStatus(ns, "java", v1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(corev1.ConditionTrue))
-			Eventually(IntegrationLogs(ns, "java"), TestTimeoutShort).Should(ContainSubstring("Magicstring!"))
+			Eventually(IntegrationPodPhase(ns, name), TestTimeoutLong).Should(Equal(corev1.PodRunning))
+			Eventually(IntegrationPhase(ns, name), TestTimeoutShort).Should(Equal(v1.IntegrationPhaseRunning))
+			Eventually(IntegrationConditionStatus(ns, name, v1.IntegrationConditionReady), TestTimeoutShort).
+				Should(Equal(corev1.ConditionTrue))
+			Eventually(IntegrationLogs(ns, name), TestTimeoutShort).Should(ContainSubstring("Magicstring!"))
 
-			pod := IntegrationPod(ns, "java")()
+			pod := IntegrationPod(ns, name)()
 
 			// Stop the Camel route
 			request := map[string]string{
@@ -84,7 +87,8 @@ func TestHealthTrait(t *testing.T) {
 			Expect(response).To(ContainSubstring(`"status":200`))
 
 			// Check the ready condition has turned falsy
-			Eventually(IntegrationConditionStatus(ns, "java", v1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(corev1.ConditionFalse))
+			Eventually(IntegrationConditionStatus(ns, name, v1.IntegrationConditionReady), TestTimeoutShort).
+				Should(Equal(corev1.ConditionFalse))
 			// And it contains details about the runtime state
 
 			//
@@ -98,12 +102,42 @@ func TestHealthTrait(t *testing.T) {
 			// status: "False"
 			// type: Ready
 			//
-			Eventually(IntegrationCondition(ns, "java", v1.IntegrationConditionReady), TestTimeoutLong).Should(And(
+			Eventually(IntegrationCondition(ns, name, v1.IntegrationConditionReady), TestTimeoutLong).Should(And(
 				WithTransform(IntegrationConditionReason, Equal(v1.IntegrationConditionRuntimeNotReadyReason)),
-				WithTransform(IntegrationConditionMessage, HavePrefix(fmt.Sprintf("[Pod %s runtime is not ready: map[check.kind:READINESS route.id:route1 route.status:Stopped]", pod.Name))),
+				WithTransform(IntegrationConditionMessage, HavePrefix(
+					fmt.Sprintf(
+						"[Pod %s runtime is not ready: map[check.kind:READINESS route.id:route1 route.status:Stopped]",
+						pod.Name))),
 			))
 			// Check the Integration is still in running phase
-			Eventually(IntegrationPhase(ns, "java"), TestTimeoutShort).Should(Equal(v1.IntegrationPhaseRunning))
+			Eventually(IntegrationPhase(ns, name), TestTimeoutShort).Should(Equal(v1.IntegrationPhaseRunning))
+
+			// Clean-up
+			Expect(Kamel("delete", "--all", "-n", ns).Execute()).To(Succeed())
+		})
+
+		t.Run("Readiness condition with never ready route", func(t *testing.T) {
+			name := "never-ready"
+			Expect(KamelRunWithID(operatorID, ns, "files/NeverReady.java",
+				"-t", "health.enabled=true",
+			).Execute()).To(Succeed())
+
+			Eventually(IntegrationPodPhase(ns, name), TestTimeoutLong).Should(Equal(corev1.PodRunning))
+			Eventually(IntegrationPhase(ns, name), TestTimeoutShort).Should(Equal(v1.IntegrationPhaseRunning))
+			Consistently(IntegrationConditionStatus(ns, name, v1.IntegrationConditionReady), 1*time.Minute).
+				Should(Equal(corev1.ConditionFalse))
+			Eventually(IntegrationPhase(ns, name), TestTimeoutLong).Should(Equal(v1.IntegrationPhaseError))
+
+			pod := IntegrationPod(ns, name)()
+
+			// Check that the error message is propagated from health checks even if deployment never becomes ready
+			Eventually(IntegrationCondition(ns, name, v1.IntegrationConditionReady), TestTimeoutLong).Should(And(
+				WithTransform(IntegrationConditionReason, Equal(v1.IntegrationConditionErrorReason)),
+				WithTransform(IntegrationConditionMessage, HavePrefix(
+					fmt.Sprintf(
+						"[Pod %s runtime is not ready: map[check.kind:READINESS route.id:never-ready route.status:Stopped]",
+						pod.Name))),
+			))
 
 			// Clean-up
 			Expect(Kamel("delete", "--all", "-n", ns).Execute()).To(Succeed())
diff --git a/pkg/controller/integration/health_test.go b/pkg/controller/integration/health_test.go
index ab7c2fc89..ef1a9c799 100644
--- a/pkg/controller/integration/health_test.go
+++ b/pkg/controller/integration/health_test.go
@@ -61,24 +61,24 @@ func TestNewHealthCheck(t *testing.T) {
 	`)
 	health, err := NewHealthCheck(body)
 	assert.NoError(t, err)
-	assert.Equal(t, HealthCheckStateDown, health.Status)
+	assert.Equal(t, HealthCheckStatusDown, health.Status)
 	assert.Len(t, health.Checks, 3)
 	assert.Equal(t, "camel-routes", health.Checks[0].Name)
-	assert.Equal(t, HealthCheckStateDown, health.Checks[0].Status)
+	assert.Equal(t, HealthCheckStatusDown, health.Checks[0].Status)
 	assert.True(t, reflect.DeepEqual(health.Checks[0].Data, map[string]interface{}{
 		"route.id":           "route1",
 		"route.context.name": "camel-1",
 		"route.status":       "Stopped",
 	}))
 	assert.Equal(t, "context", health.Checks[1].Name)
-	assert.Equal(t, HealthCheckStateUp, health.Checks[1].Status)
+	assert.Equal(t, HealthCheckStatusUp, health.Checks[1].Status)
 	assert.True(t, reflect.DeepEqual(health.Checks[1].Data, map[string]interface{}{
 		"context.name":    "camel-1",
 		"context.version": "3.16.0",
 		"context.status":  "Started",
 	}))
 	assert.Equal(t, "camel-consumers", health.Checks[2].Name)
-	assert.Equal(t, HealthCheckStateDown, health.Checks[2].Status)
+	assert.Equal(t, HealthCheckStatusDown, health.Checks[2].Status)
 	assert.True(t, reflect.DeepEqual(health.Checks[2].Data, map[string]interface{}{
 		"route.id":           "route1",
 		"route.context.name": "camel-1",