blob: 79b36389dbf7bfe31a021342e63f10b144f5670c [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.diff;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.google.common.collect.AbstractIterator;
import com.google.common.collect.Lists;
import com.google.common.reflect.TypeToken;
import org.junit.Test;
import com.datastax.driver.core.*;
import org.apache.cassandra.diff.PartitionComparator;
import org.apache.cassandra.diff.PartitionStats;
import org.apache.cassandra.diff.TableSpec;
import static org.junit.Assert.assertEquals;
public class PartitionComparatorTest {
@Test
public void sourceIsNull() {
TableSpec t = spec("table1", names("c1", "c2"), names("v1", "v2"));
PartitionComparator comparator = comparator(t, null, rows(row(t, 0, 1, 2, 3)));
PartitionStats stats = comparator.call();
assertStats(stats, true, true, 0, 0, 0);
}
@Test
public void targetIsNull() {
TableSpec t = spec("table1", names("c1", "c2"), names("v1", "v2"));
PartitionComparator comparator = comparator(t, rows(row(t, 0, 1, 2, 3)), null);
PartitionStats stats = comparator.call();
assertStats(stats, true, true, 0, 0, 0);
}
@Test
public void sourceIsEmpty() {
TableSpec t = spec("table1", names("c1", "c2"), names("v1", "v2"));
PartitionComparator comparator = comparator(t, rows(), rows(row(t, 0, 1, 2, 3)));
PartitionStats stats = comparator.call();
assertStats(stats, false, false, 0, 0, 0);
}
@Test
public void targetIsEmpty() {
TableSpec t = spec("table1", names("c1", "c2"), names("v1", "v2"));
PartitionComparator comparator = comparator(t, rows(row(t, 0, 1, 2, 3)), rows());
PartitionStats stats = comparator.call();
assertStats(stats, false, false, 0, 0, 0);
}
@Test
public void sourceAndTargetAreEmpty() {
TableSpec t = spec("table1", names("c1", "c2"), names("v1", "v2"));
PartitionComparator comparator = comparator(t, rows(), rows());
PartitionStats stats = comparator.call();
assertStats(stats, false, true, 0, 0, 0);
}
@Test
public void sourceContainsExtraRowsAtStart() {
TableSpec t = spec("table1", names("c1", "c2"), names("v1", "v2"));
PartitionComparator comparator = comparator(t,
rows(row(t, 0, 1, 2, 3),
row(t, 10, 11, 12, 13)),
rows(row(t, 10, 11, 12, 13)));
PartitionStats stats = comparator.call();
// Comparison fails fast, so bails on the initial mismatch
assertStats(stats, false, false, 0, 0, 0);
}
@Test
public void targetContainsExtraRowsAtStart() {
TableSpec t = spec("table1", names("c1", "c2"), names("v1", "v2"));
PartitionComparator comparator = comparator(t,
rows(row(t, 10, 11, 12, 13)),
rows(row(t, 0, 1, 2, 3),
row(t, 10, 11, 12, 13)));
PartitionStats stats = comparator.call();
// Comparison fails fast, so bails on the initial mismatch
assertStats(stats, false, false, 0, 0, 0);
}
@Test
public void sourceContainsExtraRowsAtEnd() {
TableSpec t = spec("table1", names("c1", "c2"), names("v1", "v2"));
PartitionComparator comparator = comparator(t,
rows(row(t, 0, 1, 2, 3),
row(t, 10, 11, 12, 13)),
rows(row(t, 0, 1, 2, 3)));
PartitionStats stats = comparator.call();
// The fact that the first row & all its v1 & v2 values match should be reflected in the stats
assertStats(stats, false, false, 1, 2, 0);
}
@Test
public void targetContainsExtraRowsAtEnd() {
TableSpec t = spec("table1", names("c1", "c2"), names("v1", "v2"));
PartitionComparator comparator = comparator(t,
rows(row(t, 0, 1, 2, 3)),
rows(row(t, 0, 1, 2, 3),
row(t, 10, 11, 12, 13)));
PartitionStats stats = comparator.call();
// The fact that the first row & all its v1 & v2 values match should be reflected in the stats
assertStats(stats, false, false, 1, 2, 0);
}
@Test
public void withoutClusteringsAllRowsMatching() {
TableSpec t = spec("table1", names(), names("v1", "v2"));
PartitionComparator comparator = comparator(t,
rows(row(t, 0, 1),
row(t, 1, 11),
row(t, 2, 12)),
rows(row(t, 0, 1),
row(t, 1, 11),
row(t, 2, 12)));
PartitionStats stats = comparator.call();
assertStats(stats, false, true, 3, 6, 0);
}
@Test
public void singleClusteringAllRowsMatching() {
TableSpec t = spec("table1", names("c1"), names("v1", "v2"));
PartitionComparator comparator = comparator(t,
rows(row(t, 0, 1, 2),
row(t, 1, 11, 12),
row(t, 2, 21, 22)),
rows(row(t, 0, 1, 2),
row(t, 1, 11, 12),
row(t, 2, 21, 22)));
PartitionStats stats = comparator.call();
assertStats(stats, false, true, 3, 6, 0);
}
@Test
public void multipleClusteringAllRowsMatching() {
TableSpec t = spec("table1", names("c1", "c2"), names("v1", "v2"));
PartitionComparator comparator = comparator(t,
rows(row(t, 0, 1, 2, 3),
row(t, 1, 11, 12, 13),
row(t, 2, 21, 22, 23)),
rows(row(t, 0, 1, 2, 3),
row(t, 1, 11, 12, 13),
row(t, 2, 21, 22, 23)));
PartitionStats stats = comparator.call();
assertStats(stats, false, true, 3, 6, 0);
}
@Test
public void withoutClusteringsWithMismatches() {
TableSpec t = spec("table1", names(), names("v1", "v2"));
PartitionComparator comparator = comparator(t,
rows(row(t, 0, 1),
row(t, 1, 11),
row(t, 2, 12)),
rows(row(t, 0, 1),
row(t, 1, 1100),
row(t, 2, 1200)));
PartitionStats stats = comparator.call();
assertStats(stats, false, true, 3, 4, 2);
}
@Test
public void singleClusteringWithMismatches() {
TableSpec t = spec("table1", names("c1"), names("v1", "v2"));
PartitionComparator comparator = comparator(t,
rows(row(t, 0, 1, 2),
row(t, 1, 11, 21),
row(t, 2, 12, 22)),
rows(row(t, 0, 1, 20),
row(t, 1, 1100, 21),
row(t, 2, 12, 1200)));
PartitionStats stats = comparator.call();
assertStats(stats, false, true, 3, 3, 3);
}
private void assertStats(PartitionStats stats,
boolean skipped,
boolean clusteringsMatch,
int matchedRows,
int matchedValues,
int mismatchedValues) {
assertEquals(skipped, stats.skipped);
assertEquals(clusteringsMatch, stats.allClusteringsMatch);
assertEquals(matchedRows, stats.matchedRows);
assertEquals(matchedValues, stats.matchedValues);
assertEquals(mismatchedValues, stats.mismatchedValues);
}
PartitionComparator comparator(TableSpec table, Iterator<Row> source, Iterator<Row> target) {
return new PartitionComparator(table, source, target);
}
List<String> names(String...names) {
return Lists.newArrayList(names);
}
TableSpec spec(String table, List<String> clusteringColumns, List<String> regularColumns) {
return new TableSpec(table, columns(clusteringColumns), columns(regularColumns));
}
List<ColumnMetadata> columns(List<String> names) {
return names.stream().map(ColumnMetadataHelper::column).collect(Collectors.toList());
}
Iterator<Row> rows(Row...rows) {
return new AbstractIterator<Row>() {
int i = 0;
protected Row computeNext() {
if (i < rows.length)
return rows[i++];
return endOfData();
}
};
}
Row row(TableSpec table, Object...values) {
return new TestRow(Stream.concat(table.getClusteringColumns().stream(),
table.getRegularColumns().stream())
.map(ColumnMetadata::getName).toArray(String[]::new),
values);
}
static class TestRow implements Row {
private final String[] names;
private final Object[] values;
TestRow(String[] names, Object[] values) {
if (names.length != values.length)
throw new IllegalArgumentException(String.format("Number of column names (%d) doesn't " +
"match number of values(%d)",
names.length, values.length));
this.names = names;
this.values = values;
}
// Only getObject(String) is used by PartitionComparator
public Object getObject(String s) {
for (int i=0; i < names.length; i++)
if (names[i].equals(s))
return values[i];
throw new IllegalArgumentException(s + " is not a column defined in this metadata");
}
public boolean isNull(String s) {
throw new UnsupportedOperationException();
}
public boolean getBool(String s) {
throw new UnsupportedOperationException();
}
public byte getByte(String s) {
throw new UnsupportedOperationException();
}
public short getShort(String s) {
throw new UnsupportedOperationException();
}
public int getInt(String s) {
throw new UnsupportedOperationException();
}
public long getLong(String s) {
throw new UnsupportedOperationException();
}
public Date getTimestamp(String s) {
throw new UnsupportedOperationException();
}
public LocalDate getDate(String s) {
throw new UnsupportedOperationException();
}
public long getTime(String s) {
throw new UnsupportedOperationException();
}
public float getFloat(String s) {
throw new UnsupportedOperationException();
}
public double getDouble(String s) {
throw new UnsupportedOperationException();
}
public ByteBuffer getBytesUnsafe(String s) {
throw new UnsupportedOperationException();
}
public ByteBuffer getBytes(String s) {
throw new UnsupportedOperationException();
}
public String getString(String s) {
throw new UnsupportedOperationException();
}
public BigInteger getVarint(String s) {
throw new UnsupportedOperationException();
}
public BigDecimal getDecimal(String s) {
throw new UnsupportedOperationException();
}
public UUID getUUID(String s) {
throw new UnsupportedOperationException();
}
public InetAddress getInet(String s) {
throw new UnsupportedOperationException();
}
public <T> List<T> getList(String s, Class<T> aClass) {
throw new UnsupportedOperationException();
}
public <T> List<T> getList(String s, TypeToken<T> typeToken) {
throw new UnsupportedOperationException();
}
public <T> Set<T> getSet(String s, Class<T> aClass) {
throw new UnsupportedOperationException();
}
public <T> Set<T> getSet(String s, TypeToken<T> typeToken) {
throw new UnsupportedOperationException();
}
public <K, V> Map<K, V> getMap(String s, Class<K> aClass, Class<V> aClass1) {
throw new UnsupportedOperationException();
}
public <K, V> Map<K, V> getMap(String s, TypeToken<K> typeToken, TypeToken<V> typeToken1) {
throw new UnsupportedOperationException();
}
public UDTValue getUDTValue(String s) {
throw new UnsupportedOperationException();
}
public TupleValue getTupleValue(String s) {
throw new UnsupportedOperationException();
}
public <T> T get(String s, Class<T> aClass) {
throw new UnsupportedOperationException();
}
public <T> T get(String s, TypeToken<T> typeToken) {
throw new UnsupportedOperationException();
}
public <T> T get(String s, TypeCodec<T> typeCodec) {
throw new UnsupportedOperationException();
}
public ColumnDefinitions getColumnDefinitions() {
throw new UnsupportedOperationException();
}
public Token getToken(int i) {
throw new UnsupportedOperationException();
}
public Token getToken(String s) {
throw new UnsupportedOperationException();
}
public Token getPartitionKeyToken() {
throw new UnsupportedOperationException();
}
public boolean isNull(int i) {
throw new UnsupportedOperationException();
}
public boolean getBool(int i) {
throw new UnsupportedOperationException();
}
public byte getByte(int i) {
throw new UnsupportedOperationException();
}
public short getShort(int i) {
throw new UnsupportedOperationException();
}
public int getInt(int i) {
throw new UnsupportedOperationException();
}
public long getLong(int i) {
throw new UnsupportedOperationException();
}
public Date getTimestamp(int i) {
throw new UnsupportedOperationException();
}
public LocalDate getDate(int i) {
throw new UnsupportedOperationException();
}
public long getTime(int i) {
throw new UnsupportedOperationException();
}
public float getFloat(int i) {
throw new UnsupportedOperationException();
}
public double getDouble(int i) {
throw new UnsupportedOperationException();
}
public ByteBuffer getBytesUnsafe(int i) {
throw new UnsupportedOperationException();
}
public ByteBuffer getBytes(int i) {
throw new UnsupportedOperationException();
}
public String getString(int i) {
throw new UnsupportedOperationException();
}
public BigInteger getVarint(int i) {
throw new UnsupportedOperationException();
}
public BigDecimal getDecimal(int i) {
throw new UnsupportedOperationException();
}
public UUID getUUID(int i) {
throw new UnsupportedOperationException();
}
public InetAddress getInet(int i) {
throw new UnsupportedOperationException();
}
public <T> List<T> getList(int i, Class<T> aClass) {
throw new UnsupportedOperationException();
}
public <T> List<T> getList(int i, TypeToken<T> typeToken) {
throw new UnsupportedOperationException();
}
public <T> Set<T> getSet(int i, Class<T> aClass) {
throw new UnsupportedOperationException();
}
public <T> Set<T> getSet(int i, TypeToken<T> typeToken) {
throw new UnsupportedOperationException();
}
public <K, V> Map<K, V> getMap(int i, Class<K> aClass, Class<V> aClass1) {
throw new UnsupportedOperationException();
}
public <K, V> Map<K, V> getMap(int i, TypeToken<K> typeToken, TypeToken<V> typeToken1) {
throw new UnsupportedOperationException();
}
public UDTValue getUDTValue(int i) {
throw new UnsupportedOperationException();
}
public TupleValue getTupleValue(int i) {
throw new UnsupportedOperationException();
}
public Object getObject(int i) {
throw new UnsupportedOperationException();
}
public <T> T get(int i, Class<T> aClass) {
throw new UnsupportedOperationException();
}
public <T> T get(int i, TypeToken<T> typeToken) {
throw new UnsupportedOperationException();
}
public <T> T get(int i, TypeCodec<T> typeCodec) {
throw new UnsupportedOperationException();
}
}
}