io.cassandrareaper.service.RepairRunnerTest.java Source code

Java tutorial

Introduction

Here is the source code for io.cassandrareaper.service.RepairRunnerTest.java

Source

/*
 * Licensed 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.
 */

package io.cassandrareaper.service;

import io.cassandrareaper.AppContext;
import io.cassandrareaper.ReaperApplicationConfiguration;
import io.cassandrareaper.ReaperException;
import io.cassandrareaper.core.Cluster;
import io.cassandrareaper.core.Node;
import io.cassandrareaper.core.RepairRun;
import io.cassandrareaper.core.RepairSegment;
import io.cassandrareaper.core.RepairUnit;
import io.cassandrareaper.core.Segment;
import io.cassandrareaper.jmx.JmxConnectionFactory;
import io.cassandrareaper.jmx.JmxProxy;
import io.cassandrareaper.jmx.RepairStatusHandler;
import io.cassandrareaper.storage.IStorage;
import io.cassandrareaper.storage.MemoryStorage;

import java.math.BigInteger;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import com.google.common.base.Optional;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.apache.cassandra.repair.RepairParallelism;
import org.apache.cassandra.service.ActiveRepairService;
import org.apache.cassandra.utils.progress.ProgressEventType;
import org.joda.time.DateTime;
import org.joda.time.DateTimeUtils;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static org.awaitility.Awaitility.await;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public final class RepairRunnerTest {

    private static final Logger LOG = LoggerFactory.getLogger(RepairRunnerTest.class);

    @Before
    public void setUp() throws Exception {
        SegmentRunner.SEGMENT_RUNNERS.clear();
    }

    @Test
    public void testHangingRepair() throws InterruptedException, ReaperException {
        final String CLUSTER_NAME = "reaper";
        final String KS_NAME = "reaper";
        final Set<String> CF_NAMES = Sets.newHashSet("reaper");
        final boolean INCREMENTAL_REPAIR = false;
        final Set<String> NODES = Sets.newHashSet("127.0.0.1");
        final Set<String> DATACENTERS = Collections.emptySet();
        final Set<String> BLACKLISTED_TABLES = Collections.emptySet();
        final long TIME_RUN = 41L;
        final double INTENSITY = 0.5f;
        final int REPAIR_THREAD_COUNT = 1;

        final IStorage storage = new MemoryStorage();
        storage.addCluster(new Cluster(CLUSTER_NAME, null, Collections.<String>singleton("127.0.0.1")));
        RepairUnit cf = storage.addRepairUnit(new RepairUnit.Builder(CLUSTER_NAME, KS_NAME, CF_NAMES,
                INCREMENTAL_REPAIR, NODES, DATACENTERS, BLACKLISTED_TABLES, REPAIR_THREAD_COUNT));
        DateTimeUtils.setCurrentMillisFixed(TIME_RUN);
        RepairRun run = storage.addRepairRun(
                new RepairRun.Builder(CLUSTER_NAME, cf.getId(), DateTime.now(), INTENSITY, 1,
                        RepairParallelism.PARALLEL),
                Collections.singleton(RepairSegment.builder(
                        Segment.builder().withTokenRange(new RingRange(BigInteger.ZERO, BigInteger.ONE)).build(),
                        cf.getId())));
        final UUID RUN_ID = run.getId();
        final UUID SEGMENT_ID = storage.getNextFreeSegmentInRange(run.getId(), Optional.absent()).get().getId();

        assertEquals(storage.getRepairSegment(RUN_ID, SEGMENT_ID).get().getState(),
                RepairSegment.State.NOT_STARTED);
        AppContext context = new AppContext();
        context.storage = storage;
        context.config = new ReaperApplicationConfiguration();
        context.repairManager = RepairManager.create(context);
        context.repairManager.initializeThreadPool(1, 500, TimeUnit.MILLISECONDS, 1, TimeUnit.MILLISECONDS);

        final Semaphore mutex = new Semaphore(0);

        context.jmxConnectionFactory = new JmxConnectionFactory() {
            final AtomicInteger repairAttempts = new AtomicInteger(1);

            @Override
            protected JmxProxy connect(final Optional<RepairStatusHandler> handler, Node host,
                    int connectionTimeout) throws ReaperException {

                final JmxProxy jmx = mock(JmxProxy.class);
                when(jmx.getClusterName()).thenReturn(CLUSTER_NAME);
                when(jmx.isConnectionAlive()).thenReturn(true);
                when(jmx.tokenRangeToEndpoint(anyString(), any(Segment.class))).thenReturn(Lists.newArrayList(""));
                when(jmx.getRangeToEndpointMap(anyString())).thenReturn(RepairRunnerTest.sixNodeCluster());
                when(jmx.getDataCenter()).thenReturn("dc1");
                when(jmx.getDataCenter(anyString())).thenReturn("dc1");

                when(jmx.triggerRepair(any(BigInteger.class), any(BigInteger.class), any(),
                        any(RepairParallelism.class), any(), anyBoolean(), any(), any(), any(), any(Integer.class)))
                                .then((invocation) -> {
                                    assertEquals(RepairSegment.State.NOT_STARTED,
                                            storage.getRepairSegment(RUN_ID, SEGMENT_ID).get().getState());
                                    final int repairNumber = repairAttempts.getAndIncrement();
                                    switch (repairNumber) {
                                    case 1:
                                        new Thread() {
                                            @Override
                                            public void run() {
                                                handler.get().handle(repairNumber,
                                                        Optional.of(ActiveRepairService.Status.STARTED),
                                                        Optional.absent(), null, jmx);

                                                assertEquals(RepairSegment.State.RUNNING, storage
                                                        .getRepairSegment(RUN_ID, SEGMENT_ID).get().getState());
                                            }
                                        }.start();
                                        break;
                                    case 2:
                                        new Thread() {
                                            @Override
                                            public void run() {

                                                handler.get().handle(repairNumber,
                                                        Optional.of(ActiveRepairService.Status.STARTED),
                                                        Optional.absent(), null, jmx);

                                                assertEquals(RepairSegment.State.RUNNING, storage
                                                        .getRepairSegment(RUN_ID, SEGMENT_ID).get().getState());

                                                handler.get().handle(repairNumber,
                                                        Optional.of(ActiveRepairService.Status.SESSION_SUCCESS),
                                                        Optional.absent(), null, jmx);

                                                assertEquals(RepairSegment.State.DONE, storage
                                                        .getRepairSegment(RUN_ID, SEGMENT_ID).get().getState());

                                                handler.get().handle(repairNumber,
                                                        Optional.of(ActiveRepairService.Status.FINISHED),
                                                        Optional.absent(), null, jmx);

                                                mutex.release();
                                                LOG.info("MUTEX RELEASED");
                                            }
                                        }.start();
                                        break;
                                    default:
                                        fail("triggerRepair should only have been called twice");
                                    }
                                    LOG.info("repair number : " + repairNumber);
                                    return repairNumber;
                                });
                return jmx;
            }
        };
        context.repairManager.startRepairRun(run);

        await().with().atMost(20, TimeUnit.SECONDS).until(() -> {
            try {
                mutex.acquire();
                LOG.info("MUTEX ACQUIRED");
                // TODO: refactor so that we can properly wait for the repair runner to finish rather than
                // TODO: using this sleep().
                Thread.sleep(1000);
                return true;
            } catch (InterruptedException ex) {
                throw new IllegalStateException(ex);
            }
        });
        assertEquals(RepairRun.RunState.DONE, storage.getRepairRun(RUN_ID).get().getRunState());
    }

    @Test
    public void testHangingRepairNewAPI() throws InterruptedException, ReaperException {
        final String CLUSTER_NAME = "reaper";
        final String KS_NAME = "reaper";
        final Set<String> CF_NAMES = Sets.newHashSet("reaper");
        final boolean INCREMENTAL_REPAIR = false;
        final Set<String> NODES = Sets.newHashSet("127.0.0.1");
        final Set<String> DATACENTERS = Collections.emptySet();
        final Set<String> BLACKLISTED_TABLES = Collections.emptySet();
        final long TIME_RUN = 41L;
        final double INTENSITY = 0.5f;
        final int REPAIR_THREAD_COUNT = 1;

        final IStorage storage = new MemoryStorage();

        storage.addCluster(new Cluster(CLUSTER_NAME, null, Collections.<String>singleton("127.0.0.1")));
        RepairUnit cf = storage.addRepairUnit(new RepairUnit.Builder(CLUSTER_NAME, KS_NAME, CF_NAMES,
                INCREMENTAL_REPAIR, NODES, DATACENTERS, BLACKLISTED_TABLES, REPAIR_THREAD_COUNT));
        DateTimeUtils.setCurrentMillisFixed(TIME_RUN);
        RepairRun run = storage.addRepairRun(
                new RepairRun.Builder(CLUSTER_NAME, cf.getId(), DateTime.now(), INTENSITY, 1,
                        RepairParallelism.PARALLEL),
                Collections.singleton(RepairSegment.builder(
                        Segment.builder().withTokenRange(new RingRange(BigInteger.ZERO, BigInteger.ONE)).build(),
                        cf.getId())));
        final UUID RUN_ID = run.getId();
        final UUID SEGMENT_ID = storage.getNextFreeSegmentInRange(run.getId(), Optional.absent()).get().getId();

        assertEquals(storage.getRepairSegment(RUN_ID, SEGMENT_ID).get().getState(),
                RepairSegment.State.NOT_STARTED);
        AppContext context = new AppContext();
        context.storage = storage;
        context.config = new ReaperApplicationConfiguration();
        context.repairManager = RepairManager.create(context);
        context.repairManager.initializeThreadPool(1, 500, TimeUnit.MILLISECONDS, 1, TimeUnit.MILLISECONDS);

        final Semaphore mutex = new Semaphore(0);

        context.jmxConnectionFactory = new JmxConnectionFactory() {
            final AtomicInteger repairAttempts = new AtomicInteger(1);

            @Override
            protected JmxProxy connect(final Optional<RepairStatusHandler> handler, Node host,
                    int connectionTimeout) throws ReaperException {

                final JmxProxy jmx = mock(JmxProxy.class);
                when(jmx.getClusterName()).thenReturn(CLUSTER_NAME);
                when(jmx.isConnectionAlive()).thenReturn(true);
                when(jmx.tokenRangeToEndpoint(anyString(), any(Segment.class))).thenReturn(Lists.newArrayList(""));
                when(jmx.getRangeToEndpointMap(anyString())).thenReturn(RepairRunnerTest.sixNodeCluster());
                when(jmx.getDataCenter()).thenReturn("dc1");
                when(jmx.getDataCenter(anyString())).thenReturn("dc1");
                //doNothing().when(jmx).cancelAllRepairs();

                when(jmx.triggerRepair(any(BigInteger.class), any(BigInteger.class), any(),
                        any(RepairParallelism.class), any(), anyBoolean(), any(), any(), any(), any(Integer.class)))
                                .then((invocation) -> {
                                    assertEquals(RepairSegment.State.NOT_STARTED,
                                            storage.getRepairSegment(RUN_ID, SEGMENT_ID).get().getState());

                                    final int repairNumber = repairAttempts.getAndIncrement();
                                    switch (repairNumber) {
                                    case 1:
                                        new Thread() {
                                            @Override
                                            public void run() {
                                                handler.get().handle(repairNumber, Optional.absent(),
                                                        Optional.of(ProgressEventType.START), null, jmx);
                                                assertEquals(RepairSegment.State.RUNNING, storage
                                                        .getRepairSegment(RUN_ID, SEGMENT_ID).get().getState());
                                            }
                                        }.start();
                                        break;
                                    case 2:
                                        new Thread() {
                                            @Override
                                            public void run() {
                                                handler.get().handle(repairNumber, Optional.absent(),
                                                        Optional.of(ProgressEventType.START), null, jmx);
                                                assertEquals(RepairSegment.State.RUNNING, storage
                                                        .getRepairSegment(RUN_ID, SEGMENT_ID).get().getState());
                                                handler.get().handle(repairNumber, Optional.absent(),
                                                        Optional.of(ProgressEventType.SUCCESS), null, jmx);
                                                assertEquals(RepairSegment.State.DONE, storage
                                                        .getRepairSegment(RUN_ID, SEGMENT_ID).get().getState());
                                                handler.get().handle(repairNumber, Optional.absent(),
                                                        Optional.of(ProgressEventType.COMPLETE), null, jmx);
                                                mutex.release();
                                                LOG.info("MUTEX RELEASED");
                                            }
                                        }.start();
                                        break;
                                    default:
                                        fail("triggerRepair should only have been called twice");
                                    }
                                    return repairNumber;
                                });
                return jmx;
            }
        };
        context.repairManager.startRepairRun(run);

        await().with().atMost(20, TimeUnit.SECONDS).until(() -> {
            try {
                mutex.acquire();
                LOG.info("MUTEX ACQUIRED");
                // TODO: refactor so that we can properly wait for the repair runner to finish rather than
                // TODO: using this sleep().
                Thread.sleep(1000);
                return true;
            } catch (InterruptedException ex) {
                throw new IllegalStateException(ex);
            }
        });
        assertEquals(RepairRun.RunState.DONE, storage.getRepairRun(RUN_ID).get().getRunState());
    }

    @Test
    public void testResumeRepair() throws InterruptedException, ReaperException {
        final String CLUSTER_NAME = "reaper";
        final String KS_NAME = "reaper";
        final Set<String> CF_NAMES = Sets.newHashSet("reaper");
        final boolean INCREMENTAL_REPAIR = false;
        final Set<String> NODES = Sets.newHashSet("127.0.0.1");
        final Set<String> DATACENTERS = Collections.emptySet();
        final Set<String> BLACKLISTED_TABLES = Collections.emptySet();
        final long TIME_RUN = 41L;
        final double INTENSITY = 0.5f;
        final int REPAIR_THREAD_COUNT = 1;

        final IStorage storage = new MemoryStorage();
        AppContext context = new AppContext();
        context.storage = storage;
        context.config = new ReaperApplicationConfiguration();
        context.repairManager = RepairManager.create(context);

        storage.addCluster(new Cluster(CLUSTER_NAME, null, Collections.<String>singleton("127.0.0.1")));
        UUID cf = storage.addRepairUnit(new RepairUnit.Builder(CLUSTER_NAME, KS_NAME, CF_NAMES, INCREMENTAL_REPAIR,
                NODES, DATACENTERS, BLACKLISTED_TABLES, REPAIR_THREAD_COUNT)).getId();
        DateTimeUtils.setCurrentMillisFixed(TIME_RUN);

        RepairRun run = storage
                .addRepairRun(
                        new RepairRun.Builder(CLUSTER_NAME, cf, DateTime
                                .now(), INTENSITY, 1, RepairParallelism.PARALLEL),
                        Lists.newArrayList(
                                RepairSegment
                                        .builder(Segment.builder()
                                                .withTokenRange(new RingRange(BigInteger.ZERO, BigInteger.ONE))
                                                .build(), cf)
                                        .withState(RepairSegment.State.RUNNING).withStartTime(DateTime.now())
                                        .withCoordinatorHost("reaper"),
                                RepairSegment.builder(Segment.builder()
                                        .withTokenRange(new RingRange(BigInteger.ONE, BigInteger.ZERO)).build(),
                                        cf)));

        final UUID RUN_ID = run.getId();
        final UUID SEGMENT_ID = storage.getNextFreeSegmentInRange(run.getId(), Optional.absent()).get().getId();

        context.repairManager.initializeThreadPool(1, 500, TimeUnit.MILLISECONDS, 1, TimeUnit.MILLISECONDS);

        assertEquals(storage.getRepairSegment(RUN_ID, SEGMENT_ID).get().getState(),
                RepairSegment.State.NOT_STARTED);
        context.jmxConnectionFactory = new JmxConnectionFactory() {
            @Override
            protected JmxProxy connect(final Optional<RepairStatusHandler> handler, Node host,
                    int connectionTimeout) throws ReaperException {

                final JmxProxy jmx = mock(JmxProxy.class);
                when(jmx.getClusterName()).thenReturn(CLUSTER_NAME);
                when(jmx.isConnectionAlive()).thenReturn(true);
                when(jmx.tokenRangeToEndpoint(anyString(), any(Segment.class))).thenReturn(Lists.newArrayList(""));
                when(jmx.getRangeToEndpointMap(anyString())).thenReturn(RepairRunnerTest.sixNodeCluster());
                when(jmx.getDataCenter()).thenReturn("dc1");
                when(jmx.getDataCenter(anyString())).thenReturn("dc1");

                when(jmx.triggerRepair(any(BigInteger.class), any(BigInteger.class), any(),
                        any(RepairParallelism.class), any(), anyBoolean(), any(), any(), any(), any(Integer.class)))
                                .then((invocation) -> {
                                    assertEquals(RepairSegment.State.NOT_STARTED,
                                            storage.getRepairSegment(RUN_ID, SEGMENT_ID).get().getState());

                                    new Thread() {
                                        @Override
                                        public void run() {
                                            handler.get().handle(1, Optional.of(ActiveRepairService.Status.STARTED),
                                                    Optional.absent(), null, jmx);

                                            handler.get().handle(1,
                                                    Optional.of(ActiveRepairService.Status.SESSION_SUCCESS),
                                                    Optional.absent(), null, jmx);

                                            handler.get().handle(1,
                                                    Optional.of(ActiveRepairService.Status.FINISHED),
                                                    Optional.absent(), null, jmx);
                                        }
                                    }.start();
                                    return 1;
                                });
                return jmx;
            }
        };

        assertEquals(RepairRun.RunState.NOT_STARTED, storage.getRepairRun(RUN_ID).get().getRunState());
        context.repairManager.resumeRunningRepairRuns();
        assertEquals(RepairRun.RunState.NOT_STARTED, storage.getRepairRun(RUN_ID).get().getRunState());
        storage.updateRepairRun(run.with().runState(RepairRun.RunState.RUNNING).build(RUN_ID));
        context.repairManager.resumeRunningRepairRuns();
        Thread.sleep(1000);
        assertEquals(RepairRun.RunState.DONE, storage.getRepairRun(RUN_ID).get().getRunState());
    }

    @Test
    public void getPossibleParallelRepairsTest() throws Exception {
        Map<List<String>, List<String>> map = RepairRunnerTest.threeNodeCluster();
        Map<String, String> endpointsThreeNodes = RepairRunnerTest.threeNodeClusterEndpoint();
        assertEquals(1, RepairRunner.getPossibleParallelRepairsCount(map, endpointsThreeNodes));

        map = RepairRunnerTest.sixNodeCluster();
        Map<String, String> endpointsSixNodes = RepairRunnerTest.sixNodeClusterEndpoint();
        assertEquals(2, RepairRunner.getPossibleParallelRepairsCount(map, endpointsSixNodes));
    }

    @Test
    public void getParallelSegmentsTest() throws ReaperException {
        List<BigInteger> tokens = Lists.transform(Lists.newArrayList("0", "50", "100", "150", "200", "250"),
                (string) -> new BigInteger(string));

        SegmentGenerator generator = new SegmentGenerator(new BigInteger("0"), new BigInteger("299"));
        List<Segment> segments = generator.generateSegments(32, tokens, Boolean.FALSE,
                RepairRunService.buildReplicasToRangeMap(RepairRunnerTest.sixNodeCluster()), "2.2.10");

        Map<List<String>, List<String>> map = RepairRunnerTest.sixNodeCluster();
        Map<String, String> endpointsSixNodes = RepairRunnerTest.sixNodeClusterEndpoint();
        List<RingRange> ranges = RepairRunner.getParallelRanges(
                RepairRunner.getPossibleParallelRepairsCount(map, endpointsSixNodes),
                Lists.newArrayList(Collections2.transform(segments, segment -> segment.getBaseRange())));
        assertEquals(2, ranges.size());
        assertEquals("0", ranges.get(0).getStart().toString());
        assertEquals("150", ranges.get(0).getEnd().toString());
        assertEquals("150", ranges.get(1).getStart().toString());
        assertEquals("0", ranges.get(1).getEnd().toString());
    }

    @Test
    public void getParallelSegmentsTest2() throws ReaperException {
        List<BigInteger> tokens = Lists.transform(
                Lists.newArrayList("0", "25", "50", "75", "100", "125", "150", "175", "200", "225", "250"),
                (string) -> new BigInteger(string));

        SegmentGenerator generator = new SegmentGenerator(new BigInteger("0"), new BigInteger("299"));

        Map<List<String>, List<String>> map = RepairRunnerTest.sixNodeCluster();
        Map<String, String> endpointsSixNodes = RepairRunnerTest.sixNodeClusterEndpoint();
        List<Segment> segments = generator.generateSegments(32, tokens, Boolean.FALSE,
                RepairRunService.buildReplicasToRangeMap(map), "2.2.10");
        List<RingRange> ranges = RepairRunner.getParallelRanges(
                RepairRunner.getPossibleParallelRepairsCount(map, endpointsSixNodes),
                Lists.newArrayList(Collections2.transform(segments, segment -> segment.getBaseRange())));
        assertEquals(2, ranges.size());
        assertEquals("0", ranges.get(0).getStart().toString());
        assertEquals("150", ranges.get(0).getEnd().toString());
        assertEquals("150", ranges.get(1).getStart().toString());
        assertEquals("0", ranges.get(1).getEnd().toString());
    }

    @Test
    public void getNoSegmentCoalescingTest() throws ReaperException {
        List<BigInteger> tokens = Lists.transform(
                Lists.newArrayList("0", "25", "50", "75", "100", "125", "150", "175", "200", "225", "250"),
                (string) -> new BigInteger(string));

        SegmentGenerator generator = new SegmentGenerator(new BigInteger("0"), new BigInteger("299"));

        Map<List<String>, List<String>> map = RepairRunnerTest.sixNodeCluster();
        List<Segment> segments = generator.generateSegments(6, tokens, Boolean.FALSE,
                RepairRunService.buildReplicasToRangeMap(map), "2.1.17");

        assertEquals(11, segments.size());
    }

    @Test
    public void getSegmentCoalescingTest() throws ReaperException {
        List<BigInteger> tokens = Lists.transform(
                Lists.newArrayList("0", "25", "50", "75", "100", "125", "150", "175", "200", "225", "250"),
                (string) -> new BigInteger(string));

        SegmentGenerator generator = new SegmentGenerator(new BigInteger("0"), new BigInteger("299"));

        Map<List<String>, List<String>> map = RepairRunnerTest.sixNodeCluster();
        List<Segment> segments = generator.generateSegments(6, tokens, Boolean.FALSE,
                RepairRunService.buildReplicasToRangeMap(map), "2.2.17");

        assertEquals(6, segments.size());
    }

    public static Map<List<String>, List<String>> threeNodeCluster() {
        Map<List<String>, List<String>> map = Maps.newHashMap();
        map = addRangeToMap(map, "0", "50", "a1", "a2", "a3");
        map = addRangeToMap(map, "50", "100", "a2", "a3", "a1");
        map = addRangeToMap(map, "100", "0", "a3", "a1", "a2");
        return map;
    }

    public static Map<List<String>, List<String>> sixNodeCluster() {
        Map<List<String>, List<String>> map = Maps.newLinkedHashMap();
        map = addRangeToMap(map, "0", "50", "a1", "a2", "a3");
        map = addRangeToMap(map, "50", "100", "a2", "a3", "a4");
        map = addRangeToMap(map, "100", "150", "a3", "a4", "a5");
        map = addRangeToMap(map, "150", "200", "a4", "a5", "a6");
        map = addRangeToMap(map, "200", "250", "a5", "a6", "a1");
        map = addRangeToMap(map, "250", "0", "a6", "a1", "a2");
        return map;
    }

    public static Map<String, String> threeNodeClusterEndpoint() {
        Map<String, String> map = Maps.newHashMap();
        map.put("host1", "hostId1");
        map.put("host2", "hostId2");
        map.put("host3", "hostId3");
        return map;
    }

    public static Map<String, String> sixNodeClusterEndpoint() {
        Map<String, String> map = Maps.newHashMap();
        map.put("host1", "hostId1");
        map.put("host2", "hostId2");
        map.put("host3", "hostId3");
        map.put("host4", "hostId4");
        map.put("host5", "hostId5");
        map.put("host6", "hostId6");
        return map;
    }

    private static Map<List<String>, List<String>> addRangeToMap(Map<List<String>, List<String>> map, String start,
            String end, String... hosts) {

        List<String> range = Lists.newArrayList(start, end);
        List<String> endPoints = Lists.newArrayList(hosts);
        map.put(range, endPoints);
        return map;
    }

}