Merge pull request #625 from datastax/multi-workload-support

Support multiple workloads for DSE nodes, updateDSENodeConfig
diff --git a/driver-core/src/test/java/com/datastax/driver/core/CCMAccess.java b/driver-core/src/test/java/com/datastax/driver/core/CCMAccess.java
index 37aea8f..81dbb95 100644
--- a/driver-core/src/test/java/com/datastax/driver/core/CCMAccess.java
+++ b/driver-core/src/test/java/com/datastax/driver/core/CCMAccess.java
@@ -203,11 +203,25 @@
     void updateNodeConfig(int n, Map<String, Object> configs);
 
     /**
-     * Sets the workload for the {@code nth} host in the CCM cluster.
+     * Updates the {@code nth} host's dse config file in the CCM cluster.
      *
      * @param n the node number (starting from 1).
      */
-    void setWorkload(int n, Workload workload);
+    void updateDSENodeConfig(int n, String key, Object value);
+
+    /**
+     * Updates the {@code nth} host's dse config file in the CCM cluster.
+     *
+     * @param n the node number (starting from 1).
+     */
+    void updateDSENodeConfig(int n, Map<String, Object> configs);
+
+    /**
+     * Sets the workload(s) for the {@code nth} host in the CCM cluster.
+     *
+     * @param n the node number (starting from 1).
+     */
+    void setWorkload(int n, Workload... workload);
 
 
     // Methods blocking until nodes are up or down
diff --git a/driver-core/src/test/java/com/datastax/driver/core/CCMBridge.java b/driver-core/src/test/java/com/datastax/driver/core/CCMBridge.java
index 1d0091a..e2ec35b 100644
--- a/driver-core/src/test/java/com/datastax/driver/core/CCMBridge.java
+++ b/driver-core/src/test/java/com/datastax/driver/core/CCMBridge.java
@@ -537,8 +537,27 @@
     }
 
     @Override
