diff --git a/source/java/org/alfresco/repo/domain/schema/SchemaBootstrap.java b/source/java/org/alfresco/repo/domain/schema/SchemaBootstrap.java index 66c70fc6bd..42d95a4e7f 100644 --- a/source/java/org/alfresco/repo/domain/schema/SchemaBootstrap.java +++ b/source/java/org/alfresco/repo/domain/schema/SchemaBootstrap.java @@ -74,6 +74,7 @@ import org.alfresco.util.LogUtil; import org.alfresco.util.TempFileProvider; import org.alfresco.util.schemacomp.Difference; import org.alfresco.util.schemacomp.ExportDb; +import org.alfresco.util.schemacomp.Result; import org.alfresco.util.schemacomp.Results; import org.alfresco.util.schemacomp.SchemaComparator; import org.alfresco.util.schemacomp.ValidationResult; @@ -104,8 +105,6 @@ import org.hibernate.engine.ActionQueue; import org.hibernate.tool.hbm2ddl.DatabaseMetadata; import org.springframework.context.ApplicationContext; 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.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; @@ -1666,8 +1665,7 @@ public class SchemaBootstrap extends AbstractLifecycleBean schemaComparator.validateAndCompare(); - Results differences = schemaComparator.getDifferences(); - List validationResults = schemaComparator.getValidationResults(); + Results results = schemaComparator.getComparisonResults(); String outputFileName = MessageFormat.format( outputFileNameTemplate, @@ -1675,8 +1673,6 @@ public class SchemaBootstrap extends AbstractLifecycleBean File outputFile = TempFileProvider.createTempFile(outputFileName, ".txt"); - - PrintWriter pw = null; try { @@ -1687,66 +1683,21 @@ public class SchemaBootstrap extends AbstractLifecycleBean 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(); - 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); + pw.println(result.describe()); } - - 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(); - if (validationResults.size() == 0 && differences.size() == 0) + if (results.size() == 0) { logger.info("Compared database schema with reference schema (all OK): " + referenceResource); } else { - int numProblems = validationResults.size() + differences.size(); + int numProblems = results.size(); logger.warn("Schema validation found " + numProblems + " potential problems, results written to: " + outputFile); diff --git a/source/java/org/alfresco/util/schemacomp/DefaultComparisonUtils.java b/source/java/org/alfresco/util/schemacomp/DefaultComparisonUtils.java index e3114dabc5..dec3effc47 100644 --- a/source/java/org/alfresco/util/schemacomp/DefaultComparisonUtils.java +++ b/source/java/org/alfresco/util/schemacomp/DefaultComparisonUtils.java @@ -81,7 +81,7 @@ public class DefaultComparisonUtils implements ComparisonUtils ArrayList leftList = new ArrayList(leftCollection); ArrayList rightList = new ArrayList(rightCollection); - Results differences = ctx.getDifferences(); + Results differences = ctx.getComparisonResults(); for (int leftIndex = 0; leftIndex < leftList.size(); leftIndex++) { @@ -144,7 +144,7 @@ public class DefaultComparisonUtils implements ComparisonUtils public void compareCollections(Collection leftCollection, Collection rightCollection, DiffContext ctx, Strength strength) { - Results differences = ctx.getDifferences(); + Results differences = ctx.getComparisonResults(); for (DbObject leftObj : leftCollection) { 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); } diff --git a/source/java/org/alfresco/util/schemacomp/DefaultComparisonUtilsTest.java b/source/java/org/alfresco/util/schemacomp/DefaultComparisonUtilsTest.java index 7abf4b7db1..d4c03ad930 100644 --- a/source/java/org/alfresco/util/schemacomp/DefaultComparisonUtilsTest.java +++ b/source/java/org/alfresco/util/schemacomp/DefaultComparisonUtilsTest.java @@ -58,7 +58,7 @@ public class DefaultComparisonUtilsTest public void setUp() { comparisonUtils = new DefaultComparisonUtils(); - ctx = new DiffContext(dialect, differences, new ArrayList(), null, null); + ctx = new DiffContext(dialect, differences, null, null); } @Test diff --git a/source/java/org/alfresco/util/schemacomp/DiffContext.java b/source/java/org/alfresco/util/schemacomp/DiffContext.java index c861befcb9..b4e818d32b 100644 --- a/source/java/org/alfresco/util/schemacomp/DiffContext.java +++ b/source/java/org/alfresco/util/schemacomp/DiffContext.java @@ -18,8 +18,6 @@ */ package org.alfresco.util.schemacomp; -import java.util.List; - import org.alfresco.util.schemacomp.model.Schema; import org.hibernate.dialect.Dialect; @@ -33,25 +31,39 @@ import org.hibernate.dialect.Dialect; public class DiffContext { private final Dialect dialect; - private final Results differences; - private final List validationResults; + private final Results results; private final Schema referenceSchema; private final Schema targetSchema; /** + * Constructor. + * * @param dialect - * @param differences + * @param results + * @param referenceSchema + * @param targetSchema */ - public DiffContext(Dialect dialect, Results differences, List validationResults, - Schema referenceSchema, Schema targetSchema) + public DiffContext(Dialect dialect, Results results, Schema referenceSchema, Schema targetSchema) { this.dialect = dialect; - this.differences = differences; - this.validationResults = validationResults; + this.results = results; this.referenceSchema = referenceSchema; 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 */ @@ -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 the validationResults - */ - public List getValidationResults() - { - return this.validationResults; + return this.results; } /** diff --git a/source/java/org/alfresco/util/schemacomp/Difference.java b/source/java/org/alfresco/util/schemacomp/Difference.java index a613e9c26d..9db40caae5 100644 --- a/source/java/org/alfresco/util/schemacomp/Difference.java +++ b/source/java/org/alfresco/util/schemacomp/Difference.java @@ -71,6 +71,43 @@ public final class Difference extends Result 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 public String toString() { diff --git a/source/java/org/alfresco/util/schemacomp/DifferenceTest.java b/source/java/org/alfresco/util/schemacomp/DifferenceTest.java new file mode 100644 index 0000000000..9d3ea3e351 --- /dev/null +++ b/source/java/org/alfresco/util/schemacomp/DifferenceTest.java @@ -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 . + */ +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()); + } +} diff --git a/source/java/org/alfresco/util/schemacomp/RedundantDbObject.java b/source/java/org/alfresco/util/schemacomp/RedundantDbObject.java new file mode 100644 index 0000000000..c81f5ec525 --- /dev/null +++ b/source/java/org/alfresco/util/schemacomp/RedundantDbObject.java @@ -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 . + */ +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 matches; + + public RedundantDbObject(DbObject dbObject, List 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 + "]"; + } +} diff --git a/source/java/org/alfresco/util/schemacomp/RedundantDbObjectTest.java b/source/java/org/alfresco/util/schemacomp/RedundantDbObjectTest.java new file mode 100644 index 0000000000..e0a57fc97f --- /dev/null +++ b/source/java/org/alfresco/util/schemacomp/RedundantDbObjectTest.java @@ -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 . + */ +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 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 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 makeMatches(int numMatches) + { + List matches = new ArrayList(); + 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) + { + } + } +} diff --git a/source/java/org/alfresco/util/schemacomp/Result.java b/source/java/org/alfresco/util/schemacomp/Result.java index 70c95d2aaa..6bb2184195 100644 --- a/source/java/org/alfresco/util/schemacomp/Result.java +++ b/source/java/org/alfresco/util/schemacomp/Result.java @@ -23,7 +23,7 @@ package org.alfresco.util.schemacomp; * * @author Matt Ward */ -public class Result +public abstract class Result { public enum Strength { WARN, ERROR }; protected final Strength strength; @@ -43,4 +43,16 @@ public class Result { 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(); + } } diff --git a/source/java/org/alfresco/util/schemacomp/Results.java b/source/java/org/alfresco/util/schemacomp/Results.java index e67b572373..84bf79cc58 100644 --- a/source/java/org/alfresco/util/schemacomp/Results.java +++ b/source/java/org/alfresco/util/schemacomp/Results.java @@ -30,9 +30,9 @@ import org.alfresco.util.schemacomp.Result.Strength; * * @author Matt Ward */ -public class Results implements Iterable +public class Results implements Iterable { - private final List items = new ArrayList(); + private final List items = new ArrayList(); /** Temporary step during refactor - Where.IN_BOTH_NO_DIFFERENCE will be going altogether */ private boolean reportNonDifferences = false; @@ -62,16 +62,32 @@ public class Results implements Iterable } + 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, * deeper items are obtained by navigating through the top-level items. */ @Override - public Iterator iterator() + public Iterator 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. */ diff --git a/source/java/org/alfresco/util/schemacomp/SchemaCompTestSuite.java b/source/java/org/alfresco/util/schemacomp/SchemaCompTestSuite.java index 3c55ca3251..dfc95f2f26 100644 --- a/source/java/org/alfresco/util/schemacomp/SchemaCompTestSuite.java +++ b/source/java/org/alfresco/util/schemacomp/SchemaCompTestSuite.java @@ -33,8 +33,11 @@ import org.junit.runners.Suite; DbPropertyTest.class, DbToXMLTest.class, DefaultComparisonUtilsTest.class, + DifferenceTest.class, ExportDbTest.class, + RedundantDbObjectTest.class, SchemaComparatorTest.class, + ValidationResultTest.class, ValidatingVisitorTest.class, SchemaToXMLTest.class, XMLToSchemaTest.class diff --git a/source/java/org/alfresco/util/schemacomp/SchemaCompTestingUtils.java b/source/java/org/alfresco/util/schemacomp/SchemaCompTestingUtils.java index 847575bf27..a6a79eec7a 100644 --- a/source/java/org/alfresco/util/schemacomp/SchemaCompTestingUtils.java +++ b/source/java/org/alfresco/util/schemacomp/SchemaCompTestingUtils.java @@ -36,23 +36,30 @@ import org.apache.commons.lang.ArrayUtils; public class SchemaCompTestingUtils { - public static void dumpValidation(List validationResults) + public static void dumpValidation(Results results) { - System.out.println("Validation Results (" + validationResults.size() + ")"); - for (ValidationResult r : validationResults) + System.out.println("Validation Results (" + results.size() + ")"); + for (Result r : results) { - System.out.println(r); + if (r instanceof ValidationResult) + { + System.out.println(r); + } } } public static void dumpDiffs(Results differences, boolean showNonDifferences) { 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) { - System.out.println(d); + Difference diff = (Difference) d; + if (diff.getWhere() != Where.IN_BOTH_NO_DIFFERENCE || showNonDifferences) + { + System.out.println(d); + } } } } diff --git a/source/java/org/alfresco/util/schemacomp/SchemaComparator.java b/source/java/org/alfresco/util/schemacomp/SchemaComparator.java index b089174be5..137895d6ef 100644 --- a/source/java/org/alfresco/util/schemacomp/SchemaComparator.java +++ b/source/java/org/alfresco/util/schemacomp/SchemaComparator.java @@ -18,9 +18,6 @@ */ 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.model.Schema; import org.hibernate.dialect.Dialect; @@ -48,7 +45,7 @@ public class SchemaComparator { this.referenceSchema = referenceSchema; this.targetSchema = targetSchema; - this.ctx = new DiffContext(dialect, new Results(), new ArrayList(), 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 the validation results. - */ - public List getValidationResults() - { - return ctx.getValidationResults(); + return ctx.getComparisonResults(); } } diff --git a/source/java/org/alfresco/util/schemacomp/SchemaComparatorTest.java b/source/java/org/alfresco/util/schemacomp/SchemaComparatorTest.java index 362b4c394e..bee4269269 100644 --- a/source/java/org/alfresco/util/schemacomp/SchemaComparatorTest.java +++ b/source/java/org/alfresco/util/schemacomp/SchemaComparatorTest.java @@ -29,7 +29,6 @@ import static org.alfresco.util.schemacomp.SchemaCompTestingUtils.pk; import static org.alfresco.util.schemacomp.SchemaCompTestingUtils.table; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertSame; import java.util.Arrays; import java.util.Iterator; @@ -57,8 +56,8 @@ public class SchemaComparatorTest @Before public void setup() { - reference = new Schema("reference_schema"); - target = new Schema("target_schema"); + reference = new Schema("schema"); + target = new Schema("schema"); dialect = new MySQL5InnoDBDialect(); } @@ -87,67 +86,55 @@ public class SchemaComparatorTest comparator.validateAndCompare(); // See stdout for diagnostics dump... - dumpDiffs(comparator.getDifferences(), false); - dumpValidation(comparator.getValidationResults()); + dumpDiffs(comparator.getComparisonResults(), false); + dumpValidation(comparator.getComparisonResults()); - Results differences = comparator.getDifferences(); + Results results = comparator.getComparisonResults(); - Iterator it = differences.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()); + Iterator it = results.iterator(); // 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("reference_schema.table_in_reference", diff.getLeft().getPath()); + assertEquals("schema.table_in_reference", diff.getLeft().getPath()); assertEquals(null, diff.getRight()); assertEquals(null, diff.getLeft().getPropertyName()); assertEquals(null, diff.getLeft().getPropertyValue()); // 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("reference_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[0]", diff.getLeft().getPath()); + assertEquals("schema.tbl_has_diff_pk.pk_is_diff.columnNames", diff.getRight().getPath()); assertEquals("columnNames[0]", diff.getLeft().getPropertyName()); assertEquals("id", diff.getLeft().getPropertyValue()); assertEquals("columnNames", diff.getRight().getPropertyName()); assertEquals(Arrays.asList("nodeRef"), diff.getRight().getPropertyValue()); // 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("reference_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", diff.getLeft().getPath()); + assertEquals("schema.tbl_has_diff_pk.pk_is_diff.columnNames[0]", diff.getRight().getPath()); assertEquals("columnNames", diff.getLeft().getPropertyName()); assertEquals(Arrays.asList("id"), diff.getLeft().getPropertyValue()); assertEquals("columnNames[0]", diff.getRight().getPropertyName()); assertEquals("nodeRef", diff.getRight().getPropertyValue()); // idx_two is unique in the righ_schema but not in the reference - diff = it.next(); - assertEquals("reference_schema.tbl_has_diff_pk.idx_two.unique", diff.getLeft().getPath()); - assertEquals("target_schema.tbl_has_diff_pk.idx_two.unique", diff.getRight().getPath()); + diff = (Difference) it.next(); + assertEquals("schema.tbl_has_diff_pk.idx_two.unique", diff.getLeft().getPath()); + assertEquals("schema.tbl_has_diff_pk.idx_two.unique", diff.getRight().getPath()); assertEquals("unique", diff.getLeft().getPropertyName()); assertEquals(false, diff.getLeft().getPropertyValue()); assertEquals("unique", diff.getRight().getPropertyName()); assertEquals(true, diff.getRight().getPropertyValue()); // 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("target_schema.table_in_target", diff.getRight().getPath()); + assertEquals("schema.table_in_target", diff.getRight().getPath()); assertEquals(null, diff.getLeft()); assertEquals(null, diff.getRight().getPropertyName()); assertEquals(null, diff.getRight().getPropertyValue()); diff --git a/source/java/org/alfresco/util/schemacomp/ValidatingVisitor.java b/source/java/org/alfresco/util/schemacomp/ValidatingVisitor.java index b788a482b5..2886d78500 100644 --- a/source/java/org/alfresco/util/schemacomp/ValidatingVisitor.java +++ b/source/java/org/alfresco/util/schemacomp/ValidatingVisitor.java @@ -44,7 +44,10 @@ public class ValidatingVisitor implements DbObjectVisitor { List 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 // using each of the available validators for that reference object. diff --git a/source/java/org/alfresco/util/schemacomp/ValidatingVisitorTest.java b/source/java/org/alfresco/util/schemacomp/ValidatingVisitorTest.java index 6c839cb8cb..95c2e5be18 100644 --- a/source/java/org/alfresco/util/schemacomp/ValidatingVisitorTest.java +++ b/source/java/org/alfresco/util/schemacomp/ValidatingVisitorTest.java @@ -31,6 +31,7 @@ import org.alfresco.util.schemacomp.validator.DbValidator; import org.hibernate.dialect.MySQL5InnoDBDialect; import org.junit.Before; import org.junit.Test; +import static org.junit.Assert.*; import org.mockito.Mockito; /** @@ -59,8 +60,7 @@ public class ValidatingVisitorTest { refTable = new Table("reference_table"); refIndex = new Index(refTable, "index_name", Arrays.asList("a", "b", "c")); - ctx = new DiffContext(new MySQL5InnoDBDialect(), new Results(), - new ArrayList(), refSchema, targetSchema); + ctx = new DiffContext(new MySQL5InnoDBDialect(), refSchema, targetSchema); visitor = new ValidatingVisitor(ctx); validators = new ArrayList(); @@ -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()); + } } diff --git a/source/java/org/alfresco/util/schemacomp/ValidationResult.java b/source/java/org/alfresco/util/schemacomp/ValidationResult.java index 3447287c81..ca360c605c 100644 --- a/source/java/org/alfresco/util/schemacomp/ValidationResult.java +++ b/source/java/org/alfresco/util/schemacomp/ValidationResult.java @@ -56,6 +56,21 @@ public class ValidationResult extends Result 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. */ diff --git a/source/java/org/alfresco/util/schemacomp/ValidationResultTest.java b/source/java/org/alfresco/util/schemacomp/ValidationResultTest.java new file mode 100644 index 0000000000..2ebba20e51 --- /dev/null +++ b/source/java/org/alfresco/util/schemacomp/ValidationResultTest.java @@ -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 . + */ +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()); + } +} diff --git a/source/java/org/alfresco/util/schemacomp/model/AbstractDbObject.java b/source/java/org/alfresco/util/schemacomp/model/AbstractDbObject.java index 24256910ad..a02d691350 100644 --- a/source/java/org/alfresco/util/schemacomp/model/AbstractDbObject.java +++ b/source/java/org/alfresco/util/schemacomp/model/AbstractDbObject.java @@ -96,16 +96,35 @@ public abstract class AbstractDbObject implements DbObject @Override 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) { - return getName().equals(other.getName()); - } - else - { - // Only other way we can know if they are the same is if they are - // the exact same object reference. - return this == other; + boolean sameParent = false; + + if (getParent() == null && other.getParent() == null) + { + sameParent = true; + } + else if (getParent() != null && getParent().sameAs(other.getParent())) + { + sameParent = true; + } + return sameParent && getName().equals(other.getName()); } + + return false; } @Override diff --git a/source/java/org/alfresco/util/schemacomp/model/AbstractDbObjectTest.java b/source/java/org/alfresco/util/schemacomp/model/AbstractDbObjectTest.java index f4a2588ee5..068c25ffa0 100644 --- a/source/java/org/alfresco/util/schemacomp/model/AbstractDbObjectTest.java +++ b/source/java/org/alfresco/util/schemacomp/model/AbstractDbObjectTest.java @@ -23,7 +23,6 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.inOrder; -import java.util.ArrayList; import java.util.Arrays; 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.Result.Strength; 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.DbValidator; import org.hibernate.dialect.Dialect; @@ -64,7 +62,7 @@ public class AbstractDbObjectTest public void setUp() throws Exception { dbObject = new ConcreteDbObject("the_object"); - ctx = new DiffContext(dialect, differences, new ArrayList(), null, null); + ctx = new DiffContext(dialect, differences, null, null); } @Test @@ -83,7 +81,8 @@ public class AbstractDbObjectTest dbObject.setName("the_name"); 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("The very same object with non-null name", dbObject.sameAs(dbObject)); } @@ -146,7 +145,7 @@ public class AbstractDbObjectTest @Override protected void doDiff(DbObject right, DiffContext ctx, Strength strength) { - Results differences = ctx.getDifferences(); + Results differences = ctx.getComparisonResults(); differences.add( Where.IN_BOTH_BUT_DIFFERENCE, 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 validatorList(DbValidator... validators) { diff --git a/source/java/org/alfresco/util/schemacomp/model/Column.java b/source/java/org/alfresco/util/schemacomp/model/Column.java index 3f16abf7f7..1b33308a7b 100644 --- a/source/java/org/alfresco/util/schemacomp/model/Column.java +++ b/source/java/org/alfresco/util/schemacomp/model/Column.java @@ -131,4 +131,28 @@ public class Column extends AbstractDbObject { 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; + } } diff --git a/source/java/org/alfresco/util/schemacomp/model/ColumnTest.java b/source/java/org/alfresco/util/schemacomp/model/ColumnTest.java index fce99ea3a6..2048a9cd19 100644 --- a/source/java/org/alfresco/util/schemacomp/model/ColumnTest.java +++ b/source/java/org/alfresco/util/schemacomp/model/ColumnTest.java @@ -23,6 +23,7 @@ import org.alfresco.util.schemacomp.DbProperty; import org.junit.Before; import org.junit.Test; import static org.mockito.Mockito.*; +import static org.junit.Assert.*; /** * Tests for the Column class. @@ -73,5 +74,24 @@ public class ColumnTest extends DbObjectTestBase 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)); + } } diff --git a/source/java/org/alfresco/util/schemacomp/model/DbObjectTestBase.java b/source/java/org/alfresco/util/schemacomp/model/DbObjectTestBase.java index c4e594957d..5891e5efa6 100644 --- a/source/java/org/alfresco/util/schemacomp/model/DbObjectTestBase.java +++ b/source/java/org/alfresco/util/schemacomp/model/DbObjectTestBase.java @@ -18,7 +18,7 @@ */ package org.alfresco.util.schemacomp.model; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.inOrder; import java.util.ArrayList; 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.DbProperty; import org.alfresco.util.schemacomp.DiffContext; -import org.alfresco.util.schemacomp.Results; 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.junit.Before; import org.junit.Test; @@ -61,7 +60,7 @@ public abstract class DbObjectTestBase // Check that the correct calls happened in the correct order. List mocks = getMocksUsedInDiff(); inOrder = inOrder(mocks.toArray()); - ctx = new DiffContext(dialect, differences, new ArrayList(), null, null); + ctx = new DiffContext(dialect, differences, null, null); } diff --git a/source/java/org/alfresco/util/schemacomp/validator/NameValidator.java b/source/java/org/alfresco/util/schemacomp/validator/NameValidator.java index 9d68522ed6..b79401259b 100644 --- a/source/java/org/alfresco/util/schemacomp/validator/NameValidator.java +++ b/source/java/org/alfresco/util/schemacomp/validator/NameValidator.java @@ -49,7 +49,7 @@ public class NameValidator implements DbValidator if (pattern != null && !pattern.matcher(name).matches()) { - ctx.getValidationResults().add(result); + ctx.getComparisonResults().add(result); } } diff --git a/source/java/org/alfresco/util/schemacomp/validator/NameValidatorTest.java b/source/java/org/alfresco/util/schemacomp/validator/NameValidatorTest.java index 9a1f5baa2a..63bb07a0d4 100644 --- a/source/java/org/alfresco/util/schemacomp/validator/NameValidatorTest.java +++ b/source/java/org/alfresco/util/schemacomp/validator/NameValidatorTest.java @@ -22,7 +22,6 @@ package org.alfresco.util.schemacomp.validator; import static org.junit.Assert.assertEquals; import java.util.ArrayList; -import java.util.List; import java.util.regex.Pattern; import org.alfresco.util.schemacomp.DiffContext; @@ -43,14 +42,14 @@ public class NameValidatorTest { private NameValidator validator; private DiffContext ctx; - private List validationResults; + private Results validationResults; @Before public void setUp() throws Exception { validator = new NameValidator(); - validationResults = new ArrayList(); - ctx = new DiffContext(new Oracle10gDialect(), new Results(), validationResults, null, null); + validationResults = new Results(); + ctx = new DiffContext(new Oracle10gDialect(), validationResults, null, null); } @Test @@ -63,8 +62,8 @@ public class NameValidatorTest validator.validate(null, indexForName("MY_INDEX"), ctx); assertEquals(2, validationResults.size()); - assertEquals("SYS_", validationResults.get(0).getValue()); - assertEquals("MY_INDEX", validationResults.get(1).getValue()); + assertEquals("SYS_", ((ValidationResult) validationResults.get(0)).getValue()); + assertEquals("MY_INDEX", ((ValidationResult) validationResults.get(1)).getValue()); } @Test @@ -76,7 +75,7 @@ public class NameValidatorTest validator.validate(null, indexForName("SYS_MYINDEX"), ctx); assertEquals(1, validationResults.size()); - assertEquals("SYS_MYINDEX", validationResults.get(0).getValue()); + assertEquals("SYS_MYINDEX", ((ValidationResult) validationResults.get(0)).getValue()); }