Repository: kroxylicious/kroxylicious (java)

Issue:
always include resource namespace in condition messages
              Maybe I was miss reading the diff but we weren't including kind or group either... 

I was actually musing if it would make mistakes easier to spot for users if we logged the full co-ordinates of what we were looking for. E.g. we can't find `kind: X in group: Y named: Z in namespace: A` makes it really obvious whats going on if you have created `kind: X in group: Y named: Z in namespace: B`. 

I guess what I'm saying its obvious to us but is it obvious to users? Is it actionable?

_Originally posted by @SamBarker in https://github.com/kroxylicious/kroxylicious/pull/1957#discussion_r1999968786_
            

Pull request description:
Include namespace in ResolveRefs message

### Type of change

- Enhancement / new feature

### Description

Adds namespace to the message to help users understand what the Operator was looking for.

Also use a less verbose form for the group/kind/name coordinates

Closes #1961 

### Checklist

_Please go through this checklist and make sure all applicable tasks have been done_

- [ ] PR raised from a fork of this repository and made from a branch rather than main. 
- [ ] Write tests
- [ ] Update documentation
- [ ] Make sure all unit/integration tests pass
- [ ] Make sure all Sonarcloud warnings are addressed or are justifiably ignored.
- [ ] If applicable to the change, [trigger the system test suite](../blob/main/DEV_GUIDE.md#jenkins-pipeline-for-system-tests).  Make sure tests pass.
- [ ] If applicable to the change, [trigger the performance test suite](../blob/main/PERFORMANCE.md#jenkins-pipeline-for-performance). Ensure that any degradations to performance numbers are understood and justified.
- [ ] Ensure the PR references relevant issue(s) so they are closed on merging.
- [ ] For user facing changes, update CHANGELOG.md (remember to include changes affecting the API of the test artefacts too).

> **_NOTE:_**  You must be a member of `@kroxylicious/developers` to trigger the system test and performance test suites.  If you are not part of this group, comment on the PR requesting a trigger, tagging `@kroxylicious/developers`.


Patch:
diff --git a/kroxylicious-operator/src/main/java/io/kroxylicious/kubernetes/operator/ClusterCondition.java b/kroxylicious-operator/src/main/java/io/kroxylicious/kubernetes/operator/ClusterCondition.java
index b5b5ff3e..03f8c10d 100644
--- a/kroxylicious-operator/src/main/java/io/kroxylicious/kubernetes/operator/ClusterCondition.java
+++ b/kroxylicious-operator/src/main/java/io/kroxylicious/kubernetes/operator/ClusterCondition.java
@@ -8,6 +8,8 @@ package io.kroxylicious.kubernetes.operator;
 
 import java.util.Set;
 
+import io.fabric8.kubernetes.api.model.HasMetadata;
+
 import io.kroxylicious.kubernetes.api.common.Condition;
 import io.kroxylicious.kubernetes.api.common.LocalRef;
 import io.kroxylicious.kubernetes.operator.model.ingress.IngressConflictException;
@@ -15,6 +17,7 @@ import io.kroxylicious.kubernetes.operator.model.ingress.IngressConflictExceptio
 import edu.umd.cs.findbugs.annotations.NonNull;
 import edu.umd.cs.findbugs.annotations.Nullable;
 
+import static io.kroxylicious.kubernetes.operator.ResourcesUtil.name;
 import static java.util.stream.Collectors.joining;
 
 public record ClusterCondition(@NonNull String cluster,
@@ -29,14 +32,9 @@ public record ClusterCondition(@NonNull String cluster,
         return new ClusterCondition(cluster, Condition.Type.Accepted, Condition.Status.TRUE, null, null);
     }
 
-    static ClusterCondition filterInvalid(String cluster, String filterName, String detail) {
-        return new ClusterCondition(cluster, Condition.Type.Accepted, Condition.Status.FALSE, INVALID,
-                String.format("Filter \"%s\" is invalid: %s", filterName, detail));
-    }
-
-    public static ClusterCondition refNotFound(String cluster, LocalRef<?> ref) {
-        return new ClusterCondition(cluster, Condition.Type.ResolvedRefs, Condition.Status.FALSE, INVALID,
-                String.format("Resource of kind \"%s\" in group \"%s\" named \"%s\" does not exist.", ref.getKind(), ref.getGroup(), ref.getName()));
+    public static ClusterCondition refNotFound(HasMetadata referrer, LocalRef<?> ref) {
+        return new ClusterCondition(name(referrer), Condition.Type.ResolvedRefs, Condition.Status.FALSE, INVALID,
+                String.format("Resource %s was not found.", ResourcesUtil.namespacedSlug(ref, referrer)));
     }
 
     public static ClusterCondition ingressConflict(String cluster, Set<IngressConflictException> ingressConflictExceptions) {
diff --git a/kroxylicious-operator/src/main/java/io/kroxylicious/kubernetes/operator/ResourcesUtil.java b/kroxylicious-operator/src/main/java/io/kroxylicious/kubernetes/operator/ResourcesUtil.java
index db93fc8e..4b74d28d 100644
--- a/kroxylicious-operator/src/main/java/io/kroxylicious/kubernetes/operator/ResourcesUtil.java
+++ b/kroxylicious-operator/src/main/java/io/kroxylicious/kubernetes/operator/ResourcesUtil.java
@@ -13,6 +13,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Comparator;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
@@ -31,8 +32,6 @@ import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
 import io.fabric8.kubernetes.api.model.OwnerReference;
 import io.fabric8.kubernetes.api.model.OwnerReferenceBuilder;
 import io.fabric8.kubernetes.client.CustomResource;
-import io.fabric8.kubernetes.model.annotation.Group;
-import io.fabric8.kubernetes.model.annotation.Singular;
 import io.javaoperatorsdk.operator.api.reconciler.Context;
 import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext;
 import io.javaoperatorsdk.operator.processing.event.ResourceID;
@@ -54,6 +53,7 @@ import io.kroxylicious.kubernetes.filter.api.v1alpha1.KafkaProtocolFilterStatus;
 import edu.umd.cs.findbugs.annotations.NonNull;
 
 public class ResourcesUtil {
+
     private ResourcesUtil() {
     }
 
@@ -176,6 +176,10 @@ public class ResourcesUtil {
     }
 
     public static String group(HasMetadata resource) {
+        // core CustomResource classes like Secret, Deployment etc. have a group of empty string and their apiVersion is the String 'v1'
+        if (!resource.getApiVersion().contains("/")) {
+            return "";
+        }
         return resource.getApiVersion().substring(0, resource.getApiVersion().indexOf("/"));
     }
 
@@ -452,15 +456,15 @@ public class ResourcesUtil {
         return newUnknownCondition(clock, observedGenerationSource, Condition.Type.ResolvedRefs, e);
     }
 
-    static String slug(String singular, String group, String name) {
-        return singular + "." + group + "/" + name;
+    public static @NonNull String namespacedSlug(LocalRef<?> ref, HasMetadata resource) {
+        return slug(ref) + " in namespace '" + namespace(resource) + "'";
     }
 
-    static String slug(Class<? extends CustomResource<?, ?>> annotatedCrdClass, String crName) {
-        return slug(
-                annotatedCrdClass.getAnnotation(Singular.class).value(),
-                annotatedCrdClass.getAnnotation(Group.class).value(),
-                crName);
+    private static @NonNull String slug(LocalRef<?> ref) {
+        String group = ref.getGroup();
+        String name = ref.getName();
+        String groupString = group.isEmpty() ? "" : "." + group;
+        return ref.getKind().toLowerCase(Locale.ROOT) + groupString + "/" + name;
     }
 
 }
diff --git a/kroxylicious-operator/src/main/java/io/kroxylicious/kubernetes/operator/VirtualKafkaClusterReconciler.java b/kroxylicious-operator/src/main/java/io/kroxylicious/kubernetes/operator/VirtualKafkaClusterReconciler.java
index 0ed9ca9f..040ff94a 100644
--- a/kroxylicious-operator/src/main/java/io/kroxylicious/kubernetes/operator/VirtualKafkaClusterReconciler.java
+++ b/kroxylicious-operator/src/main/java/io/kroxylicious/kubernetes/operator/VirtualKafkaClusterReconciler.java
@@ -130,9 +130,9 @@ public final class VirtualKafkaClusterReconciler implements
                 condition = ResourcesUtil.newResolvedRefsTrue(clock, cluster);
             }
             else {
-                Stream<String> serviceMsg = refsMessage("spec.targetKafkaServiceRef references ", KafkaService.class, unresolvedServices);
-                Stream<String> ingressMsg = refsMessage("spec.ingressRefs references ", KafkaProxyIngress.class, unresolvedIngresses);
-                Stream<String> filterMsg = refsMessage("spec.filterRefs references ", KafkaProtocolFilter.class, unresolvedFilters);
+                Stream<String> serviceMsg = refsMessage("spec.targetKafkaServiceRef references ", cluster, unresolvedServices);
+                Stream<String> ingressMsg = refsMessage("spec.ingressRefs references ", cluster, unresolvedIngresses);
+                Stream<String> filterMsg = refsMessage("spec.filterRefs references ", cluster, unresolvedFilters);
                 condition = ResourcesUtil.newResolvedRefsFalse(clock,
                         cluster,
                         TRANSITIVELY_REFERENCED_RESOURCES_NOT_FOUND,
@@ -140,10 +140,10 @@ public final class VirtualKafkaClusterReconciler implements
             }
         }
         else {
-            Stream<String> proxyMsg = refsMessage("spec.proxyRef references ", KafkaProxy.class, missingProxies);
-            Stream<String> serviceMsg = refsMessage("spec.targetKafkaServiceRef references ", KafkaService.class, missingServices);
-            Stream<String> ingressMsg = refsMessage("spec.ingressRefs references ", KafkaProxyIngress.class, missingIngresses);
-            Stream<String> filterMsg = refsMessage("spec.filterRefs references ", KafkaProtocolFilter.class, missingFilters);
+            Stream<String> proxyMsg = refsMessage("spec.proxyRef references ", cluster, missingProxies);
+            Stream<String> serviceMsg = refsMessage("spec.targetKafkaServiceRef references ", cluster, missingServices);
+            Stream<String> ingressMsg = refsMessage("spec.ingressRefs references ", cluster, missingIngresses);
+            Stream<String> filterMsg = refsMessage("spec.filterRefs references ", cluster, missingFilters);
 
             condition = ResourcesUtil.newResolvedRefsFalse(clock,
                     cluster,
@@ -173,12 +173,12 @@ public final class VirtualKafkaClusterReconciler implements
     @NonNull
     private static <R extends CustomResource<?, ?>> Stream<String> refsMessage(
                                                                                String prefix,
-                                                                               Class<R> crdClass,
+                                                                               VirtualKafkaCluster cluster,
                                                                                TreeSet<? extends LocalRef<R>> refs) {
         return refs.isEmpty() ? Stream.of()
                 : Stream.of(
                         prefix + refs.stream()
-                                .map(ref -> ResourcesUtil.slug(crdClass, ref.getName()))
+                                .map(ref -> ResourcesUtil.namespacedSlug(ref, cluster))
                                 .collect(Collectors.joining(", ")));
     }
 
diff --git a/kroxylicious-operator/src/main/java/io/kroxylicious/kubernetes/operator/resolver/ClusterConditionUnresolvedDependencyReporter.java b/kroxylicious-operator/src/main/java/io/kroxylicious/kubernetes/operator/resolver/ClusterConditionUnresolvedDependencyReporter.java
index 2c0b11d4..5f40e0b6 100644
--- a/kroxylicious-operator/src/main/java/io/kroxylicious/kubernetes/operator/resolver/ClusterConditionUnresolvedDependencyReporter.java
+++ b/kroxylicious-operator/src/main/java/io/kroxylicious/kubernetes/operator/resolver/ClusterConditionUnresolvedDependencyReporter.java
@@ -17,8 +17,6 @@ import io.kroxylicious.kubernetes.api.v1alpha1.VirtualKafkaCluster;
 import io.kroxylicious.kubernetes.operator.ClusterCondition;
 import io.kroxylicious.kubernetes.operator.SharedKafkaProxyContext;
 
-import static io.kroxylicious.kubernetes.operator.ResourcesUtil.name;
-
 public record ClusterConditionUnresolvedDependencyReporter(Context<KafkaProxy> context) implements UnresolvedDependencyReporter {
 
     @Override
@@ -33,6 +31,6 @@ public record ClusterConditionUnresolvedDependencyReporter(Context<KafkaProxy> c
                 .sorted(comparator).findFirst()
                 .orElseThrow();
         SharedKafkaProxyContext.addClusterCondition(context, cluster,
-                ClusterCondition.refNotFound(name(cluster), firstUnresolvedDependency));
+                ClusterCondition.refNotFound(cluster, firstUnresolvedDependency));
     }
 }


Test patch:
diff --git a/kroxylicious-operator/src/test/java/io/kroxylicious/kubernetes/operator/KafkaProxyReconcilerTest.java b/kroxylicious-operator/src/test/java/io/kroxylicious/kubernetes/operator/KafkaProxyReconcilerTest.java
index bf74d765..09229288 100644
--- a/kroxylicious-operator/src/test/java/io/kroxylicious/kubernetes/operator/KafkaProxyReconcilerTest.java
+++ b/kroxylicious-operator/src/test/java/io/kroxylicious/kubernetes/operator/KafkaProxyReconcilerTest.java
@@ -329,9 +329,11 @@ class KafkaProxyReconcilerTest {
                 .build();
         // @formatter:on
         doReturn(mdrc).when(context).managedWorkflowAndDependentResourceContext();
-        doReturn(Set.of(new VirtualKafkaClusterBuilder().withNewMetadata().withName("my-cluster").withNamespace("my-ns").endMetadata().withNewSpec().withNewProxyRef()
-                .withName("my-proxy").endProxyRef().endSpec().build())).when(context).getSecondaryResources(VirtualKafkaCluster.class);
-        doReturn(Optional.of(Map.of("my-cluster", ClusterCondition.refNotFound("my-cluster", new FilterRefBuilder().withName("MissingFilter").build())))).when(mdrc).get(
+        VirtualKafkaCluster cluster = new VirtualKafkaClusterBuilder().withNewMetadata().withName("my-cluster").withNamespace("my-ns").endMetadata().withNewSpec()
+                .withNewProxyRef()
+                .withName("my-proxy").endProxyRef().endSpec().build();
+        doReturn(Set.of(cluster)).when(context).getSecondaryResources(VirtualKafkaCluster.class);
+        doReturn(Optional.of(Map.of("my-cluster", ClusterCondition.refNotFound(cluster, new FilterRefBuilder().withName("MissingFilter").build())))).when(mdrc).get(
                 SharedKafkaProxyContext.CLUSTER_CONDITIONS_KEY,
                 Map.class);
 
@@ -351,7 +353,7 @@ class KafkaProxyReconcilerTest {
         statusAssert.singleCluster()
                 .nameIsEqualTo("my-cluster")
                 .singleCondition()
-                .isResolvedRefsFalse("Invalid", "Resource of kind \"KafkaProtocolFilter\" in group \"filter.kroxylicious.io\" named \"MissingFilter\" does not exist.")
+                .isResolvedRefsFalse("Invalid", "Resource kafkaprotocolfilter.filter.kroxylicious.io/MissingFilter in namespace 'my-ns' was not found.")
                 .hasObservedGeneration(generation);
         // TODO .lastTransitionTimeIsEqualTo(time);
 
diff --git a/kroxylicious-operator/src/test/java/io/kroxylicious/kubernetes/operator/ResourcesUtilTest.java b/kroxylicious-operator/src/test/java/io/kroxylicious/kubernetes/operator/ResourcesUtilTest.java
index 50e6c1b4..e4c8e79a 100644
--- a/kroxylicious-operator/src/test/java/io/kroxylicious/kubernetes/operator/ResourcesUtilTest.java
+++ b/kroxylicious-operator/src/test/java/io/kroxylicious/kubernetes/operator/ResourcesUtilTest.java
@@ -23,12 +23,14 @@ import io.fabric8.kubernetes.api.model.HasMetadata;
 import io.fabric8.kubernetes.api.model.Secret;
 import io.fabric8.kubernetes.api.model.SecretBuilder;
 
+import io.kroxylicious.kubernetes.api.common.AnyLocalRefBuilder;
 import io.kroxylicious.kubernetes.api.common.Condition;
 import io.kroxylicious.kubernetes.api.common.ConditionBuilder;
 import io.kroxylicious.kubernetes.api.common.FilterRefBuilder;
 import io.kroxylicious.kubernetes.api.common.IngressRefBuilder;
 import io.kroxylicious.kubernetes.api.common.KafkaServiceRefBuilder;
 import io.kroxylicious.kubernetes.api.common.ProxyRefBuilder;
+import io.kroxylicious.kubernetes.api.v1alpha1.KafkaProxy;
 import io.kroxylicious.kubernetes.api.v1alpha1.KafkaProxyBuilder;
 import io.kroxylicious.kubernetes.api.v1alpha1.KafkaProxyIngressBuilder;
 import io.kroxylicious.kubernetes.api.v1alpha1.KafkaServiceBuilder;
@@ -161,6 +163,30 @@ class ResourcesUtilTest {
         assertThat(ResourcesUtil.generation(secret)).isEqualTo(generation);
     }
 
+    @Test
+    void toLocalRefNoGroup() {
+        assertThat(ResourcesUtil.toLocalRef(new SecretBuilder().withNewMetadata().withName("name").endMetadata().build()))
+                .isEqualTo(new AnyLocalRefBuilder().withName("name").withGroup("").withKind("Secret").build());
+    }
+
+    @Test
+    void toLocalRefWithGroup() {
+        assertThat(ResourcesUtil.toLocalRef(new KafkaProxyBuilder().withNewMetadata().withName("name").endMetadata().build()))
+                .isEqualTo(new AnyLocalRefBuilder().withName("name").withGroup("kroxylicious.io").withKind("KafkaProxy").build());
+    }
+
+    @Test
+    void slugWithNamespaceEmptyGroup() {
+        Secret secret = new SecretBuilder().withNewMetadata().withNamespace("my-ns").withName("secreto").endMetadata().build();
+        assertThat(ResourcesUtil.namespacedSlug(ResourcesUtil.toLocalRef(secret), secret)).isEqualTo("secret/secreto in namespace 'my-ns'");
+    }
+
+    @Test
+    void slugWithNamespaceNonEmptyGroup() {
+        KafkaProxy secret = new KafkaProxyBuilder().withNewMetadata().withNamespace("my-ns").withName("secreto").endMetadata().build();
+        assertThat(ResourcesUtil.namespacedSlug(ResourcesUtil.toLocalRef(secret), secret)).isEqualTo("kafkaproxy.kroxylicious.io/secreto in namespace 'my-ns'");
+    }
+
     @Test
     void toLocalRef() {
         assertThat(ResourcesUtil.toLocalRef(new KafkaProxyBuilder().withNewMetadata().withName("foo").endMetadata().build()))
diff --git a/kroxylicious-operator/src/test/java/io/kroxylicious/kubernetes/operator/VirtualKafkaClusterReconcilerTest.java b/kroxylicious-operator/src/test/java/io/kroxylicious/kubernetes/operator/VirtualKafkaClusterReconcilerTest.java
index 4dc63e2e..0def3efd 100644
--- a/kroxylicious-operator/src/test/java/io/kroxylicious/kubernetes/operator/VirtualKafkaClusterReconcilerTest.java
+++ b/kroxylicious-operator/src/test/java/io/kroxylicious/kubernetes/operator/VirtualKafkaClusterReconcilerTest.java
@@ -46,6 +46,7 @@ class VirtualKafkaClusterReconcilerTest {
     public static final VirtualKafkaCluster CLUSTER_NO_FILTERS = new VirtualKafkaClusterBuilder()
             .withNewMetadata()
                 .withName("foo")
+                .withNamespace("my-namespace")
                 .withGeneration(42L)
             .endMetadata()
             .withNewSpec()
@@ -129,7 +130,7 @@ class VirtualKafkaClusterReconcilerTest {
                         Set.of(),
                         (Consumer<ConditionAssert>) ca -> ca.isResolvedRefsFalse(
                                 VirtualKafkaClusterReconciler.REFERENCED_RESOURCES_NOT_FOUND,
-                                "spec.proxyRef references kafkaproxy.kroxylicious.io/my-proxy")),
+                                "spec.proxyRef references kafkaproxy.kroxylicious.io/my-proxy in namespace 'my-namespace'")),
                 Arguments.argumentSet("service not found",
                         CLUSTER_NO_FILTERS,
                         Optional.of(PROXY),
@@ -138,7 +139,7 @@ class VirtualKafkaClusterReconcilerTest {
                         Set.of(),
                         (Consumer<ConditionAssert>) ca -> ca.isResolvedRefsFalse(
                                 VirtualKafkaClusterReconciler.REFERENCED_RESOURCES_NOT_FOUND,
-                                "spec.targetKafkaServiceRef references kafkaservice.kroxylicious.io/my-kafka")),
+                                "spec.targetKafkaServiceRef references kafkaservice.kroxylicious.io/my-kafka in namespace 'my-namespace'")),
                 Arguments.argumentSet("service has unresolved refs",
                         CLUSTER_NO_FILTERS,
                         Optional.of(PROXY),
@@ -148,7 +149,7 @@ class VirtualKafkaClusterReconcilerTest {
                         Set.of(),
                         (Consumer<ConditionAssert>) ca -> ca.isResolvedRefsFalse(
                                 VirtualKafkaClusterReconciler.TRANSITIVELY_REFERENCED_RESOURCES_NOT_FOUND,
-                                "spec.targetKafkaServiceRef references kafkaservice.kroxylicious.io/my-kafka")),
+                                "spec.targetKafkaServiceRef references kafkaservice.kroxylicious.io/my-kafka in namespace 'my-namespace'")),
                 Arguments.argumentSet("ingress not found",
                         CLUSTER_NO_FILTERS,
                         Optional.of(PROXY),
@@ -157,7 +158,7 @@ class VirtualKafkaClusterReconcilerTest {
                         Set.of(),
                         (Consumer<ConditionAssert>) ca -> ca.isResolvedRefsFalse(
                                 VirtualKafkaClusterReconciler.REFERENCED_RESOURCES_NOT_FOUND,
-                                "spec.ingressRefs references kafkaproxyingress.kroxylicious.io/my-ingress")),
+                                "spec.ingressRefs references kafkaproxyingress.kroxylicious.io/my-ingress in namespace 'my-namespace'")),
                 Arguments.argumentSet("ingress has unresolved refs",
                         CLUSTER_NO_FILTERS,
                         Optional.of(PROXY),
@@ -167,7 +168,7 @@ class VirtualKafkaClusterReconcilerTest {
                         Set.of(),
                         (Consumer<ConditionAssert>) ca -> ca.isResolvedRefsFalse(
                                 VirtualKafkaClusterReconciler.TRANSITIVELY_REFERENCED_RESOURCES_NOT_FOUND,
-                                "spec.ingressRefs references kafkaproxyingress.kroxylicious.io/my-ingress")),
+                                "spec.ingressRefs references kafkaproxyingress.kroxylicious.io/my-ingress in namespace 'my-namespace'")),
                 Arguments.argumentSet("filter not found",
                         CLUSTER_ONE_FILTER,
                         Optional.of(PROXY),
@@ -176,7 +177,7 @@ class VirtualKafkaClusterReconcilerTest {
                         Set.of(),
                         (Consumer<ConditionAssert>) ca -> ca.isResolvedRefsFalse(
                                 VirtualKafkaClusterReconciler.REFERENCED_RESOURCES_NOT_FOUND,
-                                "spec.filterRefs references kafkaprotocolfilter.filter.kroxylicious.io/my-filter")),
+                                "spec.filterRefs references kafkaprotocolfilter.filter.kroxylicious.io/my-filter in namespace 'my-namespace'")),
                 Arguments.argumentSet("filter has unresolved refs",
                         CLUSTER_ONE_FILTER,
                         Optional.of(PROXY),
@@ -186,7 +187,7 @@ class VirtualKafkaClusterReconcilerTest {
                                 .withStatus(Condition.Status.FALSE).endCondition().endStatus().build()),
                         (Consumer<ConditionAssert>) ca -> ca.isResolvedRefsFalse(
                                 VirtualKafkaClusterReconciler.TRANSITIVELY_REFERENCED_RESOURCES_NOT_FOUND,
-                                "spec.filterRefs references kafkaprotocolfilter.filter.kroxylicious.io/my-filter")));
+                                "spec.filterRefs references kafkaprotocolfilter.filter.kroxylicious.io/my-filter in namespace 'my-namespace'")));
     }
 
     @ParameterizedTest
diff --git a/kroxylicious-operator/src/test/java/io/kroxylicious/kubernetes/operator/resolver/ClusterConditionUnresolvedDependencyReporterTest.java b/kroxylicious-operator/src/test/java/io/kroxylicious/kubernetes/operator/resolver/ClusterConditionUnresolvedDependencyReporterTest.java
index 4c6803cf..13f0dafc 100644
--- a/kroxylicious-operator/src/test/java/io/kroxylicious/kubernetes/operator/resolver/ClusterConditionUnresolvedDependencyReporterTest.java
+++ b/kroxylicious-operator/src/test/java/io/kroxylicious/kubernetes/operator/resolver/ClusterConditionUnresolvedDependencyReporterTest.java
@@ -42,7 +42,8 @@ import static org.mockito.Mockito.when;
 @ExtendWith(MockitoExtension.class)
 class ClusterConditionUnresolvedDependencyReporterTest {
 
-    private static final VirtualKafkaCluster CLUSTER = new VirtualKafkaClusterBuilder().editMetadata().withName("cluster").endMetadata().build();
+    public static final String NAMESPACE = "foo";
+    private static final VirtualKafkaCluster CLUSTER = new VirtualKafkaClusterBuilder().editMetadata().withNamespace(NAMESPACE).withName("cluster").endMetadata().build();
 
     @Mock(strictness = LENIENT)
     Context<KafkaProxy> mockContext;
@@ -83,7 +84,7 @@ class ClusterConditionUnresolvedDependencyReporterTest {
         verify(mockResourceContext).put(eq("cluster_conditions"), assertArg(a -> {
             assertThat(a).isInstanceOfSatisfying(Map.class, map -> {
                 assertThat(map).containsExactlyEntriesOf(Map.of("cluster", new ClusterCondition("cluster", Condition.Type.ResolvedRefs, Condition.Status.FALSE, "Invalid",
-                        "Resource of kind \"KafkaProtocolFilter\" in group \"filter.kroxylicious.io\" named \"a\" does not exist.")));
+                        "Resource kafkaprotocolfilter.filter.kroxylicious.io/a in namespace '" + NAMESPACE + "' was not found.")));
             });
         }));
     }
@@ -92,7 +93,7 @@ class ClusterConditionUnresolvedDependencyReporterTest {
     void clusterRefUnresolved() {
         var unresolved = new KafkaServiceRefBuilder().withName("a").build();
         Set<LocalRef<?>> unresolvedDependencies = Set.of(unresolved);
-        VirtualKafkaCluster cluster = new VirtualKafkaClusterBuilder().editMetadata().withName("cluster").endMetadata()
+        VirtualKafkaCluster cluster = new VirtualKafkaClusterBuilder().editMetadata().withName("cluster").withNamespace(NAMESPACE).endMetadata()
                 .withNewSpec().withNewTargetKafkaServiceRef().withName("name").endTargetKafkaServiceRef()
                 .endSpec().build();
 
@@ -103,7 +104,7 @@ class ClusterConditionUnresolvedDependencyReporterTest {
         verify(mockResourceContext).put(eq("cluster_conditions"), assertArg(a -> {
             assertThat(a).isInstanceOfSatisfying(Map.class, map -> {
                 assertThat(map).containsExactlyEntriesOf(Map.of("cluster", new ClusterCondition("cluster", Condition.Type.ResolvedRefs, Condition.Status.FALSE, "Invalid",
-                        "Resource of kind \"KafkaService\" in group \"kroxylicious.io\" named \"a\" does not exist.")));
+                        "Resource kafkaservice.kroxylicious.io/a in namespace '" + NAMESPACE + "' was not found.")));
             });
         }));
     }
