-
Notifications
You must be signed in to change notification settings - Fork 25.6k
Remove dependency on cluster state API in SpecificMasterNodesIT
#127213
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 11 commits
186faee
fea0260
d890be8
b9093e2
cdee810
9aee869
bf8302e
a51bda0
4b1d6f5
8c891ce
5c5d813
f47c766
d52575f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -198,6 +198,7 @@ | |
| import java.util.List; | ||
| import java.util.Locale; | ||
| import java.util.Map; | ||
| import java.util.Optional; | ||
| import java.util.Random; | ||
| import java.util.Set; | ||
| import java.util.concurrent.Callable; | ||
|
|
@@ -940,6 +941,37 @@ public void waitNoPendingTasksOnAll() throws Exception { | |
| assertNoTimeout(clusterAdmin().prepareHealth(TEST_REQUEST_TIMEOUT).setWaitForEvents(Priority.LANGUID).get()); | ||
| } | ||
|
|
||
| /** | ||
| * Waits for the node {@code viaNode} to see {@code masterNodeName} as the master node in the cluster state and asserts that. | ||
| * Note that this does not guarantee that all other nodes in the cluster are on the same cluster state version already. | ||
| * | ||
| * @param viaNode the node to check the cluster state one | ||
| * @param masterNodeName the master node name that we wait for | ||
| */ | ||
| public void awaitAndAssertMasterNode(String viaNode, String masterNodeName) throws Exception { | ||
| awaitClusterState( | ||
|
||
| logger, | ||
| viaNode, | ||
| state -> Optional.ofNullable(state.nodes().getMasterNode()).map(m -> m.getName().equals(masterNodeName)).orElse(false) | ||
| ); | ||
| } | ||
|
|
||
| /** | ||
| * Waits for a random node in the cluster to not see a master node in the cluster state and asserts that. | ||
| */ | ||
| public void awaitAndAssertMasterNotFound() { | ||
| var viaNode = internalCluster().getRandomNodeName(); | ||
| // We use a temporary state listener instead of `awaitClusterState` here because the `ClusterStateObserver` doesn't run the | ||
| // predicate if the cluster state version didn't change. When a master node leaves the cluster (i.e. what this method is used for), | ||
| // the cluster state version is not incremented. | ||
| var listener = ClusterServiceUtils.addTemporaryStateListener( | ||
| internalCluster().clusterService(viaNode), | ||
| state -> state.nodes().getMasterNode() == null, | ||
| TEST_REQUEST_TIMEOUT | ||
| ); | ||
| safeAwait(listener, TEST_REQUEST_TIMEOUT); | ||
| } | ||
|
|
||
| /** Ensures the result counts are as expected, and logs the results if different */ | ||
| public void assertResultsAndLogOnFailure(long expectedResults, SearchResponse searchResponse) { | ||
| final TotalHits totalHits = searchResponse.getHits().getTotalHits(); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2033,15 +2033,28 @@ public String getMasterName() { | |
| * in the viaNode parameter. If viaNode isn't specified a random node will be picked to the send the request to. | ||
| */ | ||
| public String getMasterName(@Nullable String viaNode) { | ||
| viaNode = viaNode != null ? viaNode : getRandomNodeName(); | ||
| if (viaNode == null) { | ||
| throw new AssertionError("Unable to get master name, no node found"); | ||
| } | ||
| try { | ||
| Client client = viaNode != null ? client(viaNode) : client(); | ||
| return client.admin().cluster().prepareState(TEST_REQUEST_TIMEOUT).get().getState().nodes().getMasterNode().getName(); | ||
| 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(); | ||
| return state.nodes().getMasterNode().getName(); | ||
| } catch (Exception e) { | ||
| logger.warn("Can't fetch cluster state", e); | ||
| throw new RuntimeException("Can't get master node " + e.getMessage(), e); | ||
| } | ||
|
Comment on lines
2040
to
2047
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I still worry this reads the state twice and might see no master the second time due to election jitter. We could cheat and remember the master node seen in the state on which we're awaiting (also saves the exception handling): final var masterNameListener = new SubscribableListener<String>();
return safeAwait(ClusterServiceUtils.addTemporaryStateListener(clusterService(viaNode), cs -> {
Optional.ofNullable(cs.nodes().getMasterNode()).ifPresent(masterNode -> masterNameListener.onResponse(masterNode.getName()));
return masterNameListener.isDone();
}).andThen(masterNameListener::addListener));There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought about that too, but I figured "election jitter" would likely disrupt the test anyway. Tests should be designed to be deterministic/consistent, but there's only so much outside influence tests can account for (e.g. election jitter or CI blips). I'm a little hesitant to "cheat" here. I seem to recall someone saying
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Heh yeah I thought I'd said that at some point :) On reflection I think you're right, tests should not be calling this if the master isn't stable. |
||
| } | ||
|
|
||
| public String getNonMasterNodeName() { | ||
| NodeAndClient randomNodeAndClient = getRandomNodeAndClient(new NodeNamePredicate(getMasterName()).negate()); | ||
| if (randomNodeAndClient != null) { | ||
| return randomNodeAndClient.getName(); | ||
| } | ||
| throw new AssertionError("No non-master node found"); | ||
| } | ||
|
|
||
| /** | ||
| * @return the name of a random node in a cluster | ||
| */ | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added these methods in
ESIntegTestCasebecause I see other use cases for these methods (which I'll get to in follow-up PRs). I'm a little bit on the fence about which class they should live in, though. I would actually like to avoid adding them in this class, as this class is too big already. MaybeInternalTestCluster? Or an entirely new class?