ALF-11518 and ALF-11519: unify separate validation/differences lists and move text generation to Result classes.

ALF-11518: Unify differences and validation results lists
ALF-11519: Move validation/diff result text generation from SchemaBootstrap to result classes.



git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@32110 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Matt Ward
2011-11-18 18:20:53 +00:00
parent 50ad2d600c
commit 29dadc748a
25 changed files with 554 additions and 167 deletions

View File

@@ -74,6 +74,7 @@ import org.alfresco.util.LogUtil;
import org.alfresco.util.TempFileProvider; import org.alfresco.util.TempFileProvider;
import org.alfresco.util.schemacomp.Difference; import org.alfresco.util.schemacomp.Difference;
import org.alfresco.util.schemacomp.ExportDb; import org.alfresco.util.schemacomp.ExportDb;
import org.alfresco.util.schemacomp.Result;
import org.alfresco.util.schemacomp.Results; import org.alfresco.util.schemacomp.Results;
import org.alfresco.util.schemacomp.SchemaComparator; import org.alfresco.util.schemacomp.SchemaComparator;
import org.alfresco.util.schemacomp.ValidationResult; import org.alfresco.util.schemacomp.ValidationResult;
@@ -104,8 +105,6 @@ import org.hibernate.engine.ActionQueue;
import org.hibernate.tool.hbm2ddl.DatabaseMetadata; import org.hibernate.tool.hbm2ddl.DatabaseMetadata;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationEvent;
import org.springframework.core.Conventions;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver;
@@ -1666,8 +1665,7 @@ public class SchemaBootstrap extends AbstractLifecycleBean
schemaComparator.validateAndCompare(); schemaComparator.validateAndCompare();
Results differences = schemaComparator.getDifferences(); Results results = schemaComparator.getComparisonResults();
List<ValidationResult> validationResults = schemaComparator.getValidationResults();
String outputFileName = MessageFormat.format( String outputFileName = MessageFormat.format(
outputFileNameTemplate, outputFileNameTemplate,
@@ -1675,8 +1673,6 @@ public class SchemaBootstrap extends AbstractLifecycleBean
File outputFile = TempFileProvider.createTempFile(outputFileName, ".txt"); File outputFile = TempFileProvider.createTempFile(outputFileName, ".txt");
PrintWriter pw = null; PrintWriter pw = null;
try try
{ {
@@ -1687,66 +1683,21 @@ public class SchemaBootstrap extends AbstractLifecycleBean
throw new RuntimeException("Unable to open file for writing: " + outputFile); throw new RuntimeException("Unable to open file for writing: " + outputFile);
} }
for (Difference difference : differences) // Populate the file with details of the comparison's results.
for (Result result : results)
{ {
StringBuffer sb = new StringBuffer(); pw.println(result.describe());
sb.append(difference.getStrength())
.append(" (diff): ")
.append(difference.getWhere());
sb.append(" reference path:");
if (difference.getLeft() != null)
{
sb.append(difference.getLeft().getPath());
sb.append(" (value: ")
.append(difference.getLeft().getPropertyValue())
.append(")");
}
else
{
sb.append("null");
}
sb.append(" target path:");
if (difference.getRight() != null)
{
sb.append(difference.getRight().getPath());
sb.append(" (value: ")
.append(difference.getRight().getPropertyValue())
.append(")");
}
else
{
sb.append("null");
}
pw.println(sb);
}
for (ValidationResult validationResult : validationResults)
{
StringBuffer sb = new StringBuffer();
sb.append(validationResult.getStrength())
.append(" (validation): ")
.append("target path:")
.append(validationResult.getDbProperty().getPath())
.append(" (value: ")
.append(validationResult.getValue())
.append(")");
pw.println(sb);
} }
pw.close(); pw.close();
if (validationResults.size() == 0 && differences.size() == 0) if (results.size() == 0)
{ {
logger.info("Compared database schema with reference schema (all OK): " + referenceResource); logger.info("Compared database schema with reference schema (all OK): " + referenceResource);
} }
else else
{ {
int numProblems = validationResults.size() + differences.size(); int numProblems = results.size();
logger.warn("Schema validation found " + numProblems + logger.warn("Schema validation found " + numProblems +
" potential problems, results written to: " " potential problems, results written to: "
+ outputFile); + outputFile);

View File

@@ -81,7 +81,7 @@ public class DefaultComparisonUtils implements ComparisonUtils
ArrayList<? extends Object> leftList = new ArrayList<Object>(leftCollection); ArrayList<? extends Object> leftList = new ArrayList<Object>(leftCollection);
ArrayList<? extends Object> rightList = new ArrayList<Object>(rightCollection); ArrayList<? extends Object> rightList = new ArrayList<Object>(rightCollection);
Results differences = ctx.getDifferences(); Results differences = ctx.getComparisonResults();
for (int leftIndex = 0; leftIndex < leftList.size(); leftIndex++) for (int leftIndex = 0; leftIndex < leftList.size(); leftIndex++)
{ {
@@ -144,7 +144,7 @@ public class DefaultComparisonUtils implements ComparisonUtils
public void compareCollections(Collection<? extends DbObject> leftCollection, public void compareCollections(Collection<? extends DbObject> leftCollection,
Collection<? extends DbObject> rightCollection, DiffContext ctx, Strength strength) Collection<? extends DbObject> rightCollection, DiffContext ctx, Strength strength)
{ {
Results differences = ctx.getDifferences(); Results differences = ctx.getComparisonResults();
for (DbObject leftObj : leftCollection) for (DbObject leftObj : leftCollection)
{ {
DbObject rightObj = findSameObjectAs(rightCollection, leftObj); DbObject rightObj = findSameObjectAs(rightCollection, leftObj);
@@ -234,7 +234,7 @@ public class DefaultComparisonUtils implements ComparisonUtils
} }
} }
ctx.getDifferences().add(where, leftProperty, rightProperty, strength); ctx.getComparisonResults().add(where, leftProperty, rightProperty, strength);
} }

View File

@@ -58,7 +58,7 @@ public class DefaultComparisonUtilsTest
public void setUp() public void setUp()
{ {
comparisonUtils = new DefaultComparisonUtils(); comparisonUtils = new DefaultComparisonUtils();
ctx = new DiffContext(dialect, differences, new ArrayList<ValidationResult>(), null, null); ctx = new DiffContext(dialect, differences, null, null);
} }
@Test @Test

View File

@@ -18,8 +18,6 @@
*/ */
package org.alfresco.util.schemacomp; package org.alfresco.util.schemacomp;
import java.util.List;
import org.alfresco.util.schemacomp.model.Schema; import org.alfresco.util.schemacomp.model.Schema;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
@@ -33,25 +31,39 @@ import org.hibernate.dialect.Dialect;
public class DiffContext public class DiffContext
{ {
private final Dialect dialect; private final Dialect dialect;
private final Results differences; private final Results results;
private final List<ValidationResult> validationResults;
private final Schema referenceSchema; private final Schema referenceSchema;
private final Schema targetSchema; private final Schema targetSchema;
/** /**
* Constructor.
*
* @param dialect * @param dialect
* @param differences * @param results
* @param referenceSchema
* @param targetSchema
*/ */
public DiffContext(Dialect dialect, Results differences, List<ValidationResult> validationResults, public DiffContext(Dialect dialect, Results results, Schema referenceSchema, Schema targetSchema)
Schema referenceSchema, Schema targetSchema)
{ {
this.dialect = dialect; this.dialect = dialect;
this.differences = differences; this.results = results;
this.validationResults = validationResults;
this.referenceSchema = referenceSchema; this.referenceSchema = referenceSchema;
this.targetSchema = targetSchema; this.targetSchema = targetSchema;
} }
/**
* Constructor.
*
* @param dialect
* @param referenceSchema
* @param targetSchema
*/
public DiffContext(Dialect dialect, Schema referenceSchema, Schema targetSchema)
{
this(dialect, new Results(), referenceSchema, targetSchema);
}
/** /**
* @return the dialect * @return the dialect
*/ */
@@ -61,19 +73,11 @@ public class DiffContext
} }
/** /**
* @return the differences * @return the results of schema comparison: validation failures, differences etc.
*/ */
public Results getDifferences() public Results getComparisonResults()
{ {
return this.differences; return this.results;
}
/**
* @return the validationResults
*/
public List<ValidationResult> getValidationResults()
{
return this.validationResults;
} }
/** /**

View File

@@ -71,6 +71,43 @@ public final class Difference extends Result
return this.right; return this.right;
} }
@Override
public String describe()
{
StringBuffer sb = new StringBuffer();
sb.append("Difference: ")
.append(getWhere());
sb.append(" reference path:");
if (getLeft() != null)
{
sb.append(getLeft().getPath());
sb.append(" (value: ")
.append(getLeft().getPropertyValue())
.append(")");
}
else
{
sb.append("null");
}
sb.append(" target path:");
if (getRight() != null)
{
sb.append(getRight().getPath());
sb.append(" (value: ")
.append(getRight().getPropertyValue())
.append(")");
}
else
{
sb.append("null");
}
return sb.toString();
}
@Override @Override
public String toString() public String toString()
{ {

View File

@@ -0,0 +1,51 @@
/*
* Copyright (C) 2005-2011 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.util.schemacomp;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.alfresco.util.schemacomp.Difference.Where;
import org.junit.Test;
/**
* Tests for the {@link Difference} class.
*
* @author Matt Ward
*/
public class DifferenceTest
{
@Test
public void describe()
{
DbProperty refDbProp = mock(DbProperty.class);
when(refDbProp.getPath()).thenReturn("alfresco.some_table.some_column.name");
when(refDbProp.getPropertyValue()).thenReturn("node_ref");
DbProperty targetDbProp = mock(DbProperty.class);
when(targetDbProp.getPath()).thenReturn("alfresco.some_table.some_column.name");
when(targetDbProp.getPropertyValue()).thenReturn("nood_ref");
Difference diff = new Difference(Where.ONLY_IN_LEFT, refDbProp, targetDbProp);
assertEquals("Difference: ONLY_IN_LEFT reference path:alfresco.some_table.some_column.name (value: node_ref) " +
"target path:alfresco.some_table.some_column.name (value: nood_ref)", diff.describe());
}
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright (C) 2005-2011 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.util.schemacomp;
import java.util.List;
import org.alfresco.util.schemacomp.model.DbObject;
/**
* If more than one DB item in the target schema matches a reference DB item
* then this result will be issued.
*
* @author Matt Ward
*/
public class RedundantDbObject extends Result
{
private final static int SHOW_MAX_MATCHES = 3;
private DbObject dbObject;
private List<DbObject> matches;
public RedundantDbObject(DbObject dbObject, List<DbObject> matches)
{
super(null);
this.dbObject = dbObject;
this.matches = matches;
}
@Override
public String describe()
{
StringBuffer sb = new StringBuffer();
sb.append(matches.size())
.append(" redundant items? reference: ")
.append(dbObject)
.append(", matches: ");
for (int i = 0; i < matches.size() && i < SHOW_MAX_MATCHES; i++)
{
if (i > 0)
{
sb.append(", ");
}
sb.append(matches.get(i));
}
if (matches.size() > SHOW_MAX_MATCHES)
{
sb.append(" and ")
.append(matches.size() - SHOW_MAX_MATCHES).append(" more...");
}
return sb.toString();
}
@Override
public String toString()
{
return "RedundantDbObject [dbObject=" + this.dbObject + ", matches=" + this.matches + "]";
}
}

View File

@@ -0,0 +1,91 @@
/*
* Copyright (C) 2005-2011 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.util.schemacomp;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.List;
import org.alfresco.util.schemacomp.model.AbstractDbObject;
import org.alfresco.util.schemacomp.model.DbObject;
import org.junit.Test;
/**
* Tests for the {@link RedundantDbObject} class.
*
* @author Matt Ward
*/
public class RedundantDbObjectTest
{
@Test
public void describe()
{
DbObject reference = new MyDbObject("reference");
List<DbObject> matches = makeMatches(3);
RedundantDbObject redundantDBO = new RedundantDbObject(reference, matches);
assertEquals("3 redundant items? reference: MyDbObject[name=reference], " +
"matches: MyDbObject[name=match1], MyDbObject[name=match2], MyDbObject[name=match3]",
redundantDBO.describe());
}
@Test
public void describeTooManyMatches()
{
DbObject reference = new MyDbObject("reference");
List<DbObject> matches = makeMatches(4);
RedundantDbObject redundantDBO = new RedundantDbObject(reference, matches);
assertEquals("4 redundant items? reference: MyDbObject[name=reference], " +
"matches: MyDbObject[name=match1], MyDbObject[name=match2], MyDbObject[name=match3] and 1 more...",
redundantDBO.describe());
}
/**
* @return
*/
private List<DbObject> makeMatches(int numMatches)
{
List<DbObject> matches = new ArrayList<DbObject>();
for (int i = 0; i < numMatches; i++)
{
matches.add(new MyDbObject("match" + (i+1)));
}
return matches;
}
private static class MyDbObject extends AbstractDbObject
{
public MyDbObject(String name)
{
super(null, name);
}
@Override
public void accept(DbObjectVisitor visitor)
{
}
}
}

View File

@@ -23,7 +23,7 @@ package org.alfresco.util.schemacomp;
* *
* @author Matt Ward * @author Matt Ward
*/ */
public class Result public abstract class Result
{ {
public enum Strength { WARN, ERROR }; public enum Strength { WARN, ERROR };
protected final Strength strength; protected final Strength strength;
@@ -43,4 +43,16 @@ public class Result
{ {
return this.strength; return this.strength;
} }
/**
* A loggable message to describe the comparison result. Default implementation
* delegates to toString() but this should generally be overridden as toString()
* is used in a multitude of contexts.
*
* @return
*/
public String describe()
{
return toString();
}
} }

View File

@@ -30,9 +30,9 @@ import org.alfresco.util.schemacomp.Result.Strength;
* *
* @author Matt Ward * @author Matt Ward
*/ */
public class Results implements Iterable<Difference> public class Results implements Iterable<Result>
{ {
private final List<Difference> items = new ArrayList<Difference>(); private final List<Result> items = new ArrayList<Result>();
/** Temporary step during refactor - Where.IN_BOTH_NO_DIFFERENCE will be going altogether */ /** Temporary step during refactor - Where.IN_BOTH_NO_DIFFERENCE will be going altogether */
private boolean reportNonDifferences = false; private boolean reportNonDifferences = false;
@@ -62,16 +62,32 @@ public class Results implements Iterable<Difference>
} }
public void add(Result result)
{
items.add(result);
}
/** /**
* Obtain an iterator for the top-level items held in this schema - since this is a hierarchical model, * Obtain an iterator for the top-level items held in this schema - since this is a hierarchical model,
* deeper items are obtained by navigating through the top-level items. * deeper items are obtained by navigating through the top-level items.
*/ */
@Override @Override
public Iterator<Difference> iterator() public Iterator<Result> iterator()
{ {
return items.iterator(); return items.iterator();
} }
/**
* Get the ith result.
*
* @param i
* @return Result
*/
public Result get(int i)
{
return items.get(i);
}
/** /**
* @return How many top-level items are in the schema. * @return How many top-level items are in the schema.
*/ */

View File

@@ -33,8 +33,11 @@ import org.junit.runners.Suite;
DbPropertyTest.class, DbPropertyTest.class,
DbToXMLTest.class, DbToXMLTest.class,
DefaultComparisonUtilsTest.class, DefaultComparisonUtilsTest.class,
DifferenceTest.class,
ExportDbTest.class, ExportDbTest.class,
RedundantDbObjectTest.class,
SchemaComparatorTest.class, SchemaComparatorTest.class,
ValidationResultTest.class,
ValidatingVisitorTest.class, ValidatingVisitorTest.class,
SchemaToXMLTest.class, SchemaToXMLTest.class,
XMLToSchemaTest.class XMLToSchemaTest.class

View File

@@ -36,26 +36,33 @@ import org.apache.commons.lang.ArrayUtils;
public class SchemaCompTestingUtils public class SchemaCompTestingUtils
{ {
public static void dumpValidation(List<ValidationResult> validationResults) public static void dumpValidation(Results results)
{ {
System.out.println("Validation Results (" + validationResults.size() + ")"); System.out.println("Validation Results (" + results.size() + ")");
for (ValidationResult r : validationResults) for (Result r : results)
{
if (r instanceof ValidationResult)
{ {
System.out.println(r); System.out.println(r);
} }
} }
}
public static void dumpDiffs(Results differences, boolean showNonDifferences) public static void dumpDiffs(Results differences, boolean showNonDifferences)
{ {
System.out.println("Differences (" + differences.size() + ")"); System.out.println("Differences (" + differences.size() + ")");
for (Difference d : differences) for (Result d : differences)
{ {
if (d.getWhere() != Where.IN_BOTH_NO_DIFFERENCE || showNonDifferences) if (d instanceof Difference)
{
Difference diff = (Difference) d;
if (diff.getWhere() != Where.IN_BOTH_NO_DIFFERENCE || showNonDifferences)
{ {
System.out.println(d); System.out.println(d);
} }
} }
} }
}
public static Table table(String name) public static Table table(String name)
{ {

View File

@@ -18,9 +18,6 @@
*/ */
package org.alfresco.util.schemacomp; package org.alfresco.util.schemacomp;
import java.util.ArrayList;
import java.util.List;
import org.alfresco.util.schemacomp.Result.Strength; import org.alfresco.util.schemacomp.Result.Strength;
import org.alfresco.util.schemacomp.model.Schema; import org.alfresco.util.schemacomp.model.Schema;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
@@ -48,7 +45,7 @@ public class SchemaComparator
{ {
this.referenceSchema = referenceSchema; this.referenceSchema = referenceSchema;
this.targetSchema = targetSchema; this.targetSchema = targetSchema;
this.ctx = new DiffContext(dialect, new Results(), new ArrayList<ValidationResult>(), referenceSchema, targetSchema); this.ctx = new DiffContext(dialect, referenceSchema, targetSchema);
} }
@@ -79,19 +76,10 @@ public class SchemaComparator
/** /**
* @return the differences * @return the schema comparison results.
*/ */
public Results getDifferences() public Results getComparisonResults()
{ {
return ctx.getDifferences(); return ctx.getComparisonResults();
}
/**
* @return the validation results.
*/
public List<ValidationResult> getValidationResults()
{
return ctx.getValidationResults();
} }
} }

View File

@@ -29,7 +29,6 @@ import static org.alfresco.util.schemacomp.SchemaCompTestingUtils.pk;
import static org.alfresco.util.schemacomp.SchemaCompTestingUtils.table; import static org.alfresco.util.schemacomp.SchemaCompTestingUtils.table;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import java.util.Arrays; import java.util.Arrays;
import java.util.Iterator; import java.util.Iterator;
@@ -57,8 +56,8 @@ public class SchemaComparatorTest
@Before @Before
public void setup() public void setup()
{ {
reference = new Schema("reference_schema"); reference = new Schema("schema");
target = new Schema("target_schema"); target = new Schema("schema");
dialect = new MySQL5InnoDBDialect(); dialect = new MySQL5InnoDBDialect();
} }
@@ -87,67 +86,55 @@ public class SchemaComparatorTest
comparator.validateAndCompare(); comparator.validateAndCompare();
// See stdout for diagnostics dump... // See stdout for diagnostics dump...
dumpDiffs(comparator.getDifferences(), false); dumpDiffs(comparator.getComparisonResults(), false);
dumpValidation(comparator.getValidationResults()); dumpValidation(comparator.getComparisonResults());
Results differences = comparator.getDifferences(); Results results = comparator.getComparisonResults();
Iterator<Difference> it = differences.iterator(); Iterator<Result> it = results.iterator();
// Schema names are different ("reference_schema" vs "target_schema")
Difference diff = it.next();
assertEquals(Where.IN_BOTH_BUT_DIFFERENCE, diff.getWhere());
assertEquals("reference_schema.name", diff.getLeft().getPath());
assertEquals("target_schema.name", diff.getRight().getPath());
assertSame(reference, diff.getLeft().getDbObject());
assertSame(target, diff.getRight().getDbObject());
assertEquals("name", diff.getLeft().getPropertyName());
assertEquals("reference_schema", diff.getLeft().getPropertyValue());
assertEquals("name", diff.getRight().getPropertyName());
assertEquals("target_schema", diff.getRight().getPropertyValue());
// Table table_in_reference only appears in the reference schema // Table table_in_reference only appears in the reference schema
diff = it.next(); Difference diff = (Difference) it.next();
assertEquals(Where.ONLY_IN_LEFT, diff.getWhere()); assertEquals(Where.ONLY_IN_LEFT, diff.getWhere());
assertEquals("reference_schema.table_in_reference", diff.getLeft().getPath()); assertEquals("schema.table_in_reference", diff.getLeft().getPath());
assertEquals(null, diff.getRight()); assertEquals(null, diff.getRight());
assertEquals(null, diff.getLeft().getPropertyName()); assertEquals(null, diff.getLeft().getPropertyName());
assertEquals(null, diff.getLeft().getPropertyValue()); assertEquals(null, diff.getLeft().getPropertyValue());
// Table tbl_has_diff_pk has PK of "id" in reference and "nodeRef" in target // Table tbl_has_diff_pk has PK of "id" in reference and "nodeRef" in target
diff = it.next(); diff = (Difference) it.next();
assertEquals(Where.ONLY_IN_LEFT, diff.getWhere()); assertEquals(Where.ONLY_IN_LEFT, diff.getWhere());
assertEquals("reference_schema.tbl_has_diff_pk.pk_is_diff.columnNames[0]", diff.getLeft().getPath()); assertEquals("schema.tbl_has_diff_pk.pk_is_diff.columnNames[0]", diff.getLeft().getPath());
assertEquals("target_schema.tbl_has_diff_pk.pk_is_diff.columnNames", diff.getRight().getPath()); assertEquals("schema.tbl_has_diff_pk.pk_is_diff.columnNames", diff.getRight().getPath());
assertEquals("columnNames[0]", diff.getLeft().getPropertyName()); assertEquals("columnNames[0]", diff.getLeft().getPropertyName());
assertEquals("id", diff.getLeft().getPropertyValue()); assertEquals("id", diff.getLeft().getPropertyValue());
assertEquals("columnNames", diff.getRight().getPropertyName()); assertEquals("columnNames", diff.getRight().getPropertyName());
assertEquals(Arrays.asList("nodeRef"), diff.getRight().getPropertyValue()); assertEquals(Arrays.asList("nodeRef"), diff.getRight().getPropertyValue());
// Table tbl_has_diff_pk has PK of "id" in reference and "nodeRef" in target // Table tbl_has_diff_pk has PK of "id" in reference and "nodeRef" in target
diff = it.next(); diff = (Difference) it.next();
assertEquals(Where.ONLY_IN_RIGHT, diff.getWhere()); assertEquals(Where.ONLY_IN_RIGHT, diff.getWhere());
assertEquals("reference_schema.tbl_has_diff_pk.pk_is_diff.columnNames", diff.getLeft().getPath()); assertEquals("schema.tbl_has_diff_pk.pk_is_diff.columnNames", diff.getLeft().getPath());
assertEquals("target_schema.tbl_has_diff_pk.pk_is_diff.columnNames[0]", diff.getRight().getPath()); assertEquals("schema.tbl_has_diff_pk.pk_is_diff.columnNames[0]", diff.getRight().getPath());
assertEquals("columnNames", diff.getLeft().getPropertyName()); assertEquals("columnNames", diff.getLeft().getPropertyName());
assertEquals(Arrays.asList("id"), diff.getLeft().getPropertyValue()); assertEquals(Arrays.asList("id"), diff.getLeft().getPropertyValue());
assertEquals("columnNames[0]", diff.getRight().getPropertyName()); assertEquals("columnNames[0]", diff.getRight().getPropertyName());
assertEquals("nodeRef", diff.getRight().getPropertyValue()); assertEquals("nodeRef", diff.getRight().getPropertyValue());
// idx_two is unique in the righ_schema but not in the reference // idx_two is unique in the righ_schema but not in the reference
diff = it.next(); diff = (Difference) it.next();
assertEquals("reference_schema.tbl_has_diff_pk.idx_two.unique", diff.getLeft().getPath()); assertEquals("schema.tbl_has_diff_pk.idx_two.unique", diff.getLeft().getPath());
assertEquals("target_schema.tbl_has_diff_pk.idx_two.unique", diff.getRight().getPath()); assertEquals("schema.tbl_has_diff_pk.idx_two.unique", diff.getRight().getPath());
assertEquals("unique", diff.getLeft().getPropertyName()); assertEquals("unique", diff.getLeft().getPropertyName());
assertEquals(false, diff.getLeft().getPropertyValue()); assertEquals(false, diff.getLeft().getPropertyValue());
assertEquals("unique", diff.getRight().getPropertyName()); assertEquals("unique", diff.getRight().getPropertyName());
assertEquals(true, diff.getRight().getPropertyValue()); assertEquals(true, diff.getRight().getPropertyValue());
// Table table_in_target does not exist in the reference schema // Table table_in_target does not exist in the reference schema
diff = it.next(); diff = (Difference) it.next();
assertEquals(Where.ONLY_IN_RIGHT, diff.getWhere()); assertEquals(Where.ONLY_IN_RIGHT, diff.getWhere());
assertEquals("target_schema.table_in_target", diff.getRight().getPath()); assertEquals("schema.table_in_target", diff.getRight().getPath());
assertEquals(null, diff.getLeft()); assertEquals(null, diff.getLeft());
assertEquals(null, diff.getRight().getPropertyName()); assertEquals(null, diff.getRight().getPropertyName());
assertEquals(null, diff.getRight().getPropertyValue()); assertEquals(null, diff.getRight().getPropertyValue());

View File

@@ -44,7 +44,10 @@ public class ValidatingVisitor implements DbObjectVisitor
{ {
List<DbObject> matches = comparisonUtils.findEquivalentObjects(ctx.getTargetSchema(), referenceObj); List<DbObject> matches = comparisonUtils.findEquivalentObjects(ctx.getTargetSchema(), referenceObj);
// TODO: if matches.size() > 1 then warn of possible redundant database objects if (matches.size() > 1)
{
ctx.getComparisonResults().add(new RedundantDbObject(referenceObj, matches));
}
// Validate each matching target object against the reference object // Validate each matching target object against the reference object
// using each of the available validators for that reference object. // using each of the available validators for that reference object.

View File

@@ -31,6 +31,7 @@ import org.alfresco.util.schemacomp.validator.DbValidator;
import org.hibernate.dialect.MySQL5InnoDBDialect; import org.hibernate.dialect.MySQL5InnoDBDialect;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import static org.junit.Assert.*;
import org.mockito.Mockito; import org.mockito.Mockito;
/** /**
@@ -59,8 +60,7 @@ public class ValidatingVisitorTest
{ {
refTable = new Table("reference_table"); refTable = new Table("reference_table");
refIndex = new Index(refTable, "index_name", Arrays.asList("a", "b", "c")); refIndex = new Index(refTable, "index_name", Arrays.asList("a", "b", "c"));
ctx = new DiffContext(new MySQL5InnoDBDialect(), new Results(), ctx = new DiffContext(new MySQL5InnoDBDialect(), refSchema, targetSchema);
new ArrayList<ValidationResult>(), refSchema, targetSchema);
visitor = new ValidatingVisitor(ctx); visitor = new ValidatingVisitor(ctx);
validators = new ArrayList<DbValidator>(); validators = new ArrayList<DbValidator>();
@@ -97,4 +97,29 @@ public class ValidatingVisitorTest
} }
@Test
public void redundantDbObjectsAreNoticed()
{
Mockito.when(comparisonUtils.findEquivalentObjects(refSchema, refIndex)).
thenReturn(Arrays.asList((DbObject) targetIndex1, targetIndex2, targetIndex3));
// Validate all instances of the target schema's indexes that are equivalent to this index
visitor.visit(refIndex);
assertEquals(1, ctx.getComparisonResults().size());
assertEquals(RedundantDbObject.class, ctx.getComparisonResults().get(0).getClass());
}
@Test
public void nonRedundantDbObjectsAreNoticed()
{
Mockito.when(comparisonUtils.findEquivalentObjects(refSchema, refIndex)).
thenReturn(Arrays.asList((DbObject) targetIndex1));
// Validate all instances of the target schema's indexes that are equivalent to this index
visitor.visit(refIndex);
assertEquals(0, ctx.getComparisonResults().size());
}
} }

View File

@@ -56,6 +56,21 @@ public class ValidationResult extends Result
this.dbProperty = dbProperty; this.dbProperty = dbProperty;
} }
@Override
public String describe()
{
StringBuffer sb = new StringBuffer();
sb.append("Validation ")
.append("target path:")
.append(getDbProperty().getPath())
.append(" (value: ")
.append(getValue())
.append(")");
return sb.toString();
}
/** /**
* @return the value that was rejected. * @return the value that was rejected.
*/ */

View File

@@ -0,0 +1,48 @@
/*
* Copyright (C) 2005-2011 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.util.schemacomp;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.junit.Test;
/**
* Tests for the {@link ValidationResult} class.
*
* @author Matt Ward
*/
public class ValidationResultTest
{
@Test
public void describe()
{
DbProperty targetDbProp = mock(DbProperty.class);
when(targetDbProp.getPath()).thenReturn("alfresco.some_table.some_index.name");
when(targetDbProp.getPropertyValue()).thenReturn("ibx_my_index");
ValidationResult validation = new ValidationResult(targetDbProp);
assertEquals("Validation target path:alfresco.some_table.some_index.name (value: ibx_my_index)",
validation.describe());
}
}

View File

@@ -96,16 +96,35 @@ public abstract class AbstractDbObject implements DbObject
@Override @Override
public boolean sameAs(DbObject other) public boolean sameAs(DbObject other)
{ {
if (other == null)
{
return false;
}
if (this == other)
{
return true;
}
if (!this.getClass().equals(other.getClass()))
{
// Objects are not the same type, even if they have the same name and parent
return false;
}
if (getName() != null && other != null && other.getName() != null) if (getName() != null && other != null && other.getName() != null)
{ {
return getName().equals(other.getName()); boolean sameParent = false;
}
else if (getParent() == null && other.getParent() == null)
{ {
// Only other way we can know if they are the same is if they are sameParent = true;
// the exact same object reference.
return this == other;
} }
else if (getParent() != null && getParent().sameAs(other.getParent()))
{
sameParent = true;
}
return sameParent && getName().equals(other.getName());
}
return false;
} }
@Override @Override

View File

@@ -23,7 +23,6 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.inOrder;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@@ -33,7 +32,6 @@ import org.alfresco.util.schemacomp.DiffContext;
import org.alfresco.util.schemacomp.Difference.Where; import org.alfresco.util.schemacomp.Difference.Where;
import org.alfresco.util.schemacomp.Result.Strength; import org.alfresco.util.schemacomp.Result.Strength;
import org.alfresco.util.schemacomp.Results; import org.alfresco.util.schemacomp.Results;
import org.alfresco.util.schemacomp.ValidationResult;
import org.alfresco.util.schemacomp.validator.AbstractDbValidator; import org.alfresco.util.schemacomp.validator.AbstractDbValidator;
import org.alfresco.util.schemacomp.validator.DbValidator; import org.alfresco.util.schemacomp.validator.DbValidator;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
@@ -64,7 +62,7 @@ public class AbstractDbObjectTest
public void setUp() throws Exception public void setUp() throws Exception
{ {
dbObject = new ConcreteDbObject("the_object"); dbObject = new ConcreteDbObject("the_object");
ctx = new DiffContext(dialect, differences, new ArrayList<ValidationResult>(), null, null); ctx = new DiffContext(dialect, differences, null, null);
} }
@Test @Test
@@ -84,6 +82,7 @@ public class AbstractDbObjectTest
dbObject.setName("the_name"); dbObject.setName("the_name");
assertFalse("Not the same.", dbObject.sameAs(null)); assertFalse("Not the same.", dbObject.sameAs(null));
assertFalse("Not the same.", dbObject.sameAs(new ConcreteDbObject("different_name"))); assertFalse("Not the same.", dbObject.sameAs(new ConcreteDbObject("different_name")));
assertFalse("Not the same type", dbObject.sameAs(new AnotherConcreteDbObject("the_name")));
assertTrue("Logically the same object.", dbObject.sameAs(new ConcreteDbObject("the_name"))); assertTrue("Logically the same object.", dbObject.sameAs(new ConcreteDbObject("the_name")));
assertTrue("The very same object with non-null name", dbObject.sameAs(dbObject)); assertTrue("The very same object with non-null name", dbObject.sameAs(dbObject));
} }
@@ -146,7 +145,7 @@ public class AbstractDbObjectTest
@Override @Override
protected void doDiff(DbObject right, DiffContext ctx, Strength strength) protected void doDiff(DbObject right, DiffContext ctx, Strength strength)
{ {
Results differences = ctx.getDifferences(); Results differences = ctx.getComparisonResults();
differences.add( differences.add(
Where.IN_BOTH_BUT_DIFFERENCE, Where.IN_BOTH_BUT_DIFFERENCE,
new DbProperty(this, "someProp"), new DbProperty(this, "someProp"),
@@ -164,6 +163,19 @@ public class AbstractDbObjectTest
} }
} }
public static class AnotherConcreteDbObject extends AbstractDbObject
{
public AnotherConcreteDbObject(String name)
{
super(null, name);
}
@Override
public void accept(DbObjectVisitor visitor)
{
}
}
private List<DbValidator> validatorList(DbValidator... validators) private List<DbValidator> validatorList(DbValidator... validators)
{ {

View File

@@ -131,4 +131,28 @@ public class Column extends AbstractDbObject
{ {
visitor.visit(this); visitor.visit(this);
} }
@Override
public boolean sameAs(DbObject other)
{
if (other == null)
{
return false;
}
if (this == other)
{
return true;
}
if (getClass().equals(other.getClass()))
{
if (getName() != null && other.getName() != null)
{
if (getParent() != null && other.getParent() != null && getParent().sameAs(other.getParent()))
{
return getName().equals(other.getName());
}
}
}
return false;
}
} }

View File

@@ -23,6 +23,7 @@ import org.alfresco.util.schemacomp.DbProperty;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
import static org.junit.Assert.*;
/** /**
* Tests for the Column class. * Tests for the Column class.
@@ -74,4 +75,23 @@ public class ColumnTest extends DbObjectTestBase<Column>
verify(visitor).visit(thisColumn); verify(visitor).visit(thisColumn);
} }
@Test
public void sameAs()
{
Table thisTable = new Table("the_table");
thisColumn = new Column(thisTable, "this_column", "VARCHAR2(100)", false);
Table thatTable = new Table("the_table");
thatColumn = new Column(thatTable, "this_column", "VARCHAR2(100)", false);
// This column, whilst having the same name as thisColumn, has a different
// parent table - and so is not considered 'the same'.
Table anotherTable = new Table("another_table");
Column anotherColumn = new Column(anotherTable, "this_column", "VARCHAR2(100)", false);
assertTrue("Column should always be the same as itself", thisColumn.sameAs(thisColumn));
assertTrue("Columns should be the same due to same parent table names", thisColumn.sameAs(thatColumn));
assertFalse("Should NOT be the same due to different parent table names", thisColumn.sameAs(anotherColumn));
}
} }

View File

@@ -18,7 +18,7 @@
*/ */
package org.alfresco.util.schemacomp.model; package org.alfresco.util.schemacomp.model;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.inOrder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -27,9 +27,8 @@ import org.alfresco.util.schemacomp.ComparisonUtils;
import org.alfresco.util.schemacomp.DbObjectVisitor; import org.alfresco.util.schemacomp.DbObjectVisitor;
import org.alfresco.util.schemacomp.DbProperty; import org.alfresco.util.schemacomp.DbProperty;
import org.alfresco.util.schemacomp.DiffContext; import org.alfresco.util.schemacomp.DiffContext;
import org.alfresco.util.schemacomp.Results;
import org.alfresco.util.schemacomp.Result.Strength; import org.alfresco.util.schemacomp.Result.Strength;
import org.alfresco.util.schemacomp.ValidationResult; import org.alfresco.util.schemacomp.Results;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@@ -61,7 +60,7 @@ public abstract class DbObjectTestBase<T extends AbstractDbObject>
// Check that the correct calls happened in the correct order. // Check that the correct calls happened in the correct order.
List<Object> mocks = getMocksUsedInDiff(); List<Object> mocks = getMocksUsedInDiff();
inOrder = inOrder(mocks.toArray()); inOrder = inOrder(mocks.toArray());
ctx = new DiffContext(dialect, differences, new ArrayList<ValidationResult>(), null, null); ctx = new DiffContext(dialect, differences, null, null);
} }

View File

@@ -49,7 +49,7 @@ public class NameValidator implements DbValidator
if (pattern != null && !pattern.matcher(name).matches()) if (pattern != null && !pattern.matcher(name).matches())
{ {
ctx.getValidationResults().add(result); ctx.getComparisonResults().add(result);
} }
} }

View File

@@ -22,7 +22,6 @@ package org.alfresco.util.schemacomp.validator;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.alfresco.util.schemacomp.DiffContext; import org.alfresco.util.schemacomp.DiffContext;
@@ -43,14 +42,14 @@ public class NameValidatorTest
{ {
private NameValidator validator; private NameValidator validator;
private DiffContext ctx; private DiffContext ctx;
private List<ValidationResult> validationResults; private Results validationResults;
@Before @Before
public void setUp() throws Exception public void setUp() throws Exception
{ {
validator = new NameValidator(); validator = new NameValidator();
validationResults = new ArrayList<ValidationResult>(); validationResults = new Results();
ctx = new DiffContext(new Oracle10gDialect(), new Results(), validationResults, null, null); ctx = new DiffContext(new Oracle10gDialect(), validationResults, null, null);
} }
@Test @Test
@@ -63,8 +62,8 @@ public class NameValidatorTest
validator.validate(null, indexForName("MY_INDEX"), ctx); validator.validate(null, indexForName("MY_INDEX"), ctx);
assertEquals(2, validationResults.size()); assertEquals(2, validationResults.size());
assertEquals("SYS_", validationResults.get(0).getValue()); assertEquals("SYS_", ((ValidationResult) validationResults.get(0)).getValue());
assertEquals("MY_INDEX", validationResults.get(1).getValue()); assertEquals("MY_INDEX", ((ValidationResult) validationResults.get(1)).getValue());
} }
@Test @Test
@@ -76,7 +75,7 @@ public class NameValidatorTest
validator.validate(null, indexForName("SYS_MYINDEX"), ctx); validator.validate(null, indexForName("SYS_MYINDEX"), ctx);
assertEquals(1, validationResults.size()); assertEquals(1, validationResults.size());
assertEquals("SYS_MYINDEX", validationResults.get(0).getValue()); assertEquals("SYS_MYINDEX", ((ValidationResult) validationResults.get(0)).getValue());
} }