@@ -120,7 +121,7 @@ class ClusterConditionUnresolvedDependencyReporterTest {
         verify(mockResourceContext).put(eq("cluster_conditions"), assertArg(a -> {
             assertThat(a).isInstanceOfSatisfying(Map.class, map -> {
                 assertThat(map).containsExactlyEntriesOf(Map.of("cluster", new ClusterCondition("cluster", Condition.Type.ResolvedRefs, Condition.Status.FALSE, "Invalid",
-                        "Resource of kind \"KafkaProxyIngress\" in group \"kroxylicious.io\" named \"a\" does not exist.")));
+                        "Resource kafkaproxyingress.kroxylicious.io/a in namespace '" + NAMESPACE + "' was not found.")));
             });
         }));
     }
@@ -137,7 +138,7 @@ class ClusterConditionUnresolvedDependencyReporterTest {
         verify(mockResourceContext).put(eq("cluster_conditions"), assertArg(a -> {
             assertThat(a).isInstanceOfSatisfying(Map.class, map -> {
                 assertThat(map).containsExactlyEntriesOf(Map.of("cluster", new ClusterCondition("cluster", Condition.Type.ResolvedRefs, Condition.Status.FALSE, "Invalid",
-                        "Resource of kind \"KafkaProtocolFilter\" in group \"filter.kroxylicious.io\" named \"a\" does not exist.")));
+                        "Resource kafkaprotocolfilter.filter.kroxylicious.io/a in namespace '" + NAMESPACE + "' was not found.")));
             });
         }));
     }
