This is an automated email from the ASF dual-hosted git repository.

dcapwell pushed a commit to branch cassandra-2.2
in repository https://gitbox.apache.org/repos/asf/cassandra.git


The following commit(s) were added to refs/heads/cassandra-2.2 by this push:
     new db58321  In-JVM dtest - modify schema with stopped nodes and use yaml 
fragments for config
db58321 is described below

commit db5832120f0fe9ad799ca0b5b16bbcf6f7404580
Author: Jon Meredith <[email protected]>
AuthorDate: Thu Oct 22 10:54:55 2020 -0700

    In-JVM dtest - modify schema with stopped nodes and use yaml fragments for 
config
    
    patch by Jon Meredith; reviewed by Alex Petrov, David Capwell, Dinesh 
Joshi, Yifan Cai for CASSANDRA-16152
---
 .../cassandra/config/ParameterizedClass.java       |  5 ++
 .../cassandra/config/YamlConfigurationLoader.java  | 63 +++++++++++++++
 .../distributed/impl/AbstractCluster.java          | 44 +++++++++--
 .../cassandra/distributed/impl/Instance.java       | 19 +++--
 .../cassandra/distributed/impl/InstanceConfig.java | 49 +++---------
 .../cassandra/distributed/test/JVMDTestTest.java   | 91 +++++++++++++++++++++-
 .../config/YamlConfigurationLoaderTest.java        | 54 +++++++++++++
 7 files changed, 267 insertions(+), 58 deletions(-)

diff --git a/src/java/org/apache/cassandra/config/ParameterizedClass.java 
b/src/java/org/apache/cassandra/config/ParameterizedClass.java
index 6b7af63..7ec2c18 100644
--- a/src/java/org/apache/cassandra/config/ParameterizedClass.java
+++ b/src/java/org/apache/cassandra/config/ParameterizedClass.java
@@ -28,6 +28,11 @@ public class ParameterizedClass
     public String class_name;
     public Map<String, String> parameters;
 
+    public ParameterizedClass()
+    {
+        // for snakeyaml
+    }
+
     public ParameterizedClass(String class_name, Map<String, String> 
parameters)
     {
         this.class_name = class_name;
diff --git a/src/java/org/apache/cassandra/config/YamlConfigurationLoader.java 
b/src/java/org/apache/cassandra/config/YamlConfigurationLoader.java
index dc691c4..07b149c 100644
--- a/src/java/org/apache/cassandra/config/YamlConfigurationLoader.java
+++ b/src/java/org/apache/cassandra/config/YamlConfigurationLoader.java
@@ -24,11 +24,15 @@ import java.io.InputStream;
 import java.io.IOException;
 import java.net.URL;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
 
 import com.google.common.base.Joiner;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
 import com.google.common.io.ByteStreams;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -36,10 +40,14 @@ import org.slf4j.LoggerFactory;
 import org.apache.cassandra.exceptions.ConfigurationException;
 import org.yaml.snakeyaml.TypeDescription;
 import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.composer.Composer;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.constructor.CustomClassLoaderConstructor;
 import org.yaml.snakeyaml.error.YAMLException;
 import org.yaml.snakeyaml.introspector.MissingProperty;
 import org.yaml.snakeyaml.introspector.Property;
 import org.yaml.snakeyaml.introspector.PropertyUtils;
+import org.yaml.snakeyaml.nodes.Node;
 
 public class YamlConfigurationLoader implements ConfigurationLoader
 {
@@ -119,6 +127,61 @@ public class YamlConfigurationLoader implements 
ConfigurationLoader
         }
     }
 
