This is an automated email from the ASF dual-hosted git repository.

dongjoon-hyun pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/spark-kubernetes-operator.git


The following commit(s) were added to refs/heads/main by this push:
     new bd154658 [SPARK-59878] Exclude `(UWF|NP)_UNWRITTEN_FIELD` for test 
classes in `spotbugs_exclude.xml`
bd154658 is described below

commit bd154658261b8f516844242108e698937ccaa2de
Author: Dongjoon Hyun <[email protected]>
AuthorDate: Tue Sep 29 12:20:02 2026 -0700

    [SPARK-59878] Exclude `(UWF|NP)_UNWRITTEN_FIELD` for test classes in 
`spotbugs_exclude.xml`
    
    ### What changes were proposed in this pull request?
    
    This PR aims to exclude `UWF_UNWRITTEN_FIELD` and `NP_UNWRITTEN_FIELD` for 
test classes (`~.*Test(\$.*)?`) in `spotbugs_exclude.xml`, and to remove them 
from the `SuppressFBWarnings` of 10 test classes.
    
    ### Why are the changes needed?
    
    SpotBugs reports the fields injected by `EnableKubernetesMockClient` as 
unwritten fields. However, SpotBugs drops these warnings by itself when more 
than 8 classes have such a field with the same name. Then, the class-level 
suppressions become useless and fail the build with 
`US_USELESS_SUPPRESSION_ON_CLASS`.
    
    Currently, 8 test classes have a `kubernetesClient` field. So, adding a new 
one breaks `spotbugsTest` on 5 unrelated test classes. Since SpotBugs applies 
`SuppressFBWarnings` before the exclude filter, this PR removes the class-level 
suppressions too.
    
    ### Does this PR introduce _any_ user-facing change?
    
    No. This only affects the SpotBugs analysis of test classes.
    
    ### How was this patch tested?
    
    Pass the CIs. I also manually verified that adding a 9th test class with a 
`kubernetesClient` field breaks `spotbugsTest` before this PR, but not after it.
    
    ### Was this patch authored or co-authored using generative AI tooling?
    
    Generated-by: Claude Opus 5.5
    
    Closes #911 from dongjoon-hyun/SPARK-59878.
    
    Authored-by: Dongjoon Hyun <[email protected]>
    Signed-off-by: Dongjoon Hyun <[email protected]>
---
 config/spotbugs/spotbugs_exclude.xml                             | 9 +++++++++
 .../operator/config/SparkOperatorConfigMapReconcilerTest.java    | 4 ----
 .../apache/spark/k8s/operator/kueue/KueueWorkloadUtilsTest.java  | 4 ----
 .../k8s/operator/metrics/healthcheck/SentinelManagerTest.java    | 2 +-
 .../metrics/source/KubernetesMetricsInterceptorTest.java         | 4 ----
 .../org/apache/spark/k8s/operator/probe/HealthProbeTest.java     | 4 ----
 .../reconciler/reconcilesteps/AppDriverPodCacheStaleTest.java    | 2 +-
 .../k8s/operator/reconciler/reconcilesteps/AppInitStepTest.java  | 2 +-
 .../operator/reconciler/reconcilesteps/ClusterInitStepTest.java  | 4 ----
 .../reconciler/reconcilesteps/ClusterSuspendStepTest.java        | 4 ----
 .../org/apache/spark/k8s/operator/utils/StatusRecorderTest.java  | 4 ----
 11 files changed, 12 insertions(+), 31 deletions(-)

diff --git a/config/spotbugs/spotbugs_exclude.xml 
b/config/spotbugs/spotbugs_exclude.xml
index c492bc2b..73dafac2 100644
--- a/config/spotbugs/spotbugs_exclude.xml
+++ b/config/spotbugs/spotbugs_exclude.xml
@@ -22,4 +22,13 @@
   <Bug pattern="EI_EXPOSE_REP2"/>
   <Bug pattern="MS_EXPOSE_REP"/>
   <Bug pattern="CT_CONSTRUCTOR_THROW"/>
+  <!--
+    Fields of test classes can be injected by JUnit extensions like 
`@EnableKubernetesMockClient`.
+    Exclude their unwritten-field warnings here instead of per-class 
`@SuppressFBWarnings`, which
+    SpotBugs reports as useless whenever its own heuristics already drop those 
warnings.
+  -->
+  <Match>
+    <Class name="~.*Test(\$.*)?"/>
+    <Bug pattern="UWF_UNWRITTEN_FIELD,NP_UNWRITTEN_FIELD"/>
+  </Match>
 </FindBugsFilter>