diff --git a/kroxylicious-operator/src/test/resources/DerivedResourcesTest/clusterref-resource-not-found/cond-ResolvedRefs-bar.yaml b/kroxylicious-operator/src/test/resources/DerivedResourcesTest/clusterref-resource-not-found/cond-ResolvedRefs-bar.yaml
index 049192d7..3cf04f96 100644
--- a/kroxylicious-operator/src/test/resources/DerivedResourcesTest/clusterref-resource-not-found/cond-ResolvedRefs-bar.yaml
+++ b/kroxylicious-operator/src/test/resources/DerivedResourcesTest/clusterref-resource-not-found/cond-ResolvedRefs-bar.yaml
@@ -9,5 +9,5 @@ cluster: "bar"
 type: "ResolvedRefs"
 status: "False"
 reason: "Invalid"
-message: "Resource of kind \"KafkaService\" in group \"kroxylicious.io\" named\
-    \ \"barref\" does not exist."
+message: "Resource kafkaservice.kroxylicious.io/barref in namespace 'proxy-ns' was\
+    \ not found."
diff --git a/kroxylicious-operator/src/test/resources/DerivedResourcesTest/filter-resource-not-found/cond-ResolvedRefs-bar.yaml b/kroxylicious-operator/src/test/resources/DerivedResourcesTest/filter-resource-not-found/cond-ResolvedRefs-bar.yaml
index 47308163..1b6bed8e 100644
--- a/kroxylicious-operator/src/test/resources/DerivedResourcesTest/filter-resource-not-found/cond-ResolvedRefs-bar.yaml
+++ b/kroxylicious-operator/src/test/resources/DerivedResourcesTest/filter-resource-not-found/cond-ResolvedRefs-bar.yaml
@@ -9,5 +9,5 @@ cluster: "bar"
 type: "ResolvedRefs"
 status: "False"
 reason: "Invalid"
-message: "Resource of kind \"KafkaProtocolFilter\" in group \"filter.kroxylicious.io\"\
-    \ named \"missing\" does not exist."
+message: "Resource kafkaprotocolfilter.filter.kroxylicious.io/missing in namespace\
+    \ 'proxy-ns' was not found."
\ No newline at end of file
diff --git a/kroxylicious-operator/src/test/resources/DerivedResourcesTest/two-clusters-one-with-unresolved-ingress/cond-ResolvedRefs-foo.yaml b/kroxylicious-operator/src/test/resources/DerivedResourcesTest/two-clusters-one-with-unresolved-ingress/cond-ResolvedRefs-foo.yaml
index 0f0489a1..1ca962da 100644
--- a/kroxylicious-operator/src/test/resources/DerivedResourcesTest/two-clusters-one-with-unresolved-ingress/cond-ResolvedRefs-foo.yaml
+++ b/kroxylicious-operator/src/test/resources/DerivedResourcesTest/two-clusters-one-with-unresolved-ingress/cond-ResolvedRefs-foo.yaml
@@ -9,4 +9,5 @@ cluster: foo
 type: ResolvedRefs
 status: 'False'
 reason: Invalid
-message: "Resource of kind \"KafkaProxyIngress\" in group \"kroxylicious.io\" named \"MISSING\" does not exist."
\ No newline at end of file
+message: "Resource kafkaproxyingress.kroxylicious.io/MISSING in namespace 'proxy-ns'\
+    \ was not found."
\ No newline at end of file
diff --git a/kroxylicious-operator/src/test/resources/DerivedResourcesTest/two-clusters-with-colliding-ingress-and-unresolved-filter/cond-ResolvedRefs-bar.yaml b/kroxylicious-operator/src/test/resources/DerivedResourcesTest/two-clusters-with-colliding-ingress-and-unresolved-filter/cond-ResolvedRefs-bar.yaml
index 067a3357..7b6fd88a 100644
--- a/kroxylicious-operator/src/test/resources/DerivedResourcesTest/two-clusters-with-colliding-ingress-and-unresolved-filter/cond-ResolvedRefs-bar.yaml
+++ b/kroxylicious-operator/src/test/resources/DerivedResourcesTest/two-clusters-with-colliding-ingress-and-unresolved-filter/cond-ResolvedRefs-bar.yaml
@@ -9,5 +9,5 @@ cluster: bar
 type: ResolvedRefs
 status: 'False'
 reason: Invalid
-message: "Resource of kind \"KafkaService\" in group \"kroxylicious.io\" named\
-    \ \"barref\" does not exist."
\ No newline at end of file
+message: "Resource kafkaservice.kroxylicious.io/barref in namespace 'proxy-ns' was\
+    \ not found."
\ No newline at end of file