-    public void setWorkload(int node, Workload workload) {
-        execute(CCM_COMMAND + " node%d setworkload %s", node, workload);
+    public void updateDSENodeConfig(int n, String key, Object value) {
+        updateDSENodeConfig(n, ImmutableMap.<String, Object>builder().put(key, value).build());
+    }
+
+    @Override
+    public void updateDSENodeConfig(int n, Map<String, Object> configs) {
+        StringBuilder confStr = new StringBuilder();
+        for (Map.Entry<String, Object> entry : configs.entrySet()) {
+            confStr
+                    .append(entry.getKey())
+                    .append(":")
+                    .append(entry.getValue())
+                    .append(" ");
+        }
+        execute(CCM_COMMAND + " node%s updatedseconf %s", n, confStr);
+    }
+
+    @Override
+    public void setWorkload(int node, Workload... workload) {
+        String workloadStr = Joiner.on(",").join(workload);
+        execute(CCM_COMMAND + " node%d setworkload %s", node, workloadStr);
     }
 
     private String execute(String command, Object... args) {
@@ -673,7 +692,7 @@
         private Set<String> jvmArgs = new LinkedHashSet<String>();
         private final Map<String, Object> cassandraConfiguration = Maps.newLinkedHashMap();
         private final Map<String, Object> dseConfiguration = Maps.newLinkedHashMap();
-        private Map<Integer, Workload> workloads = new HashMap<Integer, Workload>();
+        private Map<Integer, Workload[]> workloads = new HashMap<Integer, Workload[]>();
 
         private Builder() {
             cassandraConfiguration.put("start_rpc", false);
@@ -804,10 +823,10 @@
          * Sets the DSE workload for a given node.
          *
          * @param node     The node to set the workload for (starting with 1).
-         * @param workload The workload (e.g. solr, spark, hadoop)
+         * @param workload The workload(s) (e.g. solr, spark, hadoop)
          * @return This builder
          */
-        public Builder withWorkload(int node, Workload workload) {
+        public Builder withWorkload(int node, Workload... workload) {
             this.workloads.put(node, workload);
             return this;
         }
@@ -833,7 +852,7 @@
             ccm.updateConfig(cassandraConfiguration);
             if (!dseConfiguration.isEmpty())
                 ccm.updateDSEConfig(dseConfiguration);
-            for (Map.Entry<Integer, Workload> entry : workloads.entrySet()) {
+            for (Map.Entry<Integer, Workload[]> entry : workloads.entrySet()) {
                 ccm.setWorkload(entry.getKey(), entry.getValue());
             }
             if (start)
diff --git a/driver-core/src/test/java/com/datastax/driver/core/CCMCache.java b/driver-core/src/test/java/com/datastax/driver/core/CCMCache.java
index f1d75d6..5f35686 100644
--- a/driver-core/src/test/java/com/datastax/driver/core/CCMCache.java
+++ b/driver-core/src/test/java/com/datastax/driver/core/CCMCache.java
@@ -191,7 +191,17 @@
         }
 
         @Override
-        public void setWorkload(int n, Workload workload) {
+        public void updateDSENodeConfig(int n, String key, Object value) {
+            ccm.updateDSENodeConfig(n, key, value);
+        }
+
+        @Override
+        public void updateDSENodeConfig(int n, Map<String, Object> configs) {
+            ccm.updateDSENodeConfig(n, configs);
+        }
+
+        @Override
+        public void setWorkload(int n, Workload... workload) {
             ccm.setWorkload(n, workload);
         }
 
diff --git a/driver-core/src/test/java/com/datastax/driver/core/CCMConfig.java b/driver-core/src/test/java/com/datastax/driver/core/CCMConfig.java
index 11fd6f6..75ab44c 100644
--- a/driver-core/src/test/java/com/datastax/driver/core/CCMConfig.java
+++ b/driver-core/src/test/java/com/datastax/driver/core/CCMConfig.java
@@ -135,7 +135,7 @@
      *
      * @return The workloads to assign to each node.
      */
-    CCMAccess.Workload[] workloads() default {};
+    CCMWorkload[] workloads() default {};
 
     /**
      * Returns {@code true} if a {@link CCMBridge} instance should be automatically created, {@code false} otherwise.
diff --git a/driver-core/src/test/java/com/datastax/driver/core/CCMTestsSupport.java b/driver-core/src/test/java/com/datastax/driver/core/CCMTestsSupport.java
index e46ef4b..50b7119 100644
--- a/driver-core/src/test/java/com/datastax/driver/core/CCMTestsSupport.java
+++ b/driver-core/src/test/java/com/datastax/driver/core/CCMTestsSupport.java
@@ -213,7 +213,17 @@
         }
 
         @Override
-        public void setWorkload(int node, Workload workload) {
+        public void updateDSENodeConfig(int n, String key, Object value) {
+            throw new UnsupportedOperationException("This CCM cluster is read-only");
+        }
+
+        @Override
+        public void updateDSENodeConfig(int n, Map<String, Object> configs) {
+            throw new UnsupportedOperationException("This CCM cluster is read-only");
+        }
+
+        @Override
+        public void setWorkload(int node, Workload... workload) {
             throw new UnsupportedOperationException("This CCM cluster is read-only");
         }
 
@@ -351,17 +361,17 @@
             return args;
         }
 
-        private List<Workload> workloads() {
+        private List<Workload[]> workloads() {
             int total = 0;
             for (int perDc : numberOfNodes())
                 total += perDc;
-            List<Workload> workloads = new ArrayList<Workload>(Collections.<Workload>nCopies(total, null));
+            List<Workload[]> workloads = new ArrayList<Workload[]>(Collections.<Workload[]>nCopies(total, null));
             for (int i = annotations.size() - 1; i >= 0; i--) {
                 CCMConfig ann = annotations.get(i);
-                Workload[] annWorkloads = ann.workloads();
+                CCMWorkload[] annWorkloads = ann.workloads();
                 for (int j = 0; j < annWorkloads.length; j++) {
-                    Workload workload = annWorkloads[j];
-                    workloads.set(j, workload);
+                    CCMWorkload nodeWorkloads = annWorkloads[j];
+                    workloads.set(j, nodeWorkloads.value());
                 }
             }
             return workloads;
@@ -438,9 +448,9 @@
                 for (String arg : jvmArgs()) {
                     ccmBuilder.withJvmArgs(arg);
                 }
-                List<Workload> workloads = workloads();
+                List<Workload[]> workloads = workloads();
                 for (int i = 0; i < workloads.size(); i++) {
-                    Workload workload = workloads.get(i);
+                    Workload[] workload = workloads.get(i);
                     if (workload != null)
                         ccmBuilder.withWorkload(i + 1, workload);
                 }
@@ -758,6 +768,7 @@
             }
         }
     }
+
     /**
      * Signals that the test has encountered an unexpected error.
      * <p/>
diff --git a/driver-core/src/test/java/com/datastax/driver/core/CCMWorkload.java b/driver-core/src/test/java/com/datastax/driver/core/CCMWorkload.java
new file mode 100644
index 0000000..9f0c6f7
--- /dev/null
+++ b/driver-core/src/test/java/com/datastax/driver/core/CCMWorkload.java
@@ -0,0 +1,37 @@
+/*
+ *      Copyright (C) 2012-2015 DataStax 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 com.datastax.driver.core;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * A set of workloads to assign to a specific node.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.ANNOTATION_TYPE)
+public @interface CCMWorkload {
+
+    /**
+     * The workloads to assign to a specific node.
+     *
+     * @return The workloads to assign to a specifc node.
+     */
+    CCMAccess.Workload[] value() default {};
+
+}
diff --git a/driver-core/src/test/java/com/datastax/driver/core/DseCCMClusterTest.java b/driver-core/src/test/java/com/datastax/driver/core/DseCCMClusterTest.java
index e89d587..9cbfaf9 100644
--- a/driver-core/src/test/java/com/datastax/driver/core/DseCCMClusterTest.java
+++ b/driver-core/src/test/java/com/datastax/driver/core/DseCCMClusterTest.java
@@ -17,6 +17,8 @@
 
 import org.testng.annotations.Test;
 
+import static com.datastax.driver.core.CCMAccess.Workload.*;
+
 /**
  * A simple test to validate DSE setups.
  * <p/>
@@ -68,11 +70,21 @@
  * A correct example is as follows: {@code /usr/bin:/usr/local/bin:/bin:/usr/sbin:$JAVA_HOME/bin:$PATH}.
  */
 @Test(enabled = false)
-@CCMConfig(dse = true, version = "4.8.3")
+@CCMConfig(
+        dse = true,
+        numberOfNodes = 3,
+        version = "4.8.3",
+        workloads = {
+                @CCMWorkload(solr),
+                @CCMWorkload({spark, solr}),
+                @CCMWorkload({cassandra, spark})
+        }
+)
 public class DseCCMClusterTest extends CCMTestsSupport {
 
     @Test(groups = "short")
     public void should_conenct_to_dse() throws InterruptedException {
+
     }
 
 }