diff --git 
a/spark-operator/src/test/java/org/apache/spark/k8s/operator/config/SparkOperatorConfigMapReconcilerTest.java
 
b/spark-operator/src/test/java/org/apache/spark/k8s/operator/config/SparkOperatorConfigMapReconcilerTest.java
index d8f81e79..709a3be7 100644
--- 
a/spark-operator/src/test/java/org/apache/spark/k8s/operator/config/SparkOperatorConfigMapReconcilerTest.java
+++ 
b/spark-operator/src/test/java/org/apache/spark/k8s/operator/config/SparkOperatorConfigMapReconcilerTest.java
@@ -27,7 +27,6 @@ import static org.mockito.Mockito.mock;
 import java.util.Map;
 import java.util.function.Function;
 
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import io.fabric8.kubeapitest.junit.EnableKubeAPIServer;
 import io.fabric8.kubernetes.api.model.ConfigMap;
 import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
@@ -37,9 +36,6 @@ import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
-@SuppressFBWarnings(
-    value = {"UWF_UNWRITTEN_FIELD"},
-    justification = "Unwritten fields are covered by Kubernetes mock client")
 @EnableKubeAPIServer
 class SparkOperatorConfigMapReconcilerTest {
 
diff --git 
a/spark-operator/src/test/java/org/apache/spark/k8s/operator/kueue/KueueWorkloadUtilsTest.java
 
b/spark-operator/src/test/java/org/apache/spark/k8s/operator/kueue/KueueWorkloadUtilsTest.java
index 662308ec..90efba4a 100644
--- 
a/spark-operator/src/test/java/org/apache/spark/k8s/operator/kueue/KueueWorkloadUtilsTest.java
+++ 
b/spark-operator/src/test/java/org/apache/spark/k8s/operator/kueue/KueueWorkloadUtilsTest.java
@@ -42,7 +42,6 @@ import java.util.Map;
 import java.util.Optional;
 import java.util.function.BooleanSupplier;
 
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import io.fabric8.kubernetes.api.model.Condition;
 import io.fabric8.kubernetes.api.model.ConditionBuilder;
 import io.fabric8.kubernetes.api.model.KubernetesResourceList;
@@ -94,9 +93,6 @@ import org.apache.spark.k8s.operator.utils.EventUtils;
 import org.apache.spark.k8s.operator.utils.TestUtils;
 
 @EnableKubernetesMockClient(crud = true)
-@SuppressFBWarnings(
-    value = {"UWF_UNWRITTEN_FIELD", "NP_UNWRITTEN_FIELD"},
-    justification = "Unwritten fields are covered by Kubernetes mock client")
 class KueueWorkloadUtilsTest {
   private static final String NAME = "sparkapplication-app-1";
   private static final String STATUS_PATH =
diff --git 
a/spark-operator/src/test/java/org/apache/spark/k8s/operator/metrics/healthcheck/SentinelManagerTest.java
 
b/spark-operator/src/test/java/org/apache/spark/k8s/operator/metrics/healthcheck/SentinelManagerTest.java
index 8b73485d..45cf394c 100644
--- 
a/spark-operator/src/test/java/org/apache/spark/k8s/operator/metrics/healthcheck/SentinelManagerTest.java
+++ 
b/spark-operator/src/test/java/org/apache/spark/k8s/operator/metrics/healthcheck/SentinelManagerTest.java
@@ -60,7 +60,7 @@ import org.apache.spark.k8s.operator.utils.Utils;
 @EnableKubernetesMockClient(crud = true)
 @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
 @SuppressFBWarnings(
-    value = {"UWF_UNWRITTEN_FIELD", "NP_UNWRITTEN_FIELD", "UUF_UNUSED_FIELD"},
+    value = {"UUF_UNUSED_FIELD"},
     justification = "Unwritten fields are covered by Kubernetes mock client")
 class SentinelManagerTest {
   private static final String DEFAULT = "default";
diff --git 
a/spark-operator/src/test/java/org/apache/spark/k8s/operator/metrics/source/KubernetesMetricsInterceptorTest.java
 
b/spark-operator/src/test/java/org/apache/spark/k8s/operator/metrics/source/KubernetesMetricsInterceptorTest.java
index 49b1d6ef..24c2e1cc 100644
--- 
a/spark-operator/src/test/java/org/apache/spark/k8s/operator/metrics/source/KubernetesMetricsInterceptorTest.java
+++ 
b/spark-operator/src/test/java/org/apache/spark/k8s/operator/metrics/source/KubernetesMetricsInterceptorTest.java
@@ -28,7 +28,6 @@ import java.util.Map;
 
 import com.codahale.metrics.Meter;
 import com.codahale.metrics.Metric;
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import io.fabric8.kubernetes.api.model.ConfigMap;
 import io.fabric8.kubernetes.api.model.ObjectMeta;
 import io.fabric8.kubernetes.client.KubernetesClient;
@@ -48,9 +47,6 @@ import org.apache.spark.k8s.operator.spec.ApplicationSpec;
 
 @EnableKubernetesMockClient(crud = true)
 @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
-@SuppressFBWarnings(
-    value = {"UWF_UNWRITTEN_FIELD", "NP_UNWRITTEN_FIELD"},
-    justification = "Unwritten fields are covered by Kubernetes mock client")
 class KubernetesMetricsInterceptorTest {
 
   private KubernetesMockServer mockServer;
diff --git 
a/spark-operator/src/test/java/org/apache/spark/k8s/operator/probe/HealthProbeTest.java
 
b/spark-operator/src/test/java/org/apache/spark/k8s/operator/probe/HealthProbeTest.java
index 4f73a7cd..9043448e 100644
--- 
a/spark-operator/src/test/java/org/apache/spark/k8s/operator/probe/HealthProbeTest.java
+++ 
b/spark-operator/src/test/java/org/apache/spark/k8s/operator/probe/HealthProbeTest.java
@@ -30,7 +30,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicBoolean;
 
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import io.fabric8.kubernetes.client.KubernetesClient;
 import io.fabric8.kubernetes.client.server.mock.EnableKubernetesMockClient;
 import io.javaoperatorsdk.operator.Operator;
@@ -46,9 +45,6 @@ import 
org.apache.spark.k8s.operator.config.DynamicConfigMonitor;
 import org.apache.spark.k8s.operator.metrics.healthcheck.SentinelManager;
 
 @EnableKubernetesMockClient(crud = true)
-@SuppressFBWarnings(
-    value = {"UWF_UNWRITTEN_FIELD"},
-    justification = "Unwritten fields are covered by Kubernetes mock client")
 class HealthProbeTest {
   private static Operator operator;
   private static Operator sparkConfMonitor;
diff --git 
a/spark-operator/src/test/java/org/apache/spark/k8s/operator/reconciler/reconcilesteps/AppDriverPodCacheStaleTest.java
 
b/spark-operator/src/test/java/org/apache/spark/k8s/operator/reconciler/reconcilesteps/AppDriverPodCacheStaleTest.java
index 6751b783..cb00b433 100644
--- 
a/spark-operator/src/test/java/org/apache/spark/k8s/operator/reconciler/reconcilesteps/AppDriverPodCacheStaleTest.java
+++ 
b/spark-operator/src/test/java/org/apache/spark/k8s/operator/reconciler/reconcilesteps/AppDriverPodCacheStaleTest.java
@@ -55,7 +55,7 @@ import 
org.apache.spark.k8s.operator.utils.SparkAppStatusRecorder;
 
 @EnableKubernetesMockClient(crud = true)
 @SuppressFBWarnings(
-    value = {"UWF_UNWRITTEN_FIELD", "NP_UNWRITTEN_FIELD", "UUF_UNUSED_FIELD"},
+    value = {"UUF_UNUSED_FIELD"},
     justification = "Fields are written by the Kubernetes mock client 
extension.")
 class AppDriverPodCacheStaleTest {
   private static final String APP_NAME = "stale-cache-app";
diff --git 
a/spark-operator/src/test/java/org/apache/spark/k8s/operator/reconciler/reconcilesteps/AppInitStepTest.java
 
b/spark-operator/src/test/java/org/apache/spark/k8s/operator/reconciler/reconcilesteps/AppInitStepTest.java
index 11386785..2c95ff4a 100644
--- 
a/spark-operator/src/test/java/org/apache/spark/k8s/operator/reconciler/reconcilesteps/AppInitStepTest.java
+++ 
b/spark-operator/src/test/java/org/apache/spark/k8s/operator/reconciler/reconcilesteps/AppInitStepTest.java
@@ -104,7 +104,7 @@ import org.apache.spark.k8s.operator.utils.TestUtils;
 
 @EnableKubernetesMockClient(crud = true)
 @SuppressFBWarnings(
-    value = {"UWF_UNWRITTEN_FIELD", "NP_UNWRITTEN_FIELD", "UUF_UNUSED_FIELD"},
+    value = {"UUF_UNUSED_FIELD"},
     justification = "Unwritten fields are covered by Kubernetes mock client")
 class AppInitStepTest {
   private KubernetesMockServer mockServer;
diff --git 
a/spark-operator/src/test/java/org/apache/spark/k8s/operator/reconciler/reconcilesteps/ClusterInitStepTest.java
 
b/spark-operator/src/test/java/org/apache/spark/k8s/operator/reconciler/reconcilesteps/ClusterInitStepTest.java
index e65adf11..02afbd51 100644
--- 
a/spark-operator/src/test/java/org/apache/spark/k8s/operator/reconciler/reconcilesteps/ClusterInitStepTest.java
+++ 
b/spark-operator/src/test/java/org/apache/spark/k8s/operator/reconciler/reconcilesteps/ClusterInitStepTest.java
@@ -35,7 +35,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import io.fabric8.kubernetes.api.model.ConditionBuilder;
 import io.fabric8.kubernetes.api.model.KubernetesResourceList;
 import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
@@ -101,9 +100,6 @@ import 
org.apache.spark.k8s.operator.utils.SparkClusterStatusRecorder;
 import org.apache.spark.k8s.operator.utils.TestUtils;
 
 @EnableKubernetesMockClient(crud = true)
-@SuppressFBWarnings(
-    value = {"UWF_UNWRITTEN_FIELD", "NP_UNWRITTEN_FIELD"},
-    justification = "Unwritten fields are covered by Kubernetes mock client")
 class ClusterInitStepTest {
   private KubernetesClient kubernetesClient;
 
diff --git 
a/spark-operator/src/test/java/org/apache/spark/k8s/operator/reconciler/reconcilesteps/ClusterSuspendStepTest.java
 
b/spark-operator/src/test/java/org/apache/spark/k8s/operator/reconciler/reconcilesteps/ClusterSuspendStepTest.java
index 278dc098..5e318ff7 100644
--- 
a/spark-operator/src/test/java/org/apache/spark/k8s/operator/reconciler/reconcilesteps/ClusterSuspendStepTest.java
+++ 
b/spark-operator/src/test/java/org/apache/spark/k8s/operator/reconciler/reconcilesteps/ClusterSuspendStepTest.java
@@ -36,7 +36,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import io.fabric8.kubernetes.api.model.ConditionBuilder;
 import io.fabric8.kubernetes.api.model.KubernetesResourceList;
 import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
@@ -95,9 +94,6 @@ import 
org.apache.spark.k8s.operator.utils.SparkClusterStatusRecorder;
 import org.apache.spark.k8s.operator.utils.TestUtils;
 
 @EnableKubernetesMockClient(crud = true)
-@SuppressFBWarnings(
-    value = {"UWF_UNWRITTEN_FIELD", "NP_UNWRITTEN_FIELD"},
-    justification = "Unwritten fields are covered by Kubernetes mock client")
 class ClusterSuspendStepTest {
   private static final String WORKLOAD_STATUS_PATH =
       
"/apis/kueue.x-k8s.io/v1beta2/namespaces/default/workloads/sparkcluster-cluster1/status";
diff --git 
a/spark-operator/src/test/java/org/apache/spark/k8s/operator/utils/StatusRecorderTest.java
 
b/spark-operator/src/test/java/org/apache/spark/k8s/operator/utils/StatusRecorderTest.java
index f3fb8a25..57ba2e3c 100644
--- 
a/spark-operator/src/test/java/org/apache/spark/k8s/operator/utils/StatusRecorderTest.java
+++ 
b/spark-operator/src/test/java/org/apache/spark/k8s/operator/utils/StatusRecorderTest.java
@@ -32,7 +32,6 @@ import java.io.IOException;
 import java.net.ServerSocket;
 import java.util.List;
 
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import io.fabric8.kubernetes.client.ConfigBuilder;
 import io.fabric8.kubernetes.client.KubernetesClient;
 import io.fabric8.kubernetes.client.KubernetesClientBuilder;
@@ -52,9 +51,6 @@ import 
org.apache.spark.k8s.operator.status.ApplicationStateSummary;
 import org.apache.spark.k8s.operator.status.ApplicationStatus;
 
 @EnableKubernetesMockClient
-@SuppressFBWarnings(
-    value = {"UWF_UNWRITTEN_FIELD", "NP_UNWRITTEN_FIELD"},
-    justification = "Unwritten fields are covered by Kubernetes mock client")
 class StatusRecorderTest {
 
   static final String DEFAULT_NS = "default";


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to