All Downloads are FREE. Search and download functionalities are using the official Maven repository.

liquibase.harness.diff.DiffCommandTestHelper.groovy Maven / Gradle / Ivy

There is a newer version: 1.0.10
Show newest version
package liquibase.harness.diff


import groovy.transform.builder.Builder
import liquibase.diff.DiffResult
import liquibase.diff.Difference
import liquibase.diff.ObjectDifferences
import liquibase.diff.compare.CompareControl
import liquibase.diff.output.DiffOutputControl
import liquibase.diff.output.changelog.DiffToChangeLog
import liquibase.harness.config.DatabaseUnderTest
import liquibase.harness.config.TestConfig
import liquibase.harness.util.DatabaseConnectionUtil
import liquibase.structure.DatabaseObject
import liquibase.structure.core.Column
import liquibase.structure.core.ForeignKey
import liquibase.structure.core.Index
import liquibase.structure.core.PrimaryKey
import liquibase.structure.core.Table
import liquibase.structure.core.Sequence
import liquibase.structure.core.UniqueConstraint
import liquibase.structure.core.View
import org.yaml.snakeyaml.Yaml

import java.util.stream.Collectors

import static liquibase.util.StringUtil.isNotEmpty

class DiffCommandTestHelper {

    static CompareControl buildCompareControl() {
        CompareControl compareControl
        Set> typesToInclude = new HashSet>()
        typesToInclude.add(Table.class)
        typesToInclude.add(Column.class)
        typesToInclude.add(PrimaryKey.class)
        typesToInclude.add(ForeignKey.class)
        typesToInclude.add(UniqueConstraint.class)
        typesToInclude.add(Sequence.class)
        typesToInclude.add(View.class)
        compareControl = new CompareControl(typesToInclude)
        compareControl.addSuppressedField(Table.class, "remarks")
        compareControl.addSuppressedField(Column.class, "remarks")
        compareControl.addSuppressedField(Column.class, "certainDataType")
        compareControl.addSuppressedField(Column.class, "autoIncrementInformation")
        compareControl.addSuppressedField(ForeignKey.class, "deleteRule")
        compareControl.addSuppressedField(ForeignKey.class, "updateRule")
        compareControl.addSuppressedField(Index.class, "unique")
        return compareControl
    }

    static List buildTestInput() {

        Yaml configFileYml = new Yaml()
        InputStream testConfig = DiffCommandTestHelper.class.getResourceAsStream("/liquibase/harness/diff/diffDatabases.yml")
        assert testConfig != null: "Cannot find diffDatabases.yml in classpath"

        List targetToReferences = configFileYml.loadAs(testConfig, DiffDatabases.class).references

        List inputList = new ArrayList<>()
        List databasesToConnect = new ArrayList<>()
        for (TargetToReference targetToReference : targetToReferences) {
            DatabaseUnderTest targetDatabase
            List matchingTargetDatabases = TestConfig.instance.databasesUnderTest.stream()
                    .filter({ it -> it.name.equalsIgnoreCase(targetToReference.targetDatabaseName) })
                    .collect(Collectors.toList())
            if (matchingTargetDatabases.size() == 1) {
                targetDatabase = matchingTargetDatabases.get(0)
            } else if (matchingTargetDatabases.size() > 1 && isNotEmpty(targetToReference.targetDatabaseVersion)) {
                targetDatabase = matchingTargetDatabases.stream()
                        .filter({ it -> targetToReference.targetDatabaseVersion.equalsIgnoreCase(it.version) })
                        .findFirst()
                        .orElseThrow({ ->
                            new IllegalArgumentException(
                                    String.format("Versions in harness-config.yml don't match with targetDatabaseVersion=%s provided in diffDatabases.yml",
                                            targetToReference.targetDatabaseVersion))
                        })
            } else {
                throw new IllegalArgumentException(String.format("can't match target DB for diff test name={%s}, version={%s}", targetToReference.targetDatabaseName, targetToReference.targetDatabaseVersion))
            }
            databasesToConnect.add(targetDatabase)

            DatabaseUnderTest referenceDatabase
            List matchingReferenceDatabases = TestConfig.instance.databasesUnderTest.stream()
                    .filter({ it -> it.name.equalsIgnoreCase(targetToReference.referenceDatabaseName) })
                    .collect(Collectors.toList())
            if (matchingReferenceDatabases.size() == 1) {
                referenceDatabase = matchingReferenceDatabases.get(0)
            } else if (matchingReferenceDatabases.size() > 1 && isNotEmpty(targetToReference.referenceDatabaseVersion)) {
                referenceDatabase = matchingReferenceDatabases.stream()
                        .filter({ it -> targetToReference.referenceDatabaseVersion.equalsIgnoreCase(it.version) })
                        .findFirst()
                        .orElseThrow({ ->
                            new IllegalArgumentException(
                                    String.format("Versions in harness-config.yml don't match with referenceDatabaseVersion=%s provided in diffDatabases.yml",
                                            targetToReference.referenceDatabaseVersion))
                        })
            } else {
                throw new IllegalArgumentException(String.format("can't match reference DB for diff test name={%s}, version={%s}", targetToReference.referenceDatabaseName, targetToReference.referenceDatabaseVersion))
            }
            databasesToConnect.add(referenceDatabase)

            inputList.add(TestInput.builder()
                    .context(TestConfig.instance.context)
                    .expectedDiffs(targetToReference.expectedDiffs)
                    .targetDatabase(targetDatabase)
                    .referenceDatabase(referenceDatabase)
                    .build())
        }
        DatabaseConnectionUtil databaseConnectionUtil = new DatabaseConnectionUtil()
        databaseConnectionUtil.initializeDatabasesConnection(databasesToConnect)
        return inputList
    }

