cassandra/test/unit/org/apache/cassandra/schema/MemtableParamsTest.java

354 lines
15 KiB
Java

/*
* 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.schema;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.LinkedHashMap;
import java.util.Map;
import com.google.common.collect.ImmutableMap;
import org.junit.Test;
import accord.utils.Gen;
import org.apache.cassandra.config.Config;
import org.apache.cassandra.config.InheritingClass;
import org.apache.cassandra.config.ParameterizedClass;
import org.apache.cassandra.db.memtable.SkipListMemtableFactory;
import org.apache.cassandra.exceptions.ConfigurationException;
import org.apache.cassandra.utils.ClassLoadingTestSupport;
import org.apache.cassandra.utils.ConfigGenBuilder;
import static accord.utils.Property.qt;
import static org.apache.cassandra.config.YamlConfigurationLoader.fromMap;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class MemtableParamsTest
{
static final ParameterizedClass DEFAULT = SkipListMemtableFactory.CONFIGURATION;
@Test
public void testDefault()
{
Map<String, ParameterizedClass> map = MemtableParams.expandDefinitions(ImmutableMap.of());
assertEquals(ImmutableMap.of("default", DEFAULT), map);
}
@Test
public void testInvalidFactoryMethodDoesNotInitializeClass() throws Exception
{
ClassLoadingTestSupport.assertNotInitialized(MemtableFactoryInvalidReturnType.class);
assertThatThrownBy(() -> getMemtableFactory(MemtableFactoryInvalidReturnType.class))
.isInstanceOf(ConfigurationException.class)
.hasStackTraceContaining("must return");
assertThat(ClassLoadingTestSupport.wasInitialized(MemtableFactoryInvalidReturnType.class)).isFalse();
}
@Test
public void testInvalidFactoryFieldDoesNotInitializeClass() throws Exception
{
ClassLoadingTestSupport.assertNotInitialized(MemtableFactoryInvalidFieldType.class);
assertThatThrownBy(() -> getMemtableFactory(MemtableFactoryInvalidFieldType.class))
.isInstanceOf(ConfigurationException.class)
.hasStackTraceContaining("must be of type");
assertThat(ClassLoadingTestSupport.wasInitialized(MemtableFactoryInvalidFieldType.class)).isFalse();
}
private static void getMemtableFactory(Class<?> memtableClass) throws Exception
{
Method method = MemtableParams.class.getDeclaredMethod("getMemtableFactory", ParameterizedClass.class);
method.setAccessible(true);
try
{
method.invoke(null, new ParameterizedClass(memtableClass.getName()));
}
catch (InvocationTargetException e)
{
if (e.getCause() instanceof ConfigurationException)
throw (ConfigurationException) e.getCause();
throw e;
}
}
@Test
public void testDefaultRemapped()
{
Map<String, ParameterizedClass> map = MemtableParams.expandDefinitions
(
ImmutableMap.of("remap", new InheritingClass("default", null, null))
);
assertEquals(ImmutableMap.of("default", DEFAULT,
"remap", DEFAULT),
map);
}
@Test
public void testOne()
{
final InheritingClass one = new InheritingClass(null, "SkipList", null);
Map<String, ParameterizedClass> map = MemtableParams.expandDefinitions(ImmutableMap.of("one", one));
assertEquals(ImmutableMap.of("default", DEFAULT,
"one", one),
map);
}
@Test
public void testOrderingDoesNotMatter()
{
// linked hash map preserves insertion order
Map<String, InheritingClass> config = new LinkedHashMap<>();
config.put("default", new InheritingClass("trie", null, null));
config.put("abc", new InheritingClass(null, "Abc", ImmutableMap.of("c", "d")));
config.put("skiplist", new InheritingClass("skiplistOnSteroids", "SkipListMemtable", ImmutableMap.of("e", "f")));
config.put("skiplistOnSteroids", new InheritingClass("abc", null, ImmutableMap.of("a", "b")));
config.put("trie", new InheritingClass(null, "TrieMemtable", null));
Map<String, ParameterizedClass> map = MemtableParams.expandDefinitions(config);
assertEquals("TrieMemtable", map.get("default").class_name);
// this inherits abc which has c as config parameter
assertTrue(map.get("skiplistOnSteroids").parameters.containsKey("a"));
assertTrue(map.get("skiplistOnSteroids").parameters.containsKey("c"));
assertEquals(map.get("skiplistOnSteroids").class_name, config.get("abc").class_name);
// this inherits from skiplistOnSteroids which so params are carried over as well
assertTrue(map.get("skiplist").parameters.containsKey("a"));
assertTrue(map.get("skiplist").parameters.containsKey("c"));
assertTrue(map.get("skiplist").parameters.containsKey("e"));
assertEquals(map.get("skiplist").class_name, "SkipListMemtable");
Map<String, InheritingClass> config2 = new LinkedHashMap<>();
config2.put("skiplist", new InheritingClass(null, "SkipListMemtable", null));
config2.put("trie", new InheritingClass(null, "TrieMemtable", null));
config2.put("default", new InheritingClass("trie", null, null));
Map<String, ParameterizedClass> map2 = MemtableParams.expandDefinitions(config2);
assertEquals("TrieMemtable", map2.get("default").class_name);
}
@Test
public void testExtends()
{
final InheritingClass one = new InheritingClass(null, "SkipList", null);
Map<String, ParameterizedClass> map = MemtableParams.expandDefinitions
(
ImmutableMap.of("one", one,
"two", new InheritingClass("one",
null,
ImmutableMap.of("extra", "value")))
);
assertEquals(ImmutableMap.of("default", DEFAULT,
"one", one,
"two", new ParameterizedClass("SkipList",
ImmutableMap.of("extra", "value"))),
map);
}
@Test
public void testExtendsReplace()
{
final InheritingClass one = new InheritingClass(null,
"SkipList",
ImmutableMap.of("extra", "valueOne"));
Map<String, ParameterizedClass> map = MemtableParams.expandDefinitions
(
ImmutableMap.of("one", one,
"two", new InheritingClass("one",
null,
ImmutableMap.of("extra", "value")))
);
assertEquals(ImmutableMap.of("default", DEFAULT,
"one", one,
"two", new ParameterizedClass("SkipList",
ImmutableMap.of("extra", "value"))),
map);
}
@Test
public void testDoubleExtends()
{
final InheritingClass one = new InheritingClass(null, "SkipList", null);
Map<String, ParameterizedClass> map = MemtableParams.expandDefinitions
(
ImmutableMap.of("one", one,
"two", new InheritingClass("one",
null,
ImmutableMap.of("param", "valueTwo",
"extra", "value")),
"three", new InheritingClass("two",
"OtherClass",
ImmutableMap.of("param", "valueThree",
"extraThree", "three")))
);
assertEquals(ImmutableMap.of("default", DEFAULT,
"one", one,
"two", new ParameterizedClass("SkipList",
ImmutableMap.of("param", "valueTwo",
"extra", "value")),
"three", new ParameterizedClass("OtherClass",
ImmutableMap.of("param", "valueThree",
"extra", "value",
"extraThree", "three"))),
map);
}
@Test
public void testInvalidSelfExtends()
{
try
{
Map<String, ParameterizedClass> map = MemtableParams.expandDefinitions
(
ImmutableMap.of("one", new InheritingClass("one",
null,
ImmutableMap.of("extra", "value")))
);
fail("Expected exception.");
}
catch (ConfigurationException e)
{
// expected
}
}
@Test
public void testReplaceDefault()
{
final InheritingClass one = new InheritingClass(null,
"SkipList",
ImmutableMap.of("extra", "valueOne"));
Map<String, ParameterizedClass> map = MemtableParams.expandDefinitions(ImmutableMap.of("default", one));
assertEquals(ImmutableMap.of("default", one), map);
}
@Test
public void testDefaultExtends()
{
final InheritingClass one = new InheritingClass(null,
"SkipList",
ImmutableMap.of("extra", "valueOne"));
Map<String, ParameterizedClass> map = MemtableParams.expandDefinitions
(
ImmutableMap.of("one", one,
"default", new InheritingClass("one", null, ImmutableMap.of()))
);
assertEquals(ImmutableMap.of("one", one,
"default", one),
map);
}
// Note: The factories constructed from these parameters are tested in the CreateTest and AlterTest.
@Test
public void testExpandDefinitions()
{
Gen<Map<String, InheritingClass>> gen = new ConfigGenBuilder()
.buildMemtable()
.map(m -> fromMap(m, Config.class))
.map(c -> c.memtable.configurations);
qt().forAll(gen).check(configs -> {
Map<String, ParameterizedClass> result = MemtableParams.expandDefinitions(configs);
assertThat(result.keySet()).isEqualTo(configs.keySet());
for (Map.Entry<String, InheritingClass> e : configs.entrySet()) {
if (e.getValue().inherits == null) continue;
ParameterizedClass parent = result.get(e.getValue().inherits);
ParameterizedClass src = result.get(e.getKey());
assertThat(src.class_name).isEqualTo(parent.class_name);
assertThat(src.parameters).isEqualTo(parent.parameters);
}
});
}
@Test
public void testInheritsNonExistent()
{
try
{
Map<String, ParameterizedClass> map = MemtableParams.expandDefinitions
(
ImmutableMap.of("one", new InheritingClass("two",
null,
ImmutableMap.of("extra", "value")),
"two", new InheritingClass("three",
null,
ImmutableMap.of("extra2", "value2")))
);
fail("Expected exception.");
}
catch (ConfigurationException e)
{
// expected
}
}
@Test
public void testInvalidLoops()
{
try
{
Map<String, ParameterizedClass> map = MemtableParams.expandDefinitions
(
ImmutableMap.of("one", new InheritingClass("two",
null,
ImmutableMap.of("extra", "value")),
"two", new InheritingClass("one",
null,
ImmutableMap.of("extra2", "value2")))
);
fail("Expected exception.");
}
catch (ConfigurationException e)
{
// expected
}
try
{
Map<String, ParameterizedClass> map = MemtableParams.expandDefinitions
(
ImmutableMap.of("one", new InheritingClass("two",
null,
ImmutableMap.of("extra", "value")),
"two", new InheritingClass("three",
null,
ImmutableMap.of("extra2", "value2")),
"three", new InheritingClass("one",
null,
ImmutableMap.of("extra3", "value3")))
);
fail("Expected exception.");
}
catch (ConfigurationException e)
{
// expected
}
}
}