
eu.drus.jpa.unit.sql.dbunit.DataSetComparator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jpa-unit-rdbms Show documentation
Show all versions of jpa-unit-rdbms Show documentation
Makes JPA Unit support SQL databases
The newest version!
package eu.drus.jpa.unit.sql.dbunit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import org.dbunit.Assertion;
import org.dbunit.DatabaseUnitException;
import org.dbunit.assertion.DbComparisonFailure;
import org.dbunit.assertion.DiffCollectingFailureHandler;
import org.dbunit.assertion.Difference;
import org.dbunit.dataset.Column;
import org.dbunit.dataset.CompositeTable;
import org.dbunit.dataset.DataSetException;
import org.dbunit.dataset.FilteredDataSet;
import org.dbunit.dataset.FilteredTableMetaData;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.ITable;
import org.dbunit.dataset.NoSuchTableException;
import org.dbunit.dataset.SortedTable;
import org.dbunit.dataset.filter.DefaultColumnFilter;
import org.dbunit.dataset.filter.IColumnFilter;
import org.dbunit.dataset.filter.IncludeTableFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import eu.drus.jpa.unit.api.JpaUnitException;
import eu.drus.jpa.unit.spi.AssertionErrorCollector;
import eu.drus.jpa.unit.spi.ColumnsHolder;
public class DataSetComparator {
private static final Function ID_MAPPER = (final String name) -> name;
private static final String DIFF_ERROR = "%s | In row %d: expected value of %s \"%s\" but was \"%s\".";
private static final Logger LOG = LoggerFactory.getLogger(DataSetComparator.class);
private final ColumnsHolder toExclude;
private final ColumnsHolder orderBy;
private final Set> columnFilters;
private boolean isStrict;
public DataSetComparator(final String[] orderBy, final String[] toExclude, final boolean isStrict,
final Set> columnFilters) {
this.toExclude = new ColumnsHolder(toExclude, ID_MAPPER);
this.orderBy = new ColumnsHolder(orderBy, ID_MAPPER);
this.isStrict = isStrict;
this.columnFilters = columnFilters;
}
public void compare(final IDataSet currentDataSet, final IDataSet expectedDataSet, final AssertionErrorCollector errorCollector)
throws DatabaseUnitException {
if (expectedDataSet.getTableNames().length == 0) {
shouldBeEmpty(currentDataSet, errorCollector);
} else {
compareContent(currentDataSet, expectedDataSet, errorCollector);
}
}
private void shouldBeEmpty(final IDataSet dataSet, final AssertionErrorCollector errorCollector) throws DatabaseUnitException {
for (final String tableName : dataSet.getTableNames()) {
final int rowCount = dataSet.getTable(tableName).getRowCount();
if (rowCount != 0) {
errorCollector.collect(tableName + " was expected to be empty, but has <" + rowCount + "> entries.");
}
}
}
@SuppressWarnings("unchecked")
private void compareContent(final IDataSet currentDataSet, final IDataSet expectedDataSet, final AssertionErrorCollector errorCollector)
throws DatabaseUnitException {
final String[] expectedTableNames = expectedDataSet.getTableNames();
final FilteredDataSet filteredCurrentDataSet = new FilteredDataSet(new IncludeTableFilter(expectedTableNames), currentDataSet);
for (final String tableName : expectedTableNames) {
try {
final List columnsForSorting = defineColumnsForSorting(filteredCurrentDataSet, expectedDataSet, tableName);
final ITable table = filteredCurrentDataSet.getTable(tableName);
final ITable expectedTable = sort(new TableWrapper(expectedDataSet.getTable(tableName), table.getTableMetaData()),
columnsForSorting);
final ITable currentTable = sort(table, columnsForSorting);
final List columnsToIgnore = extractColumnsToBeIgnored(expectedDataSet.getTable(tableName), table);
final String[] toBeIgnored = columnsToIgnore.toArray(new String[columnsToIgnore.size()]);
final ITable expectedTableWithFilteredColumns = filter(expectedTable, toBeIgnored);
final ITable actualTableWithFilteredColumns = filter(currentTable, toBeIgnored);
final DiffCollectingFailureHandler diffCollector = new DiffCollectingFailureHandler();
Assertion.assertEquals(expectedTableWithFilteredColumns, actualTableWithFilteredColumns, diffCollector);
collectErrors(errorCollector, diffCollector.getDiffList());
} catch (final NoSuchTableException e) {
final int rowCount = expectedDataSet.getTable(tableName).getRowCount();
errorCollector.collect(tableName + " was expected to be present and to contain <" + rowCount + "> entries, but not found.");
} catch (final DbComparisonFailure e) {
errorCollector.collect(e.getMessage());
}
}
if (isStrict) {
final List currentTableNames = new ArrayList<>(Arrays.asList(currentDataSet.getTableNames()));
currentTableNames.removeAll(Arrays.asList(expectedTableNames));
for (final String notExpectedTableName : currentTableNames) {
try {
final int rowCount = currentDataSet.getTable(notExpectedTableName).getRowCount();
if (rowCount > 0) {
errorCollector.collect(
notExpectedTableName + " was not expected, but is present and contains <" + rowCount + "> entries.");
}
} catch (final NoSuchTableException e) {
// This should usually not happen. But it looks some persistence provider do not
// close the connection pool immediately so that if in-memory DB is used a new
// entity context manager is created before the previous active DB instance
// could be dropped.
// TODO: This needs further investigations
}
}
}
}
private List defineColumnsForSorting(final IDataSet currentDataSet, final IDataSet expectedDataSet, final String tableName)
throws DataSetException {
final List additionalColumns = additionalColumnsForSorting(expectedDataSet.getTable(tableName),
currentDataSet.getTable(tableName));
final List result = new ArrayList<>();
result.addAll(orderBy.getColumns(tableName));
result.addAll(additionalColumns);
return result;
}
private ITable sort(final ITable table, final List columnsForSorting) throws DataSetException {
final SortedTable sortedTable = new SortedTable(table, columnsForSorting.toArray(new String[columnsForSorting.size()]));
sortedTable.setUseComparable(true);
return sortedTable;
}
private List extractColumnsToBeIgnored(final ITable expectedTableState, final ITable currentTableState)
throws DataSetException {
final List columnsToIgnore = extractNotExpectedColumnNames(expectedTableState, currentTableState);
final String tableName = expectedTableState.getTableMetaData().getTableName();
columnsToIgnore.addAll(toExclude.getColumns(tableName));
final List nonExistingColumns = new ArrayList<>(columnsToIgnore);
nonExistingColumns.removeAll(extractColumnNames(currentTableState.getTableMetaData().getColumns()));
if (!nonExistingColumns.isEmpty()) {
LOG.debug("Columns which are specified to be filtered out {} are not existing in the table {}",
Arrays.toString(nonExistingColumns.toArray()), tableName);
}
return columnsToIgnore;
}
private ITable filter(final ITable table, final String[] columnsToFilter) throws DataSetException {
final ITable filteredTable = DefaultColumnFilter.excludedColumnsTable(table, columnsToFilter);
return applyCustomFilters(filteredTable);
}
private void collectErrors(final AssertionErrorCollector errorCollector, final List diffs) {
for (final Difference diff : diffs) {
final String tableName = diff.getActualTable().getTableMetaData().getTableName();
errorCollector.collect(String.format(DIFF_ERROR, tableName, diff.getRowIndex(), diff.getColumnName(), diff.getExpectedValue(),
diff.getActualValue()));
}
}
private List additionalColumnsForSorting(final ITable expectedTableState, final ITable currentTableState)
throws DataSetException {
final List columnsForSorting = new ArrayList<>();
final Set allColumns = new HashSet<>(extractColumnNames(expectedTableState.getTableMetaData().getColumns()));
final Set columnsToIgnore = new HashSet<>(extractColumnsToBeIgnored(expectedTableState, currentTableState));
for (final String column : allColumns) {
if (!columnsToIgnore.contains(column)) {
columnsForSorting.add(column);
}
}
return columnsForSorting;
}
private ITable applyCustomFilters(final ITable table) throws DataSetException {
ITable compositeTable = table;
for (final Class extends IColumnFilter> columnFilter : columnFilters) {
IColumnFilter customColumnFilter;
try {
customColumnFilter = columnFilter.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new JpaUnitException("Could not instanciate custom column filter", e);
}
final FilteredTableMetaData metaData = new FilteredTableMetaData(compositeTable.getTableMetaData(), customColumnFilter);
compositeTable = new CompositeTable(metaData, compositeTable);
}
return compositeTable;
}
private Collection extractColumnNames(final Column[] columns) {
final List names = new ArrayList<>(columns.length);
for (final Column column : columns) {
names.add(column.getColumnName().toLowerCase());
}
return names;
}
private List extractNotExpectedColumnNames(final ITable expectedTable, final ITable currentTable) throws DataSetException {
final Set actualColumnNames = new HashSet<>();
final Set expectedColumnNames = new HashSet<>();
if (currentTable != null) {
actualColumnNames.addAll(extractColumnNames(currentTable.getTableMetaData().getColumns()));
}
if (expectedTable != null) {
expectedColumnNames.addAll(extractColumnNames(expectedTable.getTableMetaData().getColumns()));
}
actualColumnNames.removeAll(expectedColumnNames);
return new ArrayList<>(actualColumnNames);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy