/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.schemaupdate.foreignkeys.crossschema;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.model.relational.Database;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.hibernate.tool.hbm2ddl.SchemaUpdate;
import org.hibernate.tool.schema.SourceType;
import org.hibernate.tool.schema.TargetType;
import org.hibernate.tool.schema.internal.DefaultSchemaFilter;
import org.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl;
import org.hibernate.tool.schema.internal.HibernateSchemaManagementTool;
import org.hibernate.tool.schema.internal.GroupedSchemaMigratorImpl;
import org.hibernate.tool.schema.internal.SchemaDropperImpl;
import org.hibernate.tool.schema.internal.IndividuallySchemaMigratorImpl;
import org.hibernate.tool.schema.internal.exec.GenerationTarget;
import org.hibernate.tool.schema.internal.exec.GenerationTargetToStdout;
import org.hibernate.tool.schema.spi.ExceptionHandler;
import org.hibernate.tool.schema.spi.ExecutionOptions;
import org.hibernate.tool.schema.spi.SchemaManagementTool;
import org.hibernate.tool.schema.spi.ScriptSourceInput;
import org.hibernate.tool.schema.spi.ScriptTargetOutput;
import org.hibernate.tool.schema.spi.SourceDescriptor;
import org.hibernate.tool.schema.spi.TargetDescriptor;
import org.hibernate.testing.DialectChecks;
import org.hibernate.testing.RequiresDialectFeature;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseUnitTestCase;
import org.hibernate.test.tool.schema.TargetDatabaseImpl;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
/**
* @author Andrea Boriero
*/
@RequiresDialectFeature( value = DialectChecks.SupportSchemaCreation.class)
public class CrossSchemaForeignKeyGenerationTest extends BaseUnitTestCase {
private File output;
private StandardServiceRegistry ssr;
@Before
public void setUp() throws IOException {
output = File.createTempFile( "update_script", ".sql" );
output.deleteOnExit();
ssr = new StandardServiceRegistryBuilder().applySetting( AvailableSettings.HBM2DLL_CREATE_SCHEMAS, "true" )
.build();
}
@After
public void tearsDown() {
StandardServiceRegistryBuilder.destroy( ssr );
}
@Test
@TestForIssue(jiraKey = "HHH-10420")
public void testSchemaExportForeignKeysAreGeneratedAfterAllTheTablesAreCreated() throws Exception {
final MetadataSources metadataSources = new MetadataSources( ssr );
metadataSources.addAnnotatedClass( SchemaOneEntity.class );
metadataSources.addAnnotatedClass( SchemaTwoEntity.class );
MetadataImplementor metadata = (MetadataImplementor) metadataSources.buildMetadata();
metadata.validate();
new SchemaExport().setHaltOnError( true )
.setOutputFile( output.getAbsolutePath() )
.setFormat( false )
.create( EnumSet.of( TargetType.SCRIPT, TargetType.STDOUT ), metadata );
final List<String> sqlLines = Files.readAllLines( output.toPath(), Charset.defaultCharset() );
assertThat(
"Expected alter table SCHEMA1.Child add constraint but is : " + sqlLines.get( 4 ),
sqlLines.get( sqlLines.size() - 1 ).startsWith( "alter table " ),
is( true )
);
}
@Test
@TestForIssue(jiraKey = "HHH-10802")
public void testSchemaUpdateDoesNotFailResolvingCrossSchemaForeignKey() throws Exception {
final MetadataSources metadataSources = new MetadataSources( ssr );
metadataSources.addAnnotatedClass( SchemaOneEntity.class );
metadataSources.addAnnotatedClass( SchemaTwoEntity.class );
MetadataImplementor metadata = (MetadataImplementor) metadataSources.buildMetadata();
metadata.validate();
new SchemaExport()
.setOutputFile( output.getAbsolutePath() )
.setFormat( false )
.create( EnumSet.of( TargetType.DATABASE ), metadata );
new SchemaUpdate().setHaltOnError( true )
.setOutputFile( output.getAbsolutePath() )
.setFormat( false )
.execute( EnumSet.of( TargetType.DATABASE ), metadata );
new SchemaExport().setHaltOnError( true )
.setOutputFile( output.getAbsolutePath() )
.setFormat( false )
.drop( EnumSet.of( TargetType.DATABASE ), metadata );
}
@Test
@TestForIssue(jiraKey = "HHH-10420")
public void testSchemaMigrationForeignKeysAreGeneratedAfterAllTheTablesAreCreated() throws Exception {
final MetadataSources metadataSources = new MetadataSources( ssr );
metadataSources.addAnnotatedClass( SchemaOneEntity.class );
metadataSources.addAnnotatedClass( SchemaTwoEntity.class );
MetadataImplementor metadata = (MetadataImplementor) metadataSources.buildMetadata();
metadata.validate();
final Database database = metadata.getDatabase();
final HibernateSchemaManagementTool tool = (HibernateSchemaManagementTool) ssr.getService( SchemaManagementTool.class );
final Map configurationValues = ssr.getService( ConfigurationService.class ).getSettings();
final ExecutionOptions options = new ExecutionOptions() {
@Override
public boolean shouldManageNamespaces() {
return true;
}
@Override
public Map getConfigurationValues() {
return configurationValues;
}
@Override
public ExceptionHandler getExceptionHandler() {
return ExceptionHandlerLoggedImpl.INSTANCE;
}
};
new IndividuallySchemaMigratorImpl( tool, DefaultSchemaFilter.INSTANCE ).doMigration(
metadata,
options,
TargetDescriptorImpl.INSTANCE
);
new IndividuallySchemaMigratorImpl( tool, DefaultSchemaFilter.INSTANCE ).doMigration(
metadata,
options,
TargetDescriptorImpl.INSTANCE
);
new SchemaDropperImpl( tool ).doDrop(
metadata,
options,
ssr.getService( JdbcEnvironment.class ).getDialect(),
new SourceDescriptor() {
@Override
public SourceType getSourceType() {
return SourceType.METADATA;
}
@Override
public ScriptSourceInput getScriptSourceInput() {
return null;
}
},
buildTargets()
);
}
@Test
@TestForIssue(jiraKey = "HHH-10420")
public void testImprovedSchemaMigrationForeignKeysAreGeneratedAfterAllTheTablesAreCreated() throws Exception {
final MetadataSources metadataSources = new MetadataSources( ssr );
metadataSources.addAnnotatedClass( SchemaOneEntity.class );
metadataSources.addAnnotatedClass( SchemaTwoEntity.class );
MetadataImplementor metadata = (MetadataImplementor) metadataSources.buildMetadata();
metadata.validate();
final HibernateSchemaManagementTool tool = (HibernateSchemaManagementTool) ssr.getService( SchemaManagementTool.class );
final Map configurationValues = ssr.getService( ConfigurationService.class ).getSettings();
final ExecutionOptions options = new ExecutionOptions() {
@Override
public boolean shouldManageNamespaces() {
return true;
}
@Override
public Map getConfigurationValues() {
return configurationValues;
}
@Override
public ExceptionHandler getExceptionHandler() {
return ExceptionHandlerLoggedImpl.INSTANCE;
}
};
new GroupedSchemaMigratorImpl( tool, DefaultSchemaFilter.INSTANCE ).doMigration(
metadata,
options,
TargetDescriptorImpl.INSTANCE
);
new SchemaDropperImpl( tool ).doDrop(
metadata,
options,
ssr.getService( JdbcEnvironment.class ).getDialect(),
new SourceDescriptor() {
@Override
public SourceType getSourceType() {
return SourceType.METADATA;
}
@Override
public ScriptSourceInput getScriptSourceInput() {
return null;
}
},
buildTargets()
);
}
public GenerationTarget[] buildTargets() {
return new GenerationTarget[] {
new GenerationTargetToStdout(),
new TargetDatabaseImpl( ssr.getService( JdbcServices.class ).getBootstrapJdbcConnectionAccess() )
};
}
private static class TargetDescriptorImpl implements TargetDescriptor {
public static final TargetDescriptorImpl INSTANCE = new TargetDescriptorImpl();
@Override
public EnumSet<TargetType> getTargetTypes() {
return EnumSet.of( TargetType.DATABASE );
}
@Override
public ScriptTargetOutput getScriptTargetOutput() {
return null;
}
}
}