+    @SuppressWarnings("unchecked") //getSingleData returns Object, not T
+    public static <T> T fromMap(Map<String,Object> map, Class<T> klass)
+    {
+        Constructor constructor = new 
YamlConfigurationLoader.CustomConstructor(klass, klass.getClassLoader());
+        YamlConfigurationLoader.MissingPropertiesChecker propertiesChecker = 
new YamlConfigurationLoader.MissingPropertiesChecker();
+        constructor.setPropertyUtils(propertiesChecker);
+        Yaml yaml = new Yaml(constructor);
+        Node node = yaml.represent(map);
+        constructor.setComposer(new Composer(null, null)
+        {
+            @Override
+            public Node getSingleNode()
+            {
+                return node;
+            }
+        });
+        return (T) constructor.getSingleData(klass);
+    }
+
+    static class CustomConstructor extends CustomClassLoaderConstructor
+    {
+        CustomConstructor(Class<?> theRoot, ClassLoader classLoader)
+        {
+            super(theRoot, classLoader);
+
+            TypeDescription seedDesc = new 
TypeDescription(ParameterizedClass.class);
+            seedDesc.putMapPropertyType("parameters", String.class, 
String.class);
+            addTypeDescription(seedDesc);
+        }
+
+        @Override
+        protected List<Object> createDefaultList(int initSize)
+        {
+            return Lists.newCopyOnWriteArrayList();
+        }
+
+        @Override
+        protected Map<Object, Object> createDefaultMap()
+        {
+            return Maps.newConcurrentMap();
+        }
+
+        @Override
+        protected Set<Object> createDefaultSet(int initSize)
+        {
+            return Sets.newConcurrentHashSet();
+        }
+
+        @Override
+        protected Set<Object> createDefaultSet()
+        {
+            return Sets.newConcurrentHashSet();
+        }
+    }
+
     private static class MissingPropertiesChecker extends PropertyUtils
     {
         private final Set<String> missingProperties = new HashSet<>();
diff --git 
a/test/distributed/org/apache/cassandra/distributed/impl/AbstractCluster.java 
b/test/distributed/org/apache/cassandra/distributed/impl/AbstractCluster.java
index cb55d3e..5f2b624 100644
--- 
a/test/distributed/org/apache/cassandra/distributed/impl/AbstractCluster.java
+++ 
b/test/distributed/org/apache/cassandra/distributed/impl/AbstractCluster.java
@@ -330,7 +330,7 @@ public abstract class AbstractCluster<I extends IInstance> 
implements ICluster<I
         NetworkTopology topology = NetworkTopology.build(ipPrefix, 
broadcastPort, nodeIdTopology);
 
         InstanceConfig config = InstanceConfig.generate(nodeNum, ipAddress, 
topology, root, String.valueOf(token), seedIp, datadirCount);
-        config.set("dtest.api.cluster_id", clusterId);
+        config.set("dtest.api.cluster_id", clusterId.toString());
         if (configUpdater != null)
             configUpdater.accept(config);
 
@@ -387,6 +387,12 @@ public abstract class AbstractCluster<I extends IInstance> 
implements ICluster<I
         return instanceMap.get(addr);
     }
 
