package liquibase.serializer.core.string; import liquibase.change.*; import liquibase.change.core.*; import liquibase.change.custom.CustomChangeWrapper; import liquibase.change.custom.CustomSqlChange; import liquibase.change.custom.ExampleCustomSqlChange; import liquibase.logging.Logger; import liquibase.resource.ClassLoaderResourceAccessor; import liquibase.resource.ResourceAccessor; import liquibase.statement.DatabaseFunction; import static org.junit.Assert.*; import org.junit.Test; import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.math.BigInteger; import java.util.*; public class StringChangeLogSerializerTest { @Test public void serialized_CustomChange() throws Exception { String expectedString = "customChange:[\n" + " className=\"liquibase.change.custom.ExampleCustomSqlChange\"\n" + " paramValues={\n" + " columnName=\"column_name\",\n" + " newValue=\"new_value\",\n" + " tableName=\"table_name\"\n" + " }\n" + "]"; CustomChangeWrapper wrapper = new CustomChangeWrapper(); wrapper.setResourceAccessor(new ClassLoaderResourceAccessor()); //wrapper.setFileOpener(new JUnitResourceAccessor()); //wrapper.setClassLoader(new JUnitResourceAccessor().toClassLoader()); wrapper.setClassLoader(getClass().getClassLoader()); wrapper.setClass("liquibase.change.custom.ExampleCustomSqlChange"); wrapper.setParam("columnName", "column_name"); wrapper.setParam("newValue", "new_value"); wrapper.setParam("tableName", "table_name"); assertEquals(expectedString, new StringChangeLogSerializer().serialize(wrapper)); } @Test public void serialized_AddColumnChange() { AddColumnChange change = new AddColumnChange(); assertEquals("addColumn:[\n" + " columns=[]\n" + "]", new StringChangeLogSerializer().serialize(change)); change.setTableName("TABLE_NAME"); assertEquals("addColumn:[\n" + " columns=[]\n" + " tableName=\"TABLE_NAME\"\n" + "]", new StringChangeLogSerializer().serialize(change)); change.setSchemaName("SCHEMA_NAME"); assertEquals("addColumn:[\n" + " columns=[]\n" + " schemaName=\"SCHEMA_NAME\"\n" + " tableName=\"TABLE_NAME\"\n" + "]", new StringChangeLogSerializer().serialize(change)); ColumnConfig column = new ColumnConfig(); change.addColumn(column); column.setName("COLUMN_NAME"); assertEquals("addColumn:[\n" + " columns=[\n" + " column:[\n" + " name=\"COLUMN_NAME\"\n" + " ]\n" + " ]\n" + " schemaName=\"SCHEMA_NAME\"\n" + " tableName=\"TABLE_NAME\"\n" + "]", new StringChangeLogSerializer().serialize(change)); ColumnConfig column2 = new ColumnConfig(); change.addColumn(column2); column2.setName("COLUMN2_NAME"); column2.setAutoIncrement(true); column2.setValueNumeric(52); assertEquals("addColumn:[\n" + " columns=[\n" + " column:[\n" + " name=\"COLUMN_NAME\"\n" + " ],\n" + " column:[\n" + " autoIncrement=\"true\"\n" + " name=\"COLUMN2_NAME\"\n" + " valueNumeric=\"52\"\n" + " ]\n" + " ]\n" + " schemaName=\"SCHEMA_NAME\"\n" + " tableName=\"TABLE_NAME\"\n" + "]", new StringChangeLogSerializer().serialize(change)); } @Test public void serialized_AddForeignKeyConstraint() { AddForeignKeyConstraintChange change = new AddForeignKeyConstraintChange(); assertEquals("addForeignKeyConstraint:[]", new StringChangeLogSerializer().serialize(change)); change.setBaseTableName("TABLE_NAME"); change.setBaseColumnNames("COL1, COL2"); change.setBaseTableSchemaName("BASE_SCHEM"); change.setConstraintName("FK_TEST"); change.setDeferrable(true); change.setInitiallyDeferred(true); change.setReferencesUniqueColumn(false); change.setDeleteCascade(true); change.setOnDelete("SET NULL"); change.setOnUpdate("NO ACTION"); change.setReferencedTableName("REF_TABLE"); change.setReferencedColumnNames("COLA, COLB"); change.setReferencedTableSchemaName("REF_SCHEM"); assertEquals("addForeignKeyConstraint:[\n" + " baseColumnNames=\"COL1, COL2\"\n" + " baseTableName=\"TABLE_NAME\"\n" + " baseTableSchemaName=\"BASE_SCHEM\"\n" + " constraintName=\"FK_TEST\"\n" + " deferrable=\"true\"\n" + " initiallyDeferred=\"true\"\n" + " onDelete=\"SET NULL\"\n" + " onUpdate=\"NO ACTION\"\n" + " referencedColumnNames=\"COLA, COLB\"\n" + " referencedTableName=\"REF_TABLE\"\n" + " referencedTableSchemaName=\"REF_SCHEM\"\n" + " referencesUniqueColumn=\"false\"\n" + "]", new StringChangeLogSerializer().serialize(change)); } @Test public void serialized_AddUniqueKeyConstraint() { AddUniqueConstraintChange change = new AddUniqueConstraintChange(); assertEquals("addUniqueConstraint:[]", new StringChangeLogSerializer().serialize(change)); change.setTableName("TABLE_NAME"); change.setColumnNames("COL1, COL2"); change.setSchemaName("BASE_SCHEM"); change.setConstraintName("FK_TEST"); change.setDeferrable(true); change.setInitiallyDeferred(true); change.setDisabled(true); change.setTablespace("TABLESPACE1"); assertEquals("addUniqueConstraint:[\n" + " columnNames=\"COL1, COL2\"\n" + " constraintName=\"FK_TEST\"\n" + " deferrable=\"true\"\n" + " disabled=\"true\"\n" + " initiallyDeferred=\"true\"\n" + " schemaName=\"BASE_SCHEM\"\n" + " tableName=\"TABLE_NAME\"\n" + " tablespace=\"TABLESPACE1\"\n" + "]", new StringChangeLogSerializer().serialize(change)); } // @Test // public void serialized_changeSet() { // ChangeSet changeSet = new ChangeSet("1", "ted", true, false, "com/example/test.xml", "c:/com/exmple/test", "context1, context2", "mysql, oracle"); // AddColumnChange change = new AddColumnChange(); // changeSet.addChange(change); // // assertEquals("changeSet:[\n" + // " alwaysRun=\"true\"\n" + // " author=\"ted\"\n" + // " contextList=\"context1,context2\"\n" + // " dbmsList=\"mysql,oracle\"\n" + // " filePath=\"com/example/test.xml\"\n" + // " id=\"1\"\n" + // " physicalFilePath=\"c:/com/example/test.xml\"\n" + // " runOnChange=\"false\"\n" + // " changes: [\n" + // " addColumn:[\n" + // " columns=[]\n" + // " ]\n" + // " ]\n" + // "]", new StringChangeLogSerializer().serialize(changeSet)); // } @Test public void serialized_SQLFileChange() { SQLFileChange change = new SQLFileChange(); assertEquals("sqlFile:[\n" + " splitStatements=\"true\"\n" + " stripComments=\"false\"\n]", new StringChangeLogSerializer().serialize(change)); change.setPath("PATH/TO/File.txt"); assertEquals("sqlFile:[\n" + " path=\"PATH/TO/File.txt\"\n" + " splitStatements=\"true\"\n" + " stripComments=\"false\"\n" + "]", new StringChangeLogSerializer().serialize(change)); } @Test public void serialized_rawSql() { RawSQLChange change = new RawSQLChange(); assertEquals("sql:[\n" + " splitStatements=\"true\"\n" + " stripComments=\"false\"\n]", new StringChangeLogSerializer().serialize(change)); change.setSql("some SQL Here"); assertEquals("sql:[\n" + " splitStatements=\"true\"\n" + " sql=\"some SQL Here\"\n" + " stripComments=\"false\"\n" + "]", new StringChangeLogSerializer().serialize(change)); } @Test public void tryAllChanges() throws Exception { for (SortedSet<Class<? extends Change>> changeClassSet : ChangeFactory.getInstance().getRegistry().values()) { Change change = changeClassSet.iterator().next().getConstructor().newInstance(); setFields(change); String string = new StringChangeLogSerializer().serialize(change); // System.out.println(string); // System.out.println("-------------"); assertTrue("@ in string. Probably poorly serialzed object reference." + string, string.indexOf("@") < 0); } } private void setFields(Object object) throws Exception { Class clazz = object.getClass(); if (clazz.getName().indexOf(".ext.") > 0) { return; //don't worry about ext samples } for (Field field : clazz.getDeclaredFields()) { if (field.getAnnotation(ChangeProperty.class) != null && !field.getAnnotation(ChangeProperty.class).includeInSerialization()) { continue; } field.setAccessible(true); if (field.getType().getName().equals("[[Z")) { //nothing, from emma } else if (field.getName().equals("serialVersionUID")) { //nothing } else if (field.getType().equals(Logger.class)) { //nothing } else if (field.getType().equals(ResourceAccessor.class)) { //nothing } else if (field.getType().equals(ClassLoader.class)) { //nothing } else if (field.getType().equals(long.class)) { field.set(object, createInteger().longValue()); } else if (field.getType().equals(String.class)) { field.set(object, createString()); } else if (field.getType().equals(Number.class)) { field.set(object, createNumber()); } else if (field.getType().equals(Integer.class)) { field.set(object, createInteger()); } else if (field.getType().equals(BigInteger.class)) { field.set(object, createBigInteger()); } else if (field.getType().equals(Date.class)) { field.set(object, createDate()); } else if (field.getType().equals(Boolean.class)) { field.set(object, createBoolean()); } else if (field.getType().equals(ColumnConfig.class)) { field.set(object, createColumnConfig()); } else if (field.getType().equals(DatabaseFunction.class)) { field.set(object, createDatabaseFunction()); } else if (field.getType().equals(ConstraintsConfig.class)) { field.set(object, createConstraintsConfig()); } else if (field.getType().getName().equals("liquibase.change.custom.CustomChange")) { field.set(object, createCustomChange()); } else if (field.getType().equals(Map.class)) { field.set(object, createMap()); } else if (Collection.class.isAssignableFrom(field.getType())) { Type genericType = field.getGenericType(); if (genericType instanceof ParameterizedType) { int genericsLength = ((ParameterizedType) genericType).getActualTypeArguments().length; if (genericsLength == 1) { Class typeToCreate = (Class) ((ParameterizedType) genericType).getActualTypeArguments()[0]; Collection collection; if (field.getType().equals(List.class)) { collection = new ArrayList(); } else if (field.getType().equals(SortedSet.class)) { collection = new TreeSet(); } else { throw new RuntimeException("Unknow collection type: " + field.getType().getName()); } if (typeToCreate.equals(ColumnConfig.class)) { collection.add(createColumnConfig()); collection.add(createColumnConfig()); } else if (typeToCreate.equals(LoadDataColumnConfig.class)) { collection.add(createLoadDataColumnConfig()); collection.add(createLoadDataColumnConfig()); } else if (typeToCreate.equals(String.class)) { collection.add(createString()); collection.add(createString()); } else { throw new RuntimeException("Unknown generic type for " + clazz.getName() + "." + field.getName() + ": " + typeToCreate.getName()); } field.set(object, collection); } else { throw new RuntimeException("Found " + genericsLength + " generics for " + clazz.getName() + "." + field.getName()); } } else { fail("List not generic"); } } else { fail("Unknown field type in " + clazz.getName() + ": " + field.getType().getName()); } } } private LoadDataColumnConfig createLoadDataColumnConfig() throws Exception { LoadDataColumnConfig config = new LoadDataColumnConfig(); setFields(config); return config; } private String createString() { return Long.toString(Math.abs(new Random().nextLong()), 36); } private Number createNumber() { return new Random().nextDouble() * 10000; } private Integer createInteger() { return new Random().nextInt(); } private BigInteger createBigInteger() { return new BigInteger(20, new Random()); } private Date createDate() { return new Date(new Random().nextLong()); } private Boolean createBoolean() { return true; } private Map createMap() { Map map = new HashMap(); map.put(createString(), createString()); map.put(createString(), createString()); map.put(createString(), createString()); return map; } private ColumnConfig createColumnConfig() throws Exception { ColumnConfig config = new ColumnConfig(); setFields(config); return config; } private DatabaseFunction createDatabaseFunction() throws Exception { DatabaseFunction function = new DatabaseFunction("FUNCTION_HERE"); setFields(function); return function; } private ConstraintsConfig createConstraintsConfig() throws Exception { ConstraintsConfig config = new ConstraintsConfig(); setFields(config); return config; } private CustomSqlChange createCustomChange() throws Exception { CustomSqlChange config = new ExampleCustomSqlChange(); setFields(config); return config; } }