From c35732dac58fc10db59fda901a7cbba73be52c7b Mon Sep 17 00:00:00 2001 From: Jeremy Dahlgren Date: Fri, 9 May 2025 11:49:27 -0400 Subject: [PATCH] Fix race condition in InternalTestCluster.getMasterName() Prevents assertion errors when the master node is null after obtaining the cluster state in the second call. See PRs 127213 and 127891 for details about recent changes to this method, and where the code used in this commit was proposed. --- .../elasticsearch/test/InternalTestCluster.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/framework/src/main/java/org/elasticsearch/test/InternalTestCluster.java b/test/framework/src/main/java/org/elasticsearch/test/InternalTestCluster.java index 904e53d9af418..9c342067693f8 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/InternalTestCluster.java +++ b/test/framework/src/main/java/org/elasticsearch/test/InternalTestCluster.java @@ -28,6 +28,7 @@ import org.elasticsearch.action.admin.indices.stats.CommonStatsFlags.Flag; import org.elasticsearch.action.support.DestructiveOperations; import org.elasticsearch.action.support.RefCountingRunnable; +import org.elasticsearch.action.support.SubscribableListener; import org.elasticsearch.action.support.replication.TransportReplicationAction; import org.elasticsearch.client.internal.Client; import org.elasticsearch.cluster.ClusterName; @@ -2038,13 +2039,12 @@ public String getMasterName(@Nullable String viaNode) { throw new AssertionError("Unable to get master name, no node found"); } try { - ClusterServiceUtils.awaitClusterState(logger, state -> state.nodes().getMasterNode() != null, clusterService(viaNode)); - final ClusterState state = client(viaNode).admin().cluster().prepareState(TEST_REQUEST_TIMEOUT).setLocal(true).get().getState(); - final DiscoveryNode masterNode = state.nodes().getMasterNode(); - if (masterNode == null) { - throw new AssertionError("Master is not stable but the method expects a stable master node"); - } - return masterNode.getName(); + final var masterNameListener = new SubscribableListener(); + return safeAwait(ClusterServiceUtils.addTemporaryStateListener(clusterService(viaNode), cs -> { + Optional.ofNullable(cs.nodes().getMasterNode()) + .ifPresent(masterNode -> masterNameListener.onResponse(masterNode.getName())); + return masterNameListener.isDone(); + }).andThen(masterNameListener::addListener)); } catch (Exception e) { logger.warn("Can't fetch cluster state", e); throw new RuntimeException("Can't get master node " + e.getMessage(), e);