+    public I getFirstRunningInstance()
+    {
+        return stream().filter(i -> !i.isShutdown()).findFirst().orElseThrow(
+            () -> new IllegalStateException("All instances are shutdown"));
+    }
+
     public int size()
     {
         return instances.size();
@@ -459,11 +465,31 @@ public abstract class AbstractCluster<I extends 
IInstance> implements ICluster<I
 
     public void schemaChange(String query)
     {
-        get(1).sync(() -> {
+        schemaChange(query, false);
+    }
+
+    /**
+     * Change the schema of the cluster, tolerating stopped nodes.  N.B. the 
schema
+     * will not automatically be updated when stopped nodes are restarted, 
individual tests need to
+     * re-synchronize somehow (by gossip or some other mechanism).
+     * @param query Schema altering statement
+     */
+    public void schemaChangeIgnoringStoppedInstances(String query)
+    {
+        schemaChange(query, true);
+    }
+
+    private void schemaChange(String query, boolean ignoreStoppedInstances)
+    {
+        I instance = ignoreStoppedInstances ? getFirstRunningInstance() : 
get(1);
+
+        instance.sync(() -> {
             try (SchemaChangeMonitor monitor = new SchemaChangeMonitor())
             {
                 // execute the schema change
-                coordinator(1).execute(query, ConsistencyLevel.ALL);
+                instance.coordinator().execute(query, ConsistencyLevel.ALL);
+                if (ignoreStoppedInstances)
+                    monitor.ignoreStoppedInstances();
                 monitor.waitForCompletion();
             }
         }).run();
@@ -498,16 +524,23 @@ public abstract class AbstractCluster<I extends 
IInstance> implements ICluster<I
         final SimpleCondition completed;
         private final long timeOut;
         private final TimeUnit timeoutUnit;
+        protected Predicate<IInstance> instanceFilter;
         volatile boolean changed;
 
         public ChangeMonitor(long timeOut, TimeUnit timeoutUnit)
         {
             this.timeOut = timeOut;
             this.timeoutUnit = timeoutUnit;
+            this.instanceFilter = i -> true;
             this.cleanup = new ArrayList<>(instances.size());
             this.completed = new SimpleCondition();
         }
 
+        public void ignoreStoppedInstances()
+        {
+            instanceFilter = instanceFilter.and(i -> !i.isShutdown());
+        }
+
         protected void signal()
         {
             if (changed && isCompleted())
@@ -539,8 +572,7 @@ public abstract class AbstractCluster<I extends IInstance> 
implements ICluster<I
 
         private void startPolling()
         {
-            for (IInstance instance : instances)
-                cleanup.add(startPolling(instance));
+            instances.stream().filter(instanceFilter).forEach(instance -> 
cleanup.add(startPolling(instance)));
         }
 
         protected abstract IListen.Cancel startPolling(IInstance instance);
@@ -575,7 +607,7 @@ public abstract class AbstractCluster<I extends IInstance> 
implements ICluster<I
 
         protected boolean isCompleted()
         {
-            return 1 == 
instances.stream().map(IInstance::schemaVersion).distinct().count();
+            return 1 == 
instances.stream().filter(instanceFilter).map(IInstance::schemaVersion).distinct().count();
         }
 
         protected String getMonitorTimeoutMessage()
diff --git 
a/test/distributed/org/apache/cassandra/distributed/impl/Instance.java 
b/test/distributed/org/apache/cassandra/distributed/impl/Instance.java
index 2159e03..13179c0 100644
--- a/test/distributed/org/apache/cassandra/distributed/impl/Instance.java
+++ b/test/distributed/org/apache/cassandra/distributed/impl/Instance.java
@@ -52,6 +52,7 @@ import org.apache.cassandra.concurrent.StageManager;
 import org.apache.cassandra.config.Config;
 import org.apache.cassandra.config.DatabaseDescriptor;
 import org.apache.cassandra.config.Schema;
+import org.apache.cassandra.config.YamlConfigurationLoader;
 import org.apache.cassandra.cql3.CQLStatement;
 import org.apache.cassandra.cql3.QueryOptions;
 import org.apache.cassandra.cql3.QueryProcessor;
@@ -119,13 +120,6 @@ import static 
org.apache.cassandra.distributed.api.Feature.NATIVE_PROTOCOL;
 
 public class Instance extends IsolatedExecutor implements IInvokableInstance
 {
-    private static final Map<Class<?>, Function<Object, Object>> mapper = new 
HashMap<Class<?>, Function<Object, Object>>() {{
-        this.put(IInstanceConfig.ParameterizedClass.class, (obj) -> {
-            IInstanceConfig.ParameterizedClass pc = 
(IInstanceConfig.ParameterizedClass) obj;
-            return new 
org.apache.cassandra.config.ParameterizedClass(pc.class_name, pc.parameters);
-        });
-    }};
-
     public final IInstanceConfig config;
 
     // should never be invoked directly, so that it is instantiated on other 
class loader;
@@ -270,6 +264,9 @@ public class Instance extends IsolatedExecutor implements 
IInvokableInstance
         {
             public boolean allowOutgoingMessage(MessageOut message, int id, 
InetAddress toAddress)
             {
+                if (isShutdown())
+                    return false;
+
                 // Port is not passed in, so take a best guess at the 
destination port from this instance
                 IInstance to = 
cluster.get(NetworkTopology.addressAndPort(toAddress,
                                                                           
instance.config().broadcastAddress().getPort()));
@@ -282,6 +279,9 @@ public class Instance extends IsolatedExecutor implements 
IInvokableInstance
 
             public boolean allowIncomingMessage(MessageIn message, int id)
             {
+                if (isShutdown())
+                    return false;
+
                 // Port is not passed in, so take a best guess at the 
destination port from this instance
                 IInstance from = 
cluster.get(NetworkTopology.addressAndPort(message.from,
                                                                             
instance.config().broadcastAddress().getPort()));
@@ -624,9 +624,8 @@ public class Instance extends IsolatedExecutor implements 
IInvokableInstance
 
     private static Config loadConfig(IInstanceConfig overrides)
     {
-        Config config = new Config();
-        overrides.propagate(config, mapper);
-        return config;
+        Map<String,Object> params = ((InstanceConfig) overrides).getParams();
+        return YamlConfigurationLoader.fromMap(params, Config.class);
     }
 
     private void initializeRing(ICluster cluster)
diff --git 
a/test/distributed/org/apache/cassandra/distributed/impl/InstanceConfig.java 
b/test/distributed/org/apache/cassandra/distributed/impl/InstanceConfig.java
index 4e8a782..861e2ea 100644
--- a/test/distributed/org/apache/cassandra/distributed/impl/InstanceConfig.java
+++ b/test/distributed/org/apache/cassandra/distributed/impl/InstanceConfig.java
@@ -30,16 +30,19 @@ import java.util.TreeMap;
 import java.util.UUID;
 import java.util.function.Function;
 
+import org.apache.cassandra.config.YamlConfigurationLoader;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import org.apache.cassandra.distributed.api.Feature;
 import org.apache.cassandra.distributed.api.IInstanceConfig;
 import org.apache.cassandra.distributed.shared.NetworkTopology;
+import org.apache.cassandra.distributed.shared.Shared;
 import org.apache.cassandra.distributed.shared.Versions;
 import org.apache.cassandra.locator.InetAddressAndPort;
 import org.apache.cassandra.locator.SimpleSeedProvider;
 
+@Shared
 public class InstanceConfig implements IInstanceConfig
 {
     private static final Object NULL = new Object();
@@ -198,8 +201,7 @@ public class InstanceConfig implements IInstanceConfig
 
     public void propagate(Object writeToConfig, Map<Class<?>, Function<Object, 
Object>> mapping)
     {
-        for (Map.Entry<String, Object> e : params.entrySet())
-            propagate(writeToConfig, e.getKey(), e.getValue(), mapping);
+        throw new IllegalStateException("In-JVM dtests no longer support 
propagate");
     }
 
     public void validate()
@@ -208,44 +210,6 @@ public class InstanceConfig implements IInstanceConfig
             throw new IllegalArgumentException("In-JVM dtests do not support 
vnodes as of now.");
     }
 
-    private void propagate(Object writeToConfig, String fieldName, Object 
value, Map<Class<?>, Function<Object, Object>> mapping)
-    {
-        if (value == NULL)
-            value = null;
-
-        if (mapping != null && mapping.containsKey(value.getClass()))
-            value = mapping.get(value.getClass()).apply(value);
-
-        Class<?> configClass = writeToConfig.getClass();
-        Field valueField;
-        try
-        {
-            valueField = configClass.getDeclaredField(fieldName);
-        }
-        catch (NoSuchFieldException e)
-        {
-            logger.warn("No such field: {} in config class {}", fieldName, 
configClass);
-            return;
-        }
-
-        if (valueField.getType().isEnum() && value instanceof String)
-        {
-            String test = (String) value;
-            value = Arrays.stream(valueField.getType().getEnumConstants())
-                    .filter(e -> ((Enum<?>)e).name().equals(test))
-                    .findFirst()
-                    .get();
-        }
-        try
-        {
-            valueField.set(writeToConfig, value);
-        }
-        catch (IllegalAccessException | IllegalArgumentException e)
-        {
-            throw new IllegalStateException(e);
-        }
-    }
-
     public Object get(String name)
     {
         return params.get(name);
@@ -261,6 +225,11 @@ public class InstanceConfig implements IInstanceConfig
         return (String)params.get(name);
     }
 
+    public Map<String, Object> getParams()
+    {
+        return params;
+    }
+
     public static InstanceConfig generate(int nodeNum, String ipAddress, 
NetworkTopology networkTopology, File root, String token, String seedIp, int 
datadirCount)
     {
         return new InstanceConfig(nodeNum,
diff --git 
a/test/distributed/org/apache/cassandra/distributed/test/JVMDTestTest.java 
b/test/distributed/org/apache/cassandra/distributed/test/JVMDTestTest.java
index 3a1a0a8..7e5d99a 100644
--- a/test/distributed/org/apache/cassandra/distributed/test/JVMDTestTest.java
+++ b/test/distributed/org/apache/cassandra/distributed/test/JVMDTestTest.java
@@ -19,15 +19,22 @@
 package org.apache.cassandra.distributed.test;
 
 import java.io.IOException;
+import java.util.Collections;
 import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
+import java.util.concurrent.TimeUnit;
 import java.util.logging.Logger;
 
 import org.junit.Assert;
+import com.google.common.collect.ImmutableMap;
 import org.junit.Test;
 
 import org.slf4j.LoggerFactory;
 
+import org.apache.cassandra.config.Config;
+import org.apache.cassandra.config.DatabaseDescriptor;
 import org.apache.cassandra.distributed.Cluster;
 import org.apache.cassandra.distributed.api.ConsistencyLevel;
 import org.apache.cassandra.distributed.api.Feature;
@@ -35,7 +42,11 @@ import org.apache.cassandra.distributed.api.LogAction;
 import org.apache.cassandra.service.CassandraDaemon;
 import org.apache.cassandra.utils.FBUtilities;
 
+import static org.apache.cassandra.distributed.shared.AssertUtils.assertRows;
+import static org.apache.cassandra.distributed.shared.AssertUtils.row;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 public class JVMDTestTest extends TestBaseImpl
@@ -66,7 +77,7 @@ public class JVMDTestTest extends TestBaseImpl
         try (Cluster cluster = init(Cluster.build(2).withConfig(c -> 
c.with(Feature.values())).start()))
         {
             // debug logging is turned on so we will see debug logs
-            
Assert.assertFalse(cluster.get(1).logs().grep("^DEBUG").getResult().isEmpty());
+            
assertFalse(cluster.get(1).logs().grep("^DEBUG").getResult().isEmpty());
             // make sure an exception is thrown in the cluster
             LogAction logs = cluster.get(2).logs();
             long mark = logs.mark(); // get the current position so watching 
doesn't see any previous exceptions
@@ -75,7 +86,83 @@ public class JVMDTestTest extends TestBaseImpl
                 LoggerFactory.getLogger(CassandraDaemon.class).error("Error", 
new RuntimeException("fail without fail"));
             });
             List<String> errors = logs.watchFor(mark, "^ERROR").getResult();
-            Assert.assertFalse(errors.isEmpty());
+            assertFalse(errors.isEmpty());
+        }
+    }
+
+    @Test
+    public void nonSharedConfigClassTest() throws IOException
+    {
+        Map<String,Object> commitLogCompression = 
ImmutableMap.of("class_name", "org.apache.cassandra.io.compress.LZ4Compressor",
+                                                                  
"parameters", Collections.<String,Object>emptyMap());
+        Map<String,Object> encryptionOptions = 
ImmutableMap.of("cipher_suites", Collections.singletonList("FakeCipher"),
+                                                               "optional", 
false,
+                                                               "enabled", 
false);
+
+        try (Cluster cluster = Cluster.build(1)
+                                      .withConfig(c -> {
+                                          c.set("concurrent_reads", 321);
+                                          c.set("internode_compression", 
Config.InternodeCompression.dc);
+                                          c.set("client_encryption_options", 
encryptionOptions);
+                                          c.set("commitlog_compression", 
commitLogCompression);
+                                      }).start())
+        {
+            cluster.get(1).runOnInstance(() -> {
+                assertEquals(321, DatabaseDescriptor.getConcurrentReaders());
+                assertEquals(Config.InternodeCompression.dc, 
DatabaseDescriptor.internodeCompression());
+                assertEquals("org.apache.cassandra.io.compress.LZ4Compressor", 
DatabaseDescriptor.getCommitLogCompression().class_name);
+                
assertTrue(DatabaseDescriptor.getCommitLogCompression().parameters.isEmpty());
+            });
+        }
+    }
+
+    @Test
+    public void modifySchemaWithStoppedNode() throws Throwable
+    {
+        try (Cluster cluster = init(Cluster.build().withNodes(2).withConfig(c 
-> c.with(Feature.GOSSIP).with(Feature.NETWORK)).start()))
+        {
+            assertFalse(cluster.get(1).isShutdown());
+            assertFalse(cluster.get(2).isShutdown());
+            cluster.schemaChangeIgnoringStoppedInstances("CREATE TABLE 
"+KEYSPACE+".tbl1 (id int primary key, i int)");
+
+            cluster.get(2).shutdown(true).get(1, TimeUnit.MINUTES);
+            assertFalse(cluster.get(1).isShutdown());
+            assertTrue(cluster.get(2).isShutdown());
+            cluster.schemaChangeIgnoringStoppedInstances("CREATE TABLE 
"+KEYSPACE+".tbl2 (id int primary key, i int)");
+
+            cluster.get(1).shutdown(true).get(1, TimeUnit.MINUTES);
+            assertTrue(cluster.get(1).isShutdown());
+            assertTrue(cluster.get(2).isShutdown());
+
+            // both nodes down, nothing to record a schema change so should 
get an exception
+            Throwable thrown = null;
+            try
+            {
+                cluster.schemaChangeIgnoringStoppedInstances("CREATE TABLE " + 
KEYSPACE + ".tblX (id int primary key, i int)");
+            }
+            catch (Throwable tr)
+            {
+                thrown = tr;
+            }
+            assertNotNull("Expected to fail with all nodes down", thrown);
+
+            // Have to restart instance1 before instance2 as it is hard-coded 
as the seed in in-JVM configuration.
+            cluster.get(1).startup();
+            cluster.get(2).startup();
+            assertFalse(cluster.get(1).isShutdown());
+            assertFalse(cluster.get(2).isShutdown());
+            cluster.schemaChangeIgnoringStoppedInstances("CREATE TABLE 
"+KEYSPACE+".tbl3 (id int primary key, i int)");
+
+            assertRows(cluster.get(1).executeInternal("SELECT 
columnfamily_name FROM system.schema_columnfamilies WHERE keyspace_name = ?", 
KEYSPACE),
+                       row("tbl1"), row("tbl2"), row("tbl3"));
+            assertRows(cluster.get(2).executeInternal("SELECT 
columnfamily_name FROM system.schema_columnfamilies WHERE keyspace_name = ?", 
KEYSPACE),
+                       row("tbl1"), row("tbl2"), row("tbl3"));
+
+            // Finally test schema can be changed with the first node down
+            cluster.get(1).shutdown(true).get(2, TimeUnit.MINUTES);
+            cluster.schemaChangeIgnoringStoppedInstances("CREATE TABLE 
"+KEYSPACE+".tbl4 (id int primary key, i int)");
+            assertRows(cluster.get(2).executeInternal("SELECT 
columnfamily_name FROM system.schema_columnfamilies WHERE keyspace_name = ?", 
KEYSPACE),
+                       row("tbl1"), row("tbl2"), row("tbl3"), row("tbl4"));
         }
     }
 }
diff --git 
a/test/unit/org/apache/cassandra/config/YamlConfigurationLoaderTest.java 
b/test/unit/org/apache/cassandra/config/YamlConfigurationLoaderTest.java
new file mode 100644
index 0000000..c132ffc
--- /dev/null
+++ b/test/unit/org/apache/cassandra/config/YamlConfigurationLoaderTest.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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.
+ */
+
+package org.apache.cassandra.config;
+
+import java.util.Collections;
+import java.util.Map;
+
+import com.google.common.collect.ImmutableMap;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertArrayEquals;
+
+
+public class YamlConfigurationLoaderTest
+{
+    @Test
+    public void fromMapTest()
+    {
+        Integer storagePort = 123;
+        Config.CommitLogSync commitLogSync = Config.CommitLogSync.batch;
+        ParameterizedClass seedProvider = new 
ParameterizedClass("org.apache.cassandra.locator.SimpleSeedProvider", 
Collections.emptyMap());
+        EncryptionOptions encryptionOptions = new 
EncryptionOptions.ClientEncryptionOptions();
+        encryptionOptions.keystore = "myNewKeystore";
+        encryptionOptions.cipher_suites = new String[] {"SomeCipher"};
+
+        Map<String,Object> map = ImmutableMap.of("storage_port", storagePort,
+                                                 "commitlog_sync", 
commitLogSync,
+                                                 "seed_provider", seedProvider,
+                                                 "client_encryption_options", 
encryptionOptions);
+        Config config = YamlConfigurationLoader.fromMap(map, Config.class);
+        assertEquals(storagePort, config.storage_port); // Check a simple 
integer
+        assertEquals(commitLogSync, config.commitlog_sync); // Check an enum
+        assertEquals(seedProvider, config.seed_provider); // Check a 
parameterized class
+        assertEquals(encryptionOptions.keystore, 
config.client_encryption_options.keystore); // Check a nested object
+        assertArrayEquals(encryptionOptions.cipher_suites, 
config.client_encryption_options.cipher_suites);
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to