| /* |
| * 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(); |
| } |
| } |
| |
| } |