Skip to content

Commit

Permalink
[DAT-12908] GenerateChangelogTest: add verification that 'objects' di…
Browse files Browse the repository at this point in the history
…rectory is created for stored logic objects. (#980)

* DAT-12908 adding "verify that the 'stored objects' directories are created" check

* refactoring GenerateChangelogTest, wip

---------

Co-authored-by: KushnirykOleh <[email protected]>
  • Loading branch information
Tamelianovych and KushnirykOleh authored Jan 23, 2025
1 parent 0d22b72 commit 45d261c
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 93 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package liquibase.harness.generateChangelog

import com.datical.liquibase.ext.config.LiquibaseProConfiguration
import liquibase.Scope
import liquibase.database.jvm.JdbcConnection
import liquibase.exception.CommandExecutionException
Expand All @@ -12,6 +13,8 @@ import spock.lang.Shared
import spock.lang.Specification
import spock.lang.Unroll

import java.nio.file.Paths

import static GenerateChangelogTestHelper.*
import static liquibase.harness.util.TestUtils.*
import static liquibase.harness.util.FileUtils.*
Expand All @@ -23,7 +26,6 @@ class GenerateChangelogTest extends Specification {
List<DatabaseUnderTest> databases
@Shared
UIService uiService = Scope.getCurrentScope().getUI()
String resourcesDirFullPath = System.getProperty("user.dir") + "/src/test/resources/"
String resourcesDirPath = "src/test/resources/"
long timeMillisBeforeTest
long timeMillisAfterTest
Expand All @@ -49,96 +51,83 @@ class GenerateChangelogTest extends Specification {
assert shouldRunChangeSet: "Database ${testInput.databaseName} ${testInput.version} is offline!"

and: "ignore testcase if it's invalid for this combination of db type and/or version"
shouldRunChangeSet = !getResourceContent("/$testInput.sqlChangelogPath").toLowerCase()?.contains("invalid test")
shouldRunChangeSet = !getResourceContent("/$testInput.expectedSqlPath").toLowerCase()?.contains("invalid test")
Assumptions.assumeTrue(shouldRunChangeSet, "INFO: Test for $testInput.change is ignored")

when: "execute update command using xml changelog formats"
argsMap.put("changeLogFile", testInput.inputChangelogFile)
executeCommandScope("update", argsMap)

and: "testing generateChangelog command for all files format"
def map = new LinkedHashMap<String, String>()
map.put("expectedXmlChangelog", testInput.xmlChangelogPath)
map.put("expectedSqlChangelog", testInput.sqlChangelogPath)
map.put("expectedYmlChangelog", testInput.xmlChangelogPath.replace(".xml", ".yml"))
map.put("expectedJsonChangelog", testInput.xmlChangelogPath.replace(".xml", ".json"))
argsMap.put("excludeObjects", "(?i)posts, (?i)authors")//excluding static test-harness objects from generated changelog
String sqlSpecificChangelogFile

for (Map.Entry<String, String> entry : map.entrySet()) {

when: "execute generateChangelog command using different changelog formats"
argsMap.put("changeLogFile", testInput.xmlChangelogPath)
executeCommandScope("update", argsMap)
argsMap.put("excludeObjects", "(?i)posts, (?i)authors")//excluding static test-harness objects from generated changelog
if (entry.key.equalsIgnoreCase("expectedSqlChangelog")) {
def shortDbName = getShortDatabaseName(testInput.databaseName)
sqlSpecificChangelogFile = entry.value.replace(".sql", ".$shortDbName" + ".sql")
argsMap.put("changeLogFile", resourcesDirFullPath + "generated/" + sqlSpecificChangelogFile)
String generatedFolderPath = Paths.get(resourcesDirPath, baseChangelogPath, "generated").toString()
String generatedChangeTypePath = Paths.get(resourcesDirPath, baseChangelogPath, "generated", testInput.databaseName, testInput.change).toString()
def formats = new LinkedHashMap<String, String>()
def shortDbName = getShortDatabaseName(testInput.databaseName)
formats.put("XmlTestCase", generatedChangeTypePath + ".xml")
formats.put("SqlTestCase", generatedChangeTypePath + ".$shortDbName"+".sql")
formats.put("YmlTestCase", generatedChangeTypePath + ".yml")
formats.put("JsonTestCase", generatedChangeTypePath + ".json")

then: "check if a changelog was actually generated and validate it's content"
for (Map.Entry<String, String> entry : formats.entrySet()) {

Map<String, Object> scopeValues = new HashMap<>()
if (entry.key.equalsIgnoreCase("SqlTestCase")) {
scopeValues.put(LiquibaseProConfiguration.INLINE_SQL_KEY.getKey(), true)
} else {
argsMap.put("changeLogFile", resourcesDirFullPath + "generated/" + entry.value)
scopeValues.put(LiquibaseProConfiguration.INLINE_SQL_KEY.getKey(), false)
}
executeCommandScope("generateChangelog", argsMap, testInput.databaseName)

then: "check if a changelog was actually generated and validate it's content"
String generatedChangelog = readFile((String) argsMap.get("changeLogFile"))
if (entry.key.equalsIgnoreCase("expectedSqlChangelog")) {
validateSqlChangelog(getResourceContent("/$entry.value"), generatedChangelog)
} else {
assert generatedChangelog.contains("$testInput.change")
}
clearFolder(generatedFolderPath)

//TODO will be fixed in DAT-14675.
/*
when: "get sql generated for the change set"
String generatedSql
argsMap.put("changeLogFile", resourcesDirFullPath + entry.value)
if (!entry.key.equalsIgnoreCase("expectedSqlChangelog")) {
generatedSql = parseQuery(executeCommandScope("updateSql", argsMap).toString())
generatedSql = removeSchemaNames(generatedSql, testInput.database)
}
argsMap.put("excludeObjects", "(?i)posts, (?i)authors")//excluding static test-harness objects from generated changelog
argsMap.put("changeLogFile", entry.value)
executeCommandScope("generateChangelog", argsMap, scopeValues)

then: "execute updateSql command on generated changelogs"
if (!entry.key.equalsIgnoreCase("expectedSqlChangelog")) {
def expectedSql
try {
expectedSql = parseQuery(getSqlFileContent(testInput.change, testInput.databaseName, testInput.version,
"liquibase/harness/generateChangelog/verificationSql")).toLowerCase()
} catch (NullPointerException exception) {
expectedSql = parseQuery(getSqlFileContent(testInput.change, testInput.databaseName, testInput.version,
"liquibase/harness/generateChangelog/expectedSql")).toLowerCase()
}
def generatedSqlIsCorrect = generatedSql == expectedSql
if (!generatedSqlIsCorrect) {
Scope.getCurrentScope().getUI().sendMessage("FAIL! Expected sql doesn't " +
"match generated sql! \nEXPECTED SQL: \n" + expectedSql + " \n" +
"GENERATED SQL: \n" + generatedSql)
assert generatedSql == expectedSql
String generatedChangelog = readFile((String) argsMap.get("changeLogFile"))
if (entry.key.equalsIgnoreCase("SqlTestCase")) {
validateSqlChangelog(getResourceContent("/$testInput.expectedSqlPath"), generatedChangelog)
} else {
and: "verify that the 'stored objects' directories are created"
def storedObjectTypesMap = [
//Should be fixed by DAT-19461
"createPackage" : (shortDbName == "edb-edb" ? "databasepackage" : "package"),
"createPackageBody" : (shortDbName == "edb-edb" ? "databasepackagebody" : "packagebody"),
"createFunction" : "function",
"createProcedure" : "storedprocedure",
"createTrigger" : "trigger"
]

if (storedObjectTypesMap.keySet().any { changelogType -> testInput.change.equalsIgnoreCase(changelogType) }) {
def expectedObjectType = storedObjectTypesMap[testInput.change]

def originalPath = entry.value
def replacedPath = originalPath.replaceAll(/create\w+\.(xml|yml|json)$/, "") + "objects/" + expectedObjectType

def objectDir = new File(replacedPath)
assert objectDir.exists() && objectDir.isDirectory() :
"Directory for stored object '${expectedObjectType}' was not created at path: ${replacedPath}!"
}
}
*/
and: "rollback changes"
argsMap.put("changeLogFile", testInput.xmlChangelogPath)
strategy.performRollback(argsMap)
}

cleanup: "try to rollback in case a test was failed and delete generated changelogs"
if (shouldRunChangeSet) {
try {
argsMap.put("changeLogFile", testInput.xmlChangelogPath)
argsMap.put("changeLogFile", testInput.inputChangelogFile)
strategy.performRollback(argsMap)
} catch (CommandExecutionException exception) {
//Ignore exception considering a test was successful
}
}
for (Map.Entry<String, String> entry : map.entrySet()) {
if (entry.key.equalsIgnoreCase("expectedSqlChangelog")) {
deleteFile(resourcesDirFullPath + "generated/" + sqlSpecificChangelogFile)
} else {
deleteFile(resourcesDirFullPath + "generated/" + entry.value)
}
}
clearFolder(generatedFolderPath)

where: "test input in next data table"
testInput << buildTestInput()
}



// @Unroll
// def "apply stress test against #testInput.databaseName #testInput.version"() {
// given: "read input data for stress testing"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import liquibase.harness.util.DatabaseConnectionUtil
import liquibase.harness.util.FileUtils
import liquibase.ui.UIService

import java.nio.file.Path
import java.nio.file.Paths

class GenerateChangelogTestHelper {
final static String baseChangelogPath = "liquibase/harness/generateChangelog/"
final static UIService uiService = Scope.getCurrentScope().getUI()
Expand Down Expand Up @@ -44,13 +47,9 @@ class GenerateChangelogTestHelper {
"stress/update", "xml").get(changeLogEntry.key))
.selectChangelogPath(FileUtils.resolveInputFilePaths(databaseUnderTest, baseChangelogPath +
"stress/select", "xml").get(changeLogEntry.key))
.xmlChangelogPath(FileUtils.resolveInputFilePaths(databaseUnderTest, baseChangelogPath +
.inputChangelogFile(FileUtils.resolveInputFilePaths(databaseUnderTest, baseChangelogPath +
"expectedChangeLog", "xml").get(changeLogEntry.key))
.jsonChangelogPath(FileUtils.resolveInputFilePaths(databaseUnderTest, baseChangelogPath +
"expectedChangeLog", "json").get(changeLogEntry.key))
.ymlChangelogPath(FileUtils.resolveInputFilePaths(databaseUnderTest, baseChangelogPath +
"expectedChangeLog", "yml").get(changeLogEntry.key))
.sqlChangelogPath(FileUtils.resolveInputFilePaths(databaseUnderTest, baseChangelogPath +
.expectedSqlPath(FileUtils.resolveInputFilePaths(databaseUnderTest, baseChangelogPath +
"expectedSql", "sql").get(changeLogEntry.key))
.change(changeLogEntry.key)
.database(databaseUnderTest.database)
Expand Down Expand Up @@ -87,9 +86,11 @@ class GenerateChangelogTestHelper {
}
}

static String getSqlSpecificChangelogFile (String dbName, String changelogFileName) {
def replacementName = String.format(".%s.sql", getShortDatabaseName(dbName))
return changelogFileName.replace(".sql", replacementName)
static void clearFolder(String pathToObjectDir) {
Path path = Paths.get(pathToObjectDir)
if (path.toFile().isDirectory()) {
org.apache.commons.io.FileUtils.forceDelete(new File(pathToObjectDir))
}
}

static String removeSchemaNames(String generatedSql, Database database) {
Expand All @@ -112,10 +113,8 @@ class GenerateChangelogTestHelper {
String insertChangelogPath
String updateChangelogPath
String selectChangelogPath
String xmlChangelogPath
String jsonChangelogPath
String ymlChangelogPath
String sqlChangelogPath
String inputChangelogFile
String expectedSqlPath
String dbSchema
String change
Database database
Expand Down
21 changes: 7 additions & 14 deletions src/main/groovy/liquibase/harness/util/TestUtils.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,8 @@ import liquibase.harness.util.rollback.RollbackToDate
import liquibase.resource.SearchPathResourceAccessor
import org.junit.jupiter.api.Assertions

import java.nio.file.Path
import java.nio.file.Paths
import java.util.logging.Logger

import org.apache.commons.io.FileUtils

class TestUtils {

/**
Expand Down Expand Up @@ -68,24 +64,21 @@ class TestUtils {
return outputStream
}

static OutputStream executeCommandScope(String commandName, Map<String, Object> arguments, String dbName) {
static OutputStream executeCommandScope(String commandName, Map<String, Object> arguments, Map<String,Object> scopeValues) {
def commandScope = new CommandScope(commandName)
def outputStream = new ByteArrayOutputStream()
for (Map.Entry<String, Object> entry : arguments) {
commandScope.addArgumentValue(entry.getKey(), entry.getValue())
}
commandScope.setOutput(outputStream)
try {
//TODO investigate and fix mssql issue with autogenerated objects
if (commandName.equals("generateChangelog")) {
String testResourcesPath = String.format("%s/src/test/resources/liquibase/harness/generateChangelog/expectedChangeLog/%s/objects/", System.getProperty("user.dir"), dbName) + ""
Path path = Paths.get(testResourcesPath)
if (path.toFile().isDirectory()) {
FileUtils.forceDelete(new File(testResourcesPath))
}
}
Logger.getLogger(this.class.name).info(String.format("Executing liquibase command: %s ", commandName))
commandScope.execute()
Scope.child(scopeValues, new Scope.ScopedRunner() {
@Override
void run() throws Exception {
commandScope.execute()
}
})

} catch (Exception exception) {
if (exception instanceof CommandExecutionException && exception.toString().contains("is not available in SQL output mode")) {
Expand Down

0 comments on commit 45d261c

Please sign in to comment.