blob: e97a08105f477248f8a0eead6b6fb84c5490bd3c [file] [log] [blame]
/*
* 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.distributed.test;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
import com.google.common.collect.ImmutableSet;
import org.junit.After;
import org.junit.BeforeClass;
import org.apache.cassandra.cql3.Duration;
import org.apache.cassandra.db.marshal.*;
import org.apache.cassandra.distributed.Cluster;
import org.apache.cassandra.distributed.api.ICluster;
import org.apache.cassandra.distributed.api.IInstanceConfig;
import org.apache.cassandra.distributed.api.IInvokableInstance;
import org.apache.cassandra.distributed.shared.DistributedTestBase;
import static org.apache.cassandra.config.CassandraRelevantProperties.BOOTSTRAP_SCHEMA_DELAY_MS;
import static org.apache.cassandra.distributed.action.GossipHelper.withProperty;
public class TestBaseImpl extends DistributedTestBase
{
public static final Object[][] EMPTY_ROWS = new Object[0][];
public static final boolean[] BOOLEANS = new boolean[]{ false, true };
@After
public void afterEach() {
super.afterEach();
}
@BeforeClass
public static void beforeClass() throws Throwable
{
ICluster.setup();
}
@Override
public Cluster.Builder builder() {
// This is definitely not the smartest solution, but given the complexity of the alternatives and low risk, we can just rely on the
// fact that this code is going to work accross _all_ versions.
return Cluster.build();
}
public static Object[][] rows(Object[]...rows)
{
Object[][] r = new Object[rows.length][];
System.arraycopy(rows, 0, r, 0, rows.length);
return r;
}
public static Object list(Object...values)
{
return Arrays.asList(values);
}
public static Object set(Object...values)
{
return ImmutableSet.copyOf(values);
}
public static Object map(Object...values)
{
if (values.length % 2 != 0)
throw new IllegalArgumentException("Invalid number of arguments, got " + values.length);
int size = values.length / 2;
Map<Object, Object> m = new LinkedHashMap<>(size);
for (int i = 0; i < size; i++)
m.put(values[2 * i], values[(2 * i) + 1]);
return m;
}
public static ByteBuffer tuple(Object... values)
{
ByteBuffer[] bbs = new ByteBuffer[values.length];
for (int i = 0; i < values.length; i++)
bbs[i] = makeByteBuffer(values[i]);
return TupleType.buildValue(bbs);
}
public static String batch(String... queries)
{
StringBuilder sb = new StringBuilder();
sb.append("BEGIN UNLOGGED BATCH\n");
for (String q : queries)
sb.append(q).append(";\n");
sb.append("APPLY BATCH;");
return sb.toString();
}
protected void bootstrapAndJoinNode(Cluster cluster)
{
IInstanceConfig config = cluster.newInstanceConfig();
config.set("auto_bootstrap", true);
IInvokableInstance newInstance = cluster.bootstrap(config);
withProperty(BOOTSTRAP_SCHEMA_DELAY_MS.getKey(), Integer.toString(90 * 1000),
() -> withProperty("cassandra.join_ring", false, () -> newInstance.startup(cluster)));
newInstance.nodetoolResult("join").asserts().success();
}
@SuppressWarnings("unchecked")
private static ByteBuffer makeByteBuffer(Object value)
{
if (value == null)
return null;
if (value instanceof ByteBuffer)
return (ByteBuffer) value;
return typeFor(value).decompose(value);
}
private static AbstractType typeFor(Object value)
{
if (value instanceof ByteBuffer || value == null)
return BytesType.instance;
if (value instanceof Byte)
return ByteType.instance;
if (value instanceof Short)
return ShortType.instance;
if (value instanceof Integer)
return Int32Type.instance;
if (value instanceof Long)
return LongType.instance;
if (value instanceof Float)
return FloatType.instance;
if (value instanceof Duration)
return DurationType.instance;
if (value instanceof Double)
return DoubleType.instance;
if (value instanceof BigInteger)
return IntegerType.instance;
if (value instanceof BigDecimal)
return DecimalType.instance;
if (value instanceof String)
return UTF8Type.instance;
if (value instanceof Boolean)
return BooleanType.instance;
if (value instanceof InetAddress)
return InetAddressType.instance;
if (value instanceof Date)
return TimestampType.instance;
if (value instanceof UUID)
return UUIDType.instance;
throw new IllegalArgumentException("Unsupported value type (value is " + value + ')');
}
public static void fixDistributedSchemas(Cluster cluster)
{
// These keyspaces are under replicated by default, so must be updated when doing a multi-node cluster;
// else bootstrap will fail with 'Unable to find sufficient sources for streaming range <range> in keyspace <name>'
for (String ks : Arrays.asList("system_auth", "system_traces"))
{
cluster.schemaChange("ALTER KEYSPACE " + ks + " WITH REPLICATION = {'class': 'SimpleStrategy', 'replication_factor': " + Math.min(cluster.size(), 3) + "}");
}
// in real live repair is needed in this case, but in the test case it doesn't matter if the tables loose
// anything, so ignoring repair to speed up the tests.
}
}