/*
* Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership. Crate 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.
*
* However, if you have executed another commercial license agreement
* with Crate these terms will supersede the license and you may use the
* software solely pursuant to the terms of the relevant commercial agreement.
*/
package org.elasticsearch.action.bulk;
import io.crate.test.integration.CrateUnitTest;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.ClusterChangedEvent;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.cluster.node.DiscoveryNodes;
import org.elasticsearch.cluster.routing.RoutingTable;
import org.elasticsearch.cluster.routing.allocation.AllocationService;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.index.shard.ShardNotFoundException;
import org.elasticsearch.test.ClusterServiceUtils;
import org.elasticsearch.threadpool.TestThreadPool;
import org.elasticsearch.threadpool.ThreadPool;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import java.util.concurrent.TimeUnit;
import static io.crate.testing.DiscoveryNodes.newNode;
import static org.elasticsearch.cluster.ESAllocationTestCase.createAllocationService;
import static org.hamcrest.Matchers.*;
public class BulkRetryCoordinatorPoolTest extends CrateUnitTest {
private static final String[] NODE_IDS = new String[]{"node1", "node2"};
public static final String TEST_INDEX = "test_index";
@Rule
public ExpectedException expectedException = ExpectedException.none();
BulkRetryCoordinatorPool pool;
ClusterState state;
private TestThreadPool threadPool;
private String indexUUID;
private ClusterService clusterService;
@Before
public void prepare() {
threadPool = new TestThreadPool("testing");
MetaData metaData = MetaData.builder()
.put(IndexMetaData.builder(TEST_INDEX).settings(settings(Version.CURRENT)).numberOfShards(3).numberOfReplicas(0))
.build();
RoutingTable routingTable = RoutingTable.builder()
.addAsNew(metaData.index(TEST_INDEX)).build();
ClusterState state = ClusterState
.builder(org.elasticsearch.cluster.ClusterName.DEFAULT)
.metaData(metaData)
.routingTable(routingTable)
.build();
indexUUID = metaData.index(TEST_INDEX).getIndexUUID();
state = ClusterState.builder(state).nodes(
DiscoveryNodes.builder().add(newNode(NODE_IDS[0])).localNodeId(NODE_IDS[0])).build();
AllocationService allocationService = createAllocationService();
routingTable = allocationService.reroute(state, "test").routingTable();
state = ClusterState.builder(state).routingTable(routingTable).build();
clusterService = ClusterServiceUtils.createClusterService(state, threadPool);
this.state = state;
pool = new BulkRetryCoordinatorPool(Settings.EMPTY, clusterService, threadPool);
pool.start();
}
@After
public void cleanUp() {
pool.stop();
pool.close();
pool = null;
clusterService.close();
ThreadPool.terminate(threadPool, 30, TimeUnit.SECONDS);
}
@Test
public void testGetSameCoordinatorForSameShard() throws Exception {
ShardId shardId = new ShardId(TEST_INDEX, indexUUID, 0);
BulkRetryCoordinator coordinator = pool.coordinator(shardId);
assertThat(coordinator, is(notNullValue()));
BulkRetryCoordinator sameCoordinator = pool.coordinator(shardId);
assertThat(coordinator, is(sameInstance(sameCoordinator)));
}
@Test
public void testUnknownIndex() throws Exception {
expectedException.expect(IndexNotFoundException.class);
expectedException.expectMessage("no such index");
ShardId shardId = new ShardId("unknown", indexUUID, 42);
pool.coordinator(shardId);
}
@Test
public void testUnknownShard() throws Exception {
expectedException.expect(ShardNotFoundException.class);
expectedException.expectMessage("no such shard");
ShardId shardId = new ShardId(TEST_INDEX, indexUUID, 42);
pool.coordinator(shardId);
}
@Test
public void testReturnDifferentCoordinatorForRelocatedShardFromRemovedNode() throws Exception {
ShardId shardId = new ShardId(TEST_INDEX, indexUUID, 1);
BulkRetryCoordinator coordinator = pool.coordinator(shardId);
ClusterState newState = ClusterState.builder(state).nodes(
DiscoveryNodes.builder().add(newNode(NODE_IDS[1]))).build();
AllocationService allocationService = createAllocationService();
newState = allocationService.deassociateDeadNodes(newState, true, "dummy");
RoutingTable routingTable = allocationService.reroute(newState, "test").routingTable();
newState = ClusterState.builder(newState).routingTable(routingTable).build();
pool.clusterChanged(new ClusterChangedEvent("bla", newState, state));
BulkRetryCoordinator otherCoordinator = pool.coordinator(shardId);
assertThat(coordinator, not(sameInstance(otherCoordinator)));
}
}