    static String toChangeLog(DiffResult diffResult) throws Exception {
        ByteArrayOutputStream out = new ByteArrayOutputStream()
        PrintStream printStream = new PrintStream(out, true, "UTF-8")
        DiffOutputControl diffOutputControl = new DiffOutputControl()
        diffOutputControl.setIncludeCatalog(false)
        diffOutputControl.setIncludeSchema(false)
        DiffToChangeLog diffToChangeLog = new DiffToChangeLog(diffResult,
                diffOutputControl)
        diffToChangeLog.print(printStream)
        printStream.close()
        return out.toString("UTF-8")
    }

    static void removeExpectedDiffs(ExpectedDiffs expectedDiffs, DiffResult diffResult) {
        removeUnexpectedObjects(diffResult.getUnexpectedObjects(), expectedDiffs.unexpectedObjects)
        removeMissingObjects(diffResult.getMissingObjects(), expectedDiffs.missingObjects)
        removeChangedObjects(diffResult.getChangedObjects(), expectedDiffs.changedObjects)

    }

    static void removeChangedObjects(Map diffResultMap, List expectedChangedObjects) {
        diffResultMap.entrySet().removeIf({ entry -> entry.key.toString().toUpperCase().contains("DATABASECHANGELOG") })
        diffResultMap.entrySet().removeIf({ entry ->
            doesKeyMatches(entry, expectedChangedObjects)
        })

    }

    static boolean doesKeyMatches(Map.Entry entry, List changedObjects) {
        for (HarnessObjectDifference changedObject : changedObjects) {
            if (entry.key.toString().equalsIgnoreCase(changedObject.diffName))
                return matchDifferences(entry, changedObject)
        }
        return false
    }

    static boolean matchDifferences(Map.Entry entry, HarnessObjectDifference harnessObjectDifference) {
        if (entry.value.differences.size() != harnessObjectDifference.diffs.size()) {
            return false
        }
        Map transformedObjectDiffMap = new HashMap<>()
        for (Difference difference : entry.value.differences) {
            transformedObjectDiffMap.put(difference.field, difference.message)
        }
        return transformedObjectDiffMap == harnessObjectDifference.diffs
    }

    static void removeMissingObjects(Set diffResultMissingObjects, List missingObjectsFromFile) {
        diffResultMissingObjects.removeIf({ object -> object.toString().toUpperCase().contains("DATABASECHANGELOG") })
        diffResultMissingObjects.removeIf({ object -> missingObjectsFromFile?.contains(object.toString()) })
    }

    static void removeUnexpectedObjects(Set diffResultUnexpectedObjects, List unexpectedObjectsFromFile) {
        diffResultUnexpectedObjects.removeIf({ object -> object.toString().toUpperCase().contains("DATABASECHANGELOG") })
        //TODO figure out why null safe isn't working here
        // diffResultUnexpectedObjects.removeIf({ object -> unexpectedObjectsFromFile?.contains(object.toString()) })
        diffResultUnexpectedObjects.removeIf({ object -> unexpectedObjectsFromFile != null && unexpectedObjectsFromFile.contains(object.toString()) })
    }

    static boolean diffsAbsent(DiffResult diffResult) {
        return diffResult.getChangedObjects()?.isEmpty() && diffResult.getMissingObjects()?.isEmpty() && diffResult.getUnexpectedObjects()?.isEmpty()
    }

    @Builder
    static class TestInput {
        String context
        ExpectedDiffs expectedDiffs
        DatabaseUnderTest referenceDatabase
        DatabaseUnderTest targetDatabase
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy