io.mesosphere.mesos.frameworks.cassandra.scheduler.CassandraSchedulerTest.java Source code

Java tutorial

Introduction

Here is the source code for io.mesosphere.mesos.frameworks.cassandra.scheduler.CassandraSchedulerTest.java

Source

/**
 *    Copyright (C) 2015 Mesosphere, Inc.
 *
 * 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.mesosphere.mesos.frameworks.cassandra.scheduler;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Function;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.protobuf.InvalidProtocolBufferException;
import io.mesosphere.mesos.frameworks.cassandra.CassandraFrameworkProtos;
import io.mesosphere.mesos.frameworks.cassandra.CassandraFrameworkProtos.TaskResources;
import io.mesosphere.mesos.util.CassandraFrameworkProtosUtils;
import io.mesosphere.mesos.util.ProtoUtils;
import io.mesosphere.mesos.util.SystemClock;
import org.apache.mesos.Protos;
import org.junit.Test;

import java.util.*;

import static com.google.common.collect.ImmutableList.of;
import static com.google.common.collect.Lists.newArrayList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.*;

public class CassandraSchedulerTest extends AbstractCassandraSchedulerTest {
    @Test
    public void testReregistration() throws Exception {
        threeNodeCluster();

        List<CassandraFrameworkProtos.CassandraNode> nodes = cluster.getClusterState().nodes();
        assertThat(nodes).hasSize(3);
        for (final CassandraFrameworkProtos.CassandraNode node : nodes) {
            assertNotNull(node);
            final CassandraFrameworkProtos.CassandraNodeExecutor exec = node.getCassandraNodeExecutor();
            assertNotNull(exec);
            assertThat(nodes).isNotEmpty();
            for (final CassandraFrameworkProtos.FileDownload down : exec.getDownloadList()) {
                assertThat(down.getDownloadUrl()).startsWith("http://127.0.0.1:65535/");
            }
        }

        scheduler.disconnected(driver);

        //

        cluster = new CassandraCluster(new SystemClock(), "http://127.42.42.42:42", new ExecutorCounter(state, 0L),
                new PersistedCassandraClusterState(state), new PersistedCassandraClusterHealthCheckHistory(state),
                new PersistedCassandraClusterJobs(state), configuration,
                new SeedManager(configuration, new ObjectMapper(), new SystemClock()));
        clusterState = cluster.getClusterState();
        scheduler = new CassandraScheduler(configuration, cluster, clock);
        driver = new MockSchedulerDriver(scheduler);

        driver.callReRegistered();

        nodes = cluster.getClusterState().nodes();
        assertThat(nodes).hasSize(3);
        for (final CassandraFrameworkProtos.CassandraNode node : nodes) {
            assertNotNull(node);
            final CassandraFrameworkProtos.CassandraNodeExecutor exec = node.getCassandraNodeExecutor();
            assertNotNull(exec);
            assertThat(nodes).isNotEmpty();
            for (final CassandraFrameworkProtos.FileDownload down : exec.getDownloadList()) {
                assertThat(down.getDownloadUrl()).startsWith("http://127.0.0.1:65535/");
            }
        }

    }

    @Test
    public void testIsLiveNode() throws Exception {
        cleanState();

        final CassandraFrameworkProtos.CassandraNode.Builder node = CassandraFrameworkProtos.CassandraNode
                .newBuilder().setHostname("bart").setIp("1.2.3.4").setSeed(false)
                .setTargetRunState(CassandraFrameworkProtos.CassandraNode.TargetRunState.RUN)
                .setJmxConnect(CassandraFrameworkProtos.JmxConnect.newBuilder().setIp("1.2.3.4").setJmxPort(7199));

        assertFalse(node.hasCassandraNodeExecutor());
        assertFalse(cluster.isLiveNode(node.build()));

        node.setCassandraNodeExecutor(CassandraFrameworkProtos.CassandraNodeExecutor.newBuilder().addCommand("cmd")
                .setResources(someResources()).setExecutorId("exec").setSource("src"));

        assertTrue(node.hasCassandraNodeExecutor());
        assertNull(CassandraFrameworkProtosUtils.getTaskForNode(node.build(),
                CassandraFrameworkProtos.CassandraNodeTask.NodeTaskType.SERVER));
        assertFalse(cluster.isLiveNode(node.build()));

        node.addTasks(CassandraFrameworkProtos.CassandraNodeTask.newBuilder().setResources(someResources())
                .setTaskId("task").setType(CassandraFrameworkProtos.CassandraNodeTask.NodeTaskType.SERVER));

        assertNotNull(CassandraFrameworkProtosUtils.getTaskForNode(node.build(),
                CassandraFrameworkProtos.CassandraNodeTask.NodeTaskType.SERVER));
        assertFalse(cluster.isLiveNode(node.build()));

        final CassandraFrameworkProtos.HealthCheckDetails.Builder hcd = CassandraFrameworkProtos.HealthCheckDetails
                .newBuilder().setHealthy(false);
        cluster.recordHealthCheck("exec", hcd.build());
        assertNotNull(cluster.lastHealthCheck("exec"));
        assertFalse(cluster.isLiveNode(node.build()));

        hcd.setHealthy(true);
        cluster.recordHealthCheck("exec", hcd.build());
        assertNotNull(cluster.lastHealthCheck("exec"));
        assertFalse(cluster.isLiveNode(node.build()));

        final CassandraFrameworkProtos.NodeInfo.Builder ni = CassandraFrameworkProtos.NodeInfo.newBuilder();
        hcd.setInfo(ni);
        cluster.recordHealthCheck("exec", hcd.build());
        assertFalse(cluster.isLiveNode(node.build()));

        ni.setRpcServerRunning(true);
        hcd.setInfo(ni);
        cluster.recordHealthCheck("exec", hcd.build());
        assertFalse(cluster.isLiveNode(node.build()));

        ni.setNativeTransportRunning(true);
        hcd.setInfo(ni);
        cluster.recordHealthCheck("exec", hcd.build());
        assertTrue(cluster.isLiveNode(node.build()));
    }

    @Test
    public void testGetPortMapping() {
        CassandraFrameworkProtos.CassandraFrameworkConfiguration config = CassandraFrameworkProtos.CassandraFrameworkConfiguration
                .newBuilder()
                .setDefaultConfigRole(CassandraFrameworkProtos.CassandraConfigRole.newBuilder()
                        .setResources(resources(1, 2048, 2048)))
                .setFrameworkName("a name").setHealthCheckIntervalSeconds(10).setBootstrapGraceTimeSeconds(10)
                .build();

        try {
            CassandraCluster.getPortMapping(config, "foobar");
            fail();
        } catch (final IllegalArgumentException e) {
            // OK
        }

        assertEquals(7199, CassandraCluster.getPortMapping(config, CassandraCluster.PORT_JMX));
        assertEquals(9042, CassandraCluster.getPortMapping(config, CassandraCluster.PORT_NATIVE));
        assertEquals(9160, CassandraCluster.getPortMapping(config, CassandraCluster.PORT_RPC));
        assertEquals(7000, CassandraCluster.getPortMapping(config, CassandraCluster.PORT_STORAGE));
        assertEquals(7001, CassandraCluster.getPortMapping(config, CassandraCluster.PORT_STORAGE_SSL));

        config = CassandraFrameworkProtos.CassandraFrameworkConfiguration.newBuilder()
                .setDefaultConfigRole(CassandraFrameworkProtos.CassandraConfigRole.newBuilder()
                        .setResources(resources(1, 2048, 2048)))
                .setFrameworkName("a name").setHealthCheckIntervalSeconds(10).setBootstrapGraceTimeSeconds(10)
                .addPortMapping(CassandraFrameworkProtos.PortMapping.newBuilder().setName(CassandraCluster.PORT_JMX)
                        .setPort(1))
                .addPortMapping(CassandraFrameworkProtos.PortMapping.newBuilder()
                        .setName(CassandraCluster.PORT_NATIVE).setPort(2))
                .addPortMapping(CassandraFrameworkProtos.PortMapping.newBuilder().setName(CassandraCluster.PORT_RPC)
                        .setPort(3))
                .addPortMapping(CassandraFrameworkProtos.PortMapping.newBuilder()
                        .setName(CassandraCluster.PORT_STORAGE).setPort(4))
                .addPortMapping(CassandraFrameworkProtos.PortMapping.newBuilder()
                        .setName(CassandraCluster.PORT_STORAGE_SSL).setPort(5))
                .build();

        assertEquals(1, CassandraCluster.getPortMapping(config, CassandraCluster.PORT_JMX));
        assertEquals(2, CassandraCluster.getPortMapping(config, CassandraCluster.PORT_NATIVE));
        assertEquals(3, CassandraCluster.getPortMapping(config, CassandraCluster.PORT_RPC));
        assertEquals(4, CassandraCluster.getPortMapping(config, CassandraCluster.PORT_STORAGE));
        assertEquals(5, CassandraCluster.getPortMapping(config, CassandraCluster.PORT_STORAGE_SSL));
    }

    @Test
    public void testMetadataForExecutor() {
        cleanState();

        clusterState.executorMetadata(Arrays.asList(
                CassandraFrameworkProtos.ExecutorMetadata.newBuilder().setExecutorId("exec1").setIp("1.1.1.1")
                        .setWorkdir("/foo").build(),
                CassandraFrameworkProtos.ExecutorMetadata.newBuilder().setExecutorId("exec2").setIp("2.2.2.2")
                        .setWorkdir("/bar").build()));

        assertNull(cluster.metadataForExecutor("none"));

        CassandraFrameworkProtos.ExecutorMetadata em = cluster.metadataForExecutor("exec1");
        assertNotNull(em);
        assertEquals("/foo", em.getWorkdir());

        em = cluster.metadataForExecutor("exec2");
        assertNotNull(em);
        assertEquals("/bar", em.getWorkdir());

        cluster.removeExecutor("exec1");

        assertNull(cluster.metadataForExecutor("none"));
        assertNull(cluster.metadataForExecutor("exec1"));

        em = cluster.metadataForExecutor("exec2");
        assertNotNull(em);
        assertEquals("/bar", em.getWorkdir());
    }

    @Test
    public void testNodeLogFiles() {
        cleanState();

        final CassandraFrameworkProtos.CassandraNode node1 = CassandraFrameworkProtos.CassandraNode.newBuilder()
                .setIp("1.1.1.1").setHostname("host1")
                .setJmxConnect(CassandraFrameworkProtos.JmxConnect.newBuilder().setJmxPort(1).setIp("1.1.1.1"))
                .setSeed(true).setTargetRunState(CassandraFrameworkProtos.CassandraNode.TargetRunState.RUN)
                .setCassandraNodeExecutor(CassandraFrameworkProtos.CassandraNodeExecutor.newBuilder()
                        .setResources(someResources()).setSource("src").setExecutorId("host1"))
                .build();
        final CassandraFrameworkProtos.CassandraNode node2 = CassandraFrameworkProtos.CassandraNode.newBuilder()
                .setIp("2.2.2.2").setHostname("host2")
                .setJmxConnect(CassandraFrameworkProtos.JmxConnect.newBuilder().setJmxPort(1).setIp("2.2.2.2"))
                .setSeed(true).setTargetRunState(CassandraFrameworkProtos.CassandraNode.TargetRunState.RUN)
                .setCassandraNodeExecutor(CassandraFrameworkProtos.CassandraNodeExecutor.newBuilder()
                        .setResources(someResources()).setSource("src").setExecutorId("host2"))
                .build();

        clusterState.nodes(Arrays.asList(node1, node2));

        clusterState.executorMetadata(Arrays.asList(
                CassandraFrameworkProtos.ExecutorMetadata.newBuilder().setExecutorId("host1").setIp("1.1.1.1")
                        .setWorkdir("/foo").build(),
                CassandraFrameworkProtos.ExecutorMetadata.newBuilder().setExecutorId("host2").setIp("2.2.2.2")
                        .setWorkdir("/bar").build()));

        assertThat(cluster.getNodeLogFiles(node1)).hasSize(2).contains("/foo/executor.log",
                "/foo/apache-cassandra-2.1.4/logs/system.log");

        assertThat(cluster.getNodeLogFiles(node2)).hasSize(2).contains("/bar/executor.log",
                "/bar/apache-cassandra-2.1.4/logs/system.log");
    }

    @Test
    public void testServerProcessPid() {
        cleanState();

        final CassandraFrameworkProtos.CassandraNode node1 = CassandraFrameworkProtos.CassandraNode.newBuilder()
                .setIp("1.1.1.1").setHostname("host1")
                .setJmxConnect(CassandraFrameworkProtos.JmxConnect.newBuilder().setJmxPort(1).setIp("1.1.1.1"))
                .setSeed(true).setTargetRunState(CassandraFrameworkProtos.CassandraNode.TargetRunState.RUN)
                .setCassandraNodeExecutor(CassandraFrameworkProtos.CassandraNodeExecutor.newBuilder()
                        .setResources(someResources()).setSource("src").setExecutorId("host1"))
                .build();
        final CassandraFrameworkProtos.CassandraNode node2 = CassandraFrameworkProtos.CassandraNode.newBuilder()
                .setIp("2.2.2.2").setHostname("host2")
                .setJmxConnect(CassandraFrameworkProtos.JmxConnect.newBuilder().setJmxPort(1).setIp("2.2.2.2"))
                .setSeed(true).setTargetRunState(CassandraFrameworkProtos.CassandraNode.TargetRunState.RUN)
                .setCassandraNodeExecutor(CassandraFrameworkProtos.CassandraNodeExecutor.newBuilder()
                        .setResources(someResources()).setSource("src").setExecutorId("host2"))
                .build();

        clusterState.nodes(Arrays.asList(node1, node2));

        cluster.updateCassandraProcess(Protos.ExecutorID.newBuilder().setValue("host1").build(),
                CassandraFrameworkProtos.CassandraServerRunMetadata.newBuilder().setPid(123).build());

        CassandraFrameworkProtos.CassandraNode node = cluster.findNode("1.1.1.1");
        assertNotNull(node);
        assertTrue(node.hasCassandraDaemonPid());
        assertEquals(123, node.getCassandraDaemonPid());

        node = cluster.findNode("2.2.2.2");
        assertNotNull(node);
        assertFalse(node.hasCassandraDaemonPid());

        cluster.updateCassandraProcess(Protos.ExecutorID.newBuilder().setValue("host2").build(),
                CassandraFrameworkProtos.CassandraServerRunMetadata.newBuilder().setPid(456).build());

        node = cluster.findNode("host2");
        assertNotNull(node);
        assertTrue(node.hasCassandraDaemonPid());
        assertEquals(456, node.getCassandraDaemonPid());

        cluster.updateCassandraProcess(Protos.ExecutorID.newBuilder().setValue("42-is-not-true").build(),
                CassandraFrameworkProtos.CassandraServerRunMetadata.newBuilder().setPid(999).build());
    }

    @Test
    public void testNodeAndExecutorForTask() {
        cleanState();

        clusterState
                .nodes(Arrays.asList(
                        CassandraFrameworkProtos.CassandraNode.newBuilder().setIp("1.1.1.1").setHostname("host1")
                                .setJmxConnect(CassandraFrameworkProtos.JmxConnect.newBuilder().setJmxPort(1)
                                        .setIp("1.1.1.1"))
                                .setSeed(true)
                                .setTargetRunState(CassandraFrameworkProtos.CassandraNode.TargetRunState.RUN)
                                .addTasks(CassandraFrameworkProtos.CassandraNodeTask.newBuilder()
                                        .setTaskId("host1.task1")
                                        .setType(CassandraFrameworkProtos.CassandraNodeTask.NodeTaskType.SERVER)
                                        .setResources(someResources()))
                                .addTasks(CassandraFrameworkProtos.CassandraNodeTask.newBuilder()
                                        .setTaskId("host1.task2")
                                        .setType(CassandraFrameworkProtos.CassandraNodeTask.NodeTaskType.METADATA)
                                        .setResources(someResources()))
                                .setCassandraNodeExecutor(CassandraFrameworkProtos.CassandraNodeExecutor
                                        .newBuilder().setResources(someResources()).setSource("src")
                                        .setExecutorId("host1"))
                                .build(),
                        CassandraFrameworkProtos.CassandraNode.newBuilder().setIp("2.2.2.2").setHostname("host2")
                                .setJmxConnect(CassandraFrameworkProtos.JmxConnect.newBuilder().setJmxPort(1)
                                        .setIp("2.2.2.2"))
                                .setSeed(true)
                                .setTargetRunState(CassandraFrameworkProtos.CassandraNode.TargetRunState.RUN)
                                .addTasks(CassandraFrameworkProtos.CassandraNodeTask.newBuilder()
                                        .setTaskId("host2.task1")
                                        .setType(CassandraFrameworkProtos.CassandraNodeTask.NodeTaskType.SERVER)
                                        .setResources(someResources()))
                                .addTasks(CassandraFrameworkProtos.CassandraNodeTask.newBuilder()
                                        .setTaskId("host2.task2")
                                        .setType(CassandraFrameworkProtos.CassandraNodeTask.NodeTaskType.METADATA)
                                        .setResources(someResources()))
                                .setCassandraNodeExecutor(CassandraFrameworkProtos.CassandraNodeExecutor
                                        .newBuilder().setResources(someResources()).setSource("src")
                                        .setExecutorId("host2"))
                                .build()));

        assertFalse(cluster.getNodeForTask("foo").isPresent());
        assertFalse(cluster.getExecutorIdForTask("foo").isPresent());

        assertTrue(cluster.getNodeForTask("host1.task1").isPresent());
        assertTrue(cluster.getExecutorIdForTask("host2.task1").isPresent());

        assertEquals("1.1.1.1", cluster.getNodeForTask("host1.task1").get().getIp());
        assertEquals("host1", cluster.getExecutorIdForTask("host1.task1").get());

        assertEquals("2.2.2.2", cluster.getNodeForTask("host2.task2").get().getIp());
        assertEquals("host2", cluster.getExecutorIdForTask("host2.task2").get());

        //

        cluster.removeTask("host2.task1",
                Protos.TaskStatus.newBuilder().setSource(Protos.TaskStatus.Source.SOURCE_EXECUTOR)
                        .setExecutorId(Protos.ExecutorID.newBuilder().setValue("host2")).setMessage("msg")
                        .setReason(Protos.TaskStatus.Reason.REASON_TASK_UNKNOWN)
                        .setSlaveId(Protos.SlaveID.newBuilder().setValue("slave2"))
                        .setTaskId(Protos.TaskID.newBuilder().setValue("host2.task1")).setTimestamp(1d)
                        .setState(Protos.TaskState.TASK_FAILED).build());

        assertFalse(cluster.getNodeForTask("host2.task1").isPresent());
        assertFalse(cluster.getExecutorIdForTask("host2.task1").isPresent());

        CassandraFrameworkProtos.CassandraNode node = cluster.findNode("host1");
        assertNotNull(node);
        assertFalse(node.getTasksList().isEmpty());

        assertTrue(cluster.getNodeForTask("host1.task1").isPresent());
        assertTrue(cluster.getExecutorIdForTask("host1.task1").isPresent());

        cluster.removeExecutor("host1");

        node = cluster.findNode("host1");
        assertNotNull(node);
        assertTrue(node.getTasksList().isEmpty());

        assertFalse(cluster.getNodeForTask("host1.task1").isPresent());
        assertFalse(cluster.getExecutorIdForTask("host1.task1").isPresent());
    }

    @Test
    public void testHasResources() {
        Protos.Offer offer = Protos.Offer.newBuilder().setHostname("host1")
                .setId(Protos.OfferID.newBuilder().setValue("offer"))
                .setSlaveId(Protos.SlaveID.newBuilder().setValue("slave"))
                .setFrameworkId(Protos.FrameworkID.newBuilder().setValue("frw1")).build();

        List<String> errs = CassandraCluster.hasResources(offer, resources(0, 0, 0),
                Collections.<String, Long>emptyMap(), "*");
        assertNotNull(errs);
        assertThat(errs).isEmpty();

        Locale.setDefault(Locale.ENGLISH); // required for correct float comparison!

        errs = CassandraCluster.hasResources(offer, resources(1, 2, 3), new HashMap<String, Long>() {
            {
                put("port1", 1L);
                put("port2", 2L);
                put("port3", 3L);
            }
        }, "ROLE");
        assertNotNull(errs);
        assertThat(errs).hasSize(6).contains(
                "Not enough cpu resources for role ROLE. Required 1.0 only 0.0 available",
                "Not enough mem resources for role ROLE. Required 2 only 0 available",
                "Not enough disk resources for role ROLE. Required 3 only 0 available",
                "Unavailable port 1(port1) for role ROLE. 0 other ports available",
                "Unavailable port 2(port2) for role ROLE. 0 other ports available",
                "Unavailable port 3(port3) for role ROLE. 0 other ports available");

        offer = Protos.Offer.newBuilder().setHostname("host1").setId(Protos.OfferID.newBuilder().setValue("offer"))
                .setSlaveId(Protos.SlaveID.newBuilder().setValue("slave"))
                .setFrameworkId(Protos.FrameworkID.newBuilder().setValue("frw1"))
                .addResources(Protos.Resource.newBuilder().setName("cpus").setRole("*")
                        .setType(Protos.Value.Type.SCALAR).setScalar(Protos.Value.Scalar.newBuilder().setValue(8d)))
                .addResources(
                        Protos.Resource.newBuilder().setName("mem").setRole("*").setType(Protos.Value.Type.SCALAR)
                                .setScalar(Protos.Value.Scalar.newBuilder().setValue(8192)))
                .addResources(
                        Protos.Resource.newBuilder().setName("disk").setRole("*").setType(Protos.Value.Type.SCALAR)
                                .setScalar(Protos.Value.Scalar.newBuilder().setValue(8192)))
                .addResources(
                        Protos.Resource.newBuilder().setName("ports").setRole("*").setType(Protos.Value.Type.RANGES)
                                .setRanges(Protos.Value.Ranges.newBuilder()
                                        .addRange(Protos.Value.Range.newBuilder().setBegin(7000).setEnd(10000))))
                .build();

        errs = CassandraCluster.hasResources(offer, resources(8, 8192, 8192), new HashMap<String, Long>() {
            {
                put("port1", 7000L);
                put("port2", 7002L);
                put("port3", 10000L);
            }
        }, "*");
        assertNotNull(errs);
        assertThat(errs).isEmpty();

        offer = Protos.Offer.newBuilder().setHostname("host1").setId(Protos.OfferID.newBuilder().setValue("offer"))
                .setSlaveId(Protos.SlaveID.newBuilder().setValue("slave"))
                .setFrameworkId(Protos.FrameworkID.newBuilder().setValue("frw1"))
                .addResources(Protos.Resource.newBuilder().setName("cpus").setRole("BAZ")
                        .setType(Protos.Value.Type.SCALAR).setScalar(Protos.Value.Scalar.newBuilder().setValue(8d)))
                .addResources(
                        Protos.Resource.newBuilder().setName("mem").setRole("BAZ").setType(Protos.Value.Type.SCALAR)
                                .setScalar(Protos.Value.Scalar.newBuilder().setValue(8192)))
                .addResources(Protos.Resource.newBuilder().setName("disk").setRole("BAZ")
                        .setType(Protos.Value.Type.SCALAR)
                        .setScalar(Protos.Value.Scalar.newBuilder().setValue(8192)))
                .addResources(
                        Protos.Resource.newBuilder().setName("ports").setRole("BAZ")
                                .setType(Protos.Value.Type.RANGES)
                                .setRanges(Protos.Value.Ranges.newBuilder()
                                        .addRange(Protos.Value.Range.newBuilder().setBegin(7000).setEnd(10000))))
                .build();

        errs = CassandraCluster.hasResources(offer, resources(8, 8192, 8192), new HashMap<String, Long>() {
            {
                put("port1", 7000L);
                put("port2", 7002L);
                put("port3", 10000L);
            }
        }, "BAZ");
        assertNotNull(errs);
        assertThat(errs).isEmpty();

        errs = CassandraCluster.hasResources(offer, resources(8, 8192, 8192), new HashMap<String, Long>() {
            {
                put("port1", 7000L);
                put("port2", 7002L);
                put("port3", 10000L);
            }
        }, "FOO_BAR");
        assertNotNull(errs);
        assertThat(errs).hasSize(6).contains(
                "Not enough cpu resources for role FOO_BAR. Required 8.0 only 0.0 available",
                "Not enough mem resources for role FOO_BAR. Required 8192 only 0 available",
                "Not enough disk resources for role FOO_BAR. Required 8192 only 0 available",
                "Unavailable port 7000(port1) for role FOO_BAR. 0 other ports available",
                "Unavailable port 7002(port2) for role FOO_BAR. 0 other ports available",
                "Unavailable port 10000(port3) for role FOO_BAR. 0 other ports available");

        offer = Protos.Offer.newBuilder().setHostname("host1").setId(Protos.OfferID.newBuilder().setValue("offer"))
                .setSlaveId(Protos.SlaveID.newBuilder().setValue("slave"))
                .setFrameworkId(Protos.FrameworkID.newBuilder().setValue("frw1"))
                .addResources(Protos.Resource.newBuilder().setName("cpus").setRole("*")
                        .setType(Protos.Value.Type.SCALAR).setScalar(Protos.Value.Scalar.newBuilder().setValue(8d)))
                .addResources(
                        Protos.Resource.newBuilder().setName("mem").setRole("*").setType(Protos.Value.Type.SCALAR)
                                .setScalar(Protos.Value.Scalar.newBuilder().setValue(8192)))
                .addResources(
                        Protos.Resource.newBuilder().setName("disk").setRole("*").setType(Protos.Value.Type.SCALAR)
                                .setScalar(Protos.Value.Scalar.newBuilder().setValue(8192)))
                .addResources(
                        Protos.Resource.newBuilder().setName("ports").setRole("*").setType(Protos.Value.Type.RANGES)
                                .setRanges(Protos.Value.Ranges.newBuilder()
                                        .addRange(Protos.Value.Range.newBuilder().setBegin(5000).setEnd(6000))))
                .addResources(
                        Protos.Resource.newBuilder().setName("ports").setRole("BAZ")
                                .setType(Protos.Value.Type.RANGES)
                                .setRanges(Protos.Value.Ranges.newBuilder()
                                        .addRange(Protos.Value.Range.newBuilder().setBegin(7000).setEnd(10000))))
                .build();

        errs = CassandraCluster.hasResources(offer, resources(8, 8192, 8192), new HashMap<String, Long>() {
            {
                put("port1", 7000L);
                put("port2", 7002L);
                put("port3", 10000L);
            }
        }, "BAZ");
        assertNotNull(errs);
        assertThat(errs).isEmpty();

        offer = Protos.Offer.newBuilder().setHostname("host1").setId(Protos.OfferID.newBuilder().setValue("offer"))
                .setSlaveId(Protos.SlaveID.newBuilder().setValue("slave"))
                .setFrameworkId(Protos.FrameworkID.newBuilder().setValue("frw1"))
                .addResources(Protos.Resource.newBuilder().setName("cpus").setRole("*")
                        .setType(Protos.Value.Type.SCALAR).setScalar(Protos.Value.Scalar.newBuilder().setValue(1d)))
                .addResources(Protos.Resource.newBuilder().setName("cpus").setRole("BAZ")
                        .setType(Protos.Value.Type.SCALAR).setScalar(Protos.Value.Scalar.newBuilder().setValue(8d)))
                .addResources(
                        Protos.Resource.newBuilder().setName("mem").setRole("*").setType(Protos.Value.Type.SCALAR)
                                .setScalar(Protos.Value.Scalar.newBuilder().setValue(100)))
                .addResources(
                        Protos.Resource.newBuilder().setName("mem").setRole("BAZ").setType(Protos.Value.Type.SCALAR)
                                .setScalar(Protos.Value.Scalar.newBuilder().setValue(8192)))
                .addResources(Protos.Resource.newBuilder().setName("disk").setRole("*")
                        .setType(Protos.Value.Type.SCALAR).setScalar(Protos.Value.Scalar.newBuilder().setValue(10)))
                .addResources(Protos.Resource.newBuilder().setName("disk").setRole("BAZ")
                        .setType(Protos.Value.Type.SCALAR)
                        .setScalar(Protos.Value.Scalar.newBuilder().setValue(8192)))
                .addResources(
                        Protos.Resource.newBuilder().setName("ports").setRole("*").setType(Protos.Value.Type.RANGES)
                                .setRanges(Protos.Value.Ranges.newBuilder()
                                        .addRange(Protos.Value.Range.newBuilder().setBegin(5000).setEnd(6000))))
                .addResources(
                        Protos.Resource.newBuilder().setName("ports").setRole("BAZ")
                                .setType(Protos.Value.Type.RANGES)
                                .setRanges(Protos.Value.Ranges.newBuilder()
                                        .addRange(Protos.Value.Range.newBuilder().setBegin(7000).setEnd(10000))))
                .build();

        errs = CassandraCluster.hasResources(offer, resources(8, 8192, 8192), new HashMap<String, Long>() {
            {
                put("port1", 7000L);
                put("port2", 7002L);
                put("port3", 10000L);
            }
        }, "BAZ");
        assertNotNull(errs);
        assertThat(errs).isEmpty();
    }

    @Test
    public void testHasResource_floatingPointPrecision() throws Exception {
        final Protos.Offer offer = Protos.Offer.newBuilder().setHostname("host1")
                .setId(Protos.OfferID.newBuilder().setValue("offer"))
                .setSlaveId(Protos.SlaveID.newBuilder().setValue("slave"))
                .setFrameworkId(Protos.FrameworkID.newBuilder().setValue("frw1"))
                .addResources(ProtoUtils.cpu(0.09999999999999981, "*")).addResources(ProtoUtils.mem(1024, "*"))
                .addResources(ProtoUtils.disk(1024, "*")).build();
        final TaskResources resources = resources(0.1, 500, 500);

        assertThat(CassandraCluster.hasResources(offer, resources, Collections.<String, Long>emptyMap(), "*"))
                .contains("Not enough cpu resources for role *. Required 0.1 only 0.09999999999999981 available");
    }

    @Test
    public void testGetTaskName_nameSpecified() throws Exception {
        assertThat(CassandraScheduler.getTaskName("name", "task")).isEqualTo("name");
    }

    @Test
    public void testGetTaskName_nameNull() throws Exception {
        assertThat(CassandraScheduler.getTaskName(null, "task")).isEqualTo("task");
    }

    @Test
    public void testGetTaskName_nameEmpty() throws Exception {
        assertThat(CassandraScheduler.getTaskName("", "task")).isEqualTo("task");
    }

    @Test
    public void testGetTaskName_nameEmptyAfterTrim() throws Exception {
        assertThat(CassandraScheduler.getTaskName("   \t", "task")).isEqualTo("task");
    }

    @Test
    public void testResourceList_includesDiskAbove0() throws Exception {
        final List<Protos.Resource> resources = CassandraScheduler.resourceList(
                TaskResources.newBuilder().setCpuCores(0.5).setMemMb(512).setDiskMb(1).build(), "*",
                Protos.Offer.getDefaultInstance());

        assertThat(resources).hasSize(3);
        assertThat(resources).contains(ProtoUtils.cpu(0.5, "*"));
        assertThat(resources).contains(ProtoUtils.mem(512, "*"));
        assertThat(resources).contains(ProtoUtils.disk(1, "*"));
    }

    @Test
    public void testResourceList_doesNotIncludesDiskWhen0() throws Exception {
        final List<Protos.Resource> resources = CassandraScheduler.resourceList(
                TaskResources.newBuilder().setCpuCores(0.5).setMemMb(512).setDiskMb(0).build(), "*",
                Protos.Offer.getDefaultInstance());

        assertThat(resources).hasSize(2);
        assertThat(resources).contains(ProtoUtils.cpu(0.5, "*"));
        assertThat(resources).contains(ProtoUtils.mem(512, "*"));
        assertThat(resources).doesNotContain(ProtoUtils.disk(0, "*"));
    }

    @Test
    public void testResourceList_doesNotIncludesDiskWhenBelow0() throws Exception {
        final List<Protos.Resource> resources = CassandraScheduler.resourceList(
                TaskResources.newBuilder().setCpuCores(0.5).setMemMb(512).setDiskMb(-1).build(), "*",
                Protos.Offer.getDefaultInstance());

        assertThat(resources).hasSize(2);
        assertThat(resources).contains(ProtoUtils.cpu(0.5, "*"));
        assertThat(resources).contains(ProtoUtils.mem(512, "*"));
        assertThat(resources).doesNotContain(ProtoUtils.disk(-1, "*"));
    }

    @Test
    public void testResourceList_doesReturnResourcesWithTheRoleFromOffers() {
        Protos.Offer offer = Protos.Offer.newBuilder().setFrameworkId(frameworkId).setHostname("somehost.name")
                .setId(Protos.OfferID.newBuilder().setValue(randomID()))
                .setSlaveId(Protos.SlaveID.newBuilder().setValue("someslave").build())
                .addResources(Protos.Resource.newBuilder().setName("cpus").setRole("*")
                        .setType(Protos.Value.Type.SCALAR).setScalar(Protos.Value.Scalar.newBuilder().setValue(8d)))
                .addResources(Protos.Resource.newBuilder().setName("mem").setRole("someRole")
                        .setType(Protos.Value.Type.SCALAR)
                        .setScalar(Protos.Value.Scalar.newBuilder().setValue(8192)))
                .addResources(
                        Protos.Resource.newBuilder().setName("disk").setRole("*").setType(Protos.Value.Type.SCALAR)
                                .setScalar(Protos.Value.Scalar.newBuilder().setValue(8192)))
                .build();

        final List<Protos.Resource> resources = CassandraScheduler.resourceList(
                TaskResources.newBuilder().setCpuCores(0.5).setMemMb(512).setDiskMb(1000).build(), "someRole",
                offer);

        assertThat(resources).hasSize(3);
        assertThat(resources).contains(ProtoUtils.cpu(0.5, "*"));
        assertThat(resources).contains(ProtoUtils.mem(512, "someRole"));
        assertThat(resources).contains(ProtoUtils.disk(1000, "*"));
    }

    @Test
    public void testResourceList_doesReturnResourcesWithTheRoleFromResourceOfferThatMatchesRequriements() {
        Protos.Offer offer = Protos.Offer.newBuilder().setFrameworkId(frameworkId).setHostname("somehost.name")
                .setId(Protos.OfferID.newBuilder().setValue(randomID()))
                .setSlaveId(Protos.SlaveID.newBuilder().setValue("someslave").build())
                .addResources(Protos.Resource.newBuilder().setName("cpus").setRole("*")
                        .setType(Protos.Value.Type.SCALAR).setScalar(Protos.Value.Scalar.newBuilder().setValue(8d)))
                .addResources(Protos.Resource.newBuilder().setName("mem").setRole("someRole")
                        .setType(Protos.Value.Type.SCALAR)
                        .setScalar(Protos.Value.Scalar.newBuilder().setValue(100)))
                .addResources(
                        Protos.Resource.newBuilder().setName("mem").setRole("*").setType(Protos.Value.Type.SCALAR)
                                .setScalar(Protos.Value.Scalar.newBuilder().setValue(8192)))
                .addResources(
                        Protos.Resource.newBuilder().setName("disk").setRole("*").setType(Protos.Value.Type.SCALAR)
                                .setScalar(Protos.Value.Scalar.newBuilder().setValue(8192)))
                .build();

        final List<Protos.Resource> resources = CassandraScheduler.resourceList(
                TaskResources.newBuilder().setCpuCores(0.5).setMemMb(512).setDiskMb(1000).build(), "someRole",
                offer);

        assertThat(resources).hasSize(3);
        assertThat(resources).contains(ProtoUtils.cpu(0.5, "*"));
        assertThat(resources).contains(ProtoUtils.mem(512, "*"));
        assertThat(resources).contains(ProtoUtils.disk(1000, "*"));
    }

    @Test
    public void testPorts_doesReturnPortsWithTheRoleFromOffers() {
        Protos.Offer offer = Protos.Offer.newBuilder().setFrameworkId(frameworkId).setHostname("somehost.name")
                .setId(Protos.OfferID.newBuilder().setValue(randomID()))
                .setSlaveId(Protos.SlaveID.newBuilder().setValue("someslave").build())
                .addResources(Protos.Resource.newBuilder().setName("cpus").setRole("*")
                        .setType(Protos.Value.Type.SCALAR).setScalar(Protos.Value.Scalar.newBuilder().setValue(8d)))
                .addResources(
                        Protos.Resource.newBuilder().setName("mem").setRole("*").setType(Protos.Value.Type.SCALAR)
                                .setScalar(Protos.Value.Scalar.newBuilder().setValue(8192)))
                .addResources(
                        Protos.Resource.newBuilder().setName("disk").setRole("*").setType(Protos.Value.Type.SCALAR)
                                .setScalar(Protos.Value.Scalar.newBuilder().setValue(8192)))
                .addResources(
                        Protos.Resource.newBuilder().setName("ports").setRole("*").setType(Protos.Value.Type.RANGES)
                                .setRanges(Protos.Value.Ranges.newBuilder()
                                        .addRange(Protos.Value.Range.newBuilder().setBegin(7000).setEnd(10000))))
                .build();

        ImmutableList<Long> ports = of(8080l, 9090l);
        List<Protos.Resource> resources = CassandraScheduler.ports(ports, "someRole", offer);

        Protos.Resource expectedPortsResource = Protos.Resource.newBuilder().setName("ports").setRole("*")
                .setType(Protos.Value.Type.RANGES)
                .setRanges(Protos.Value.Ranges.newBuilder().addRange(rangeOfOne(8080)).addRange(rangeOfOne(9090)))
                .build();
        assertThat(resources).hasSize(1);
        assertThat(resources).contains(expectedPortsResource);
    }

    @Test
    public void testPorts_doesReturnResourcesWithPortsFromSeveralPartsOfTheOffer() {
        Protos.Offer offer = Protos.Offer.newBuilder().setFrameworkId(frameworkId).setHostname("somehost.name")
                .setId(Protos.OfferID.newBuilder().setValue(randomID()))
                .setSlaveId(Protos.SlaveID.newBuilder().setValue("someslave").build())
                .addResources(Protos.Resource.newBuilder().setName("cpus").setRole("*")
                        .setType(Protos.Value.Type.SCALAR).setScalar(Protos.Value.Scalar.newBuilder().setValue(8d)))
                .addResources(
                        Protos.Resource.newBuilder().setName("mem").setRole("*").setType(Protos.Value.Type.SCALAR)
                                .setScalar(Protos.Value.Scalar.newBuilder().setValue(8192)))
                .addResources(
                        Protos.Resource.newBuilder().setName("disk").setRole("*").setType(Protos.Value.Type.SCALAR)
                                .setScalar(Protos.Value.Scalar.newBuilder().setValue(8192)))
                .addResources(
                        Protos.Resource.newBuilder().setName("ports").setRole("*").setType(Protos.Value.Type.RANGES)
                                .setRanges(Protos.Value.Ranges.newBuilder()
                                        .addRange(Protos.Value.Range.newBuilder().setBegin(7000).setEnd(9000))))
                .addResources(
                        Protos.Resource.newBuilder().setName("ports").setRole("someRole")
                                .setType(Protos.Value.Type.RANGES)
                                .setRanges(Protos.Value.Ranges.newBuilder()
                                        .addRange(Protos.Value.Range.newBuilder().setBegin(9000).setEnd(10000))))
                .build();

        List<Protos.Resource> resources = CassandraScheduler.ports(of(8080l, 9090l), "someRole", offer);

        Protos.Resource expectedResourceForPort8080 = Protos.Resource.newBuilder().setName("ports").setRole("*")
                .setType(Protos.Value.Type.RANGES)
                .setRanges(Protos.Value.Ranges.newBuilder().addRange(rangeOfOne(8080))).build();
        Protos.Resource expectedResourceForPort9090 = Protos.Resource.newBuilder().setName("ports")
                .setRole("someRole").setType(Protos.Value.Type.RANGES)
                .setRanges(Protos.Value.Ranges.newBuilder().addRange(rangeOfOne(9090))).build();

        assertThat(resources).hasSize(2);
        assertThat(resources).contains(expectedResourceForPort8080, expectedResourceForPort9090);
    }

    @Test
    public void testResourceOffers_canHandleOffersWithMixedRoles() throws InvalidProtocolBufferException {
        cleanState("someOtherRole");
        Protos.Offer offer = createOffer(slaves[0]);

        scheduler.resourceOffers(driver, newArrayList(offer));

        Collection<Protos.TaskInfo> launchedTasks = driver.launchTasks()._2;
        assertThat(launchedTasks).isNotEmpty();
        Protos.TaskInfo launchedTask = launchedTasks.iterator().next();
        List<Protos.Resource> resources = launchedTask.getResourcesList();
        ImmutableListMultimap<String, Protos.Resource> resourceMap = FluentIterable.from(resources)
                .index(resourceByName());

        Protos.Resource cpus = resourceMap.get("cpus").get(0);
        assertThat(cpus.getRole()).isEqualTo("*");
        assertThat(cpus.getScalar().getValue()).isEqualTo(0.1);

        Protos.Resource mem = resourceMap.get("mem").get(0);
        assertThat(mem.getRole()).isEqualTo("*");
        assertThat(mem.getScalar().getValue()).isEqualTo(32.0);
    }

    private Function<Protos.Resource, String> resourceByName() {
        return new Function<Protos.Resource, String>() {
            @Override
            public String apply(Protos.Resource resource) {
                return resource.getName();
            }
        };
    }

    private Protos.Value.Range rangeOfOne(int value) {
        return Protos.Value.Range.newBuilder().setBegin(value).setEnd(value).build();
    }

}