/*
* Copyright (c) 2005-2011 Grameen Foundation USA
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
* See also http://www.apache.org/licenses/LICENSE-2.0.html for an
* explanation of the license and how it is applied.
*/
package org.mifos.test.framework.util;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringReader;
import java.sql.Connection;
import java.sql.SQLException;
import org.dbunit.Assertion;
import org.dbunit.DataSourceDatabaseTester;
import org.dbunit.DatabaseUnitException;
import org.dbunit.IDatabaseTester;
import org.dbunit.database.DatabaseConfig;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.DataSetException;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.ITable;
import org.dbunit.dataset.ReplacementDataSet;
import org.dbunit.dataset.xml.FlatXmlDataSet;
import org.dbunit.operation.DatabaseOperation;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
public class DatabaseTestUtils {
// This method takes a variable number of String arguments - the names of the tables to clear.
// Note: to avoid database constraint violations, list tables in reverse order you want them to be cleared.
@SuppressWarnings("PMD.InsufficientStringBufferDeclaration") // test method doesn't need performance optimization yet
public void deleteDataFromTables(DriverManagerDataSource dataSource, String...tableNames)
throws IOException, DataSetException, SQLException, DatabaseUnitException {
StringBuffer dataSet = new StringBuffer();
dataSet.append("<dataset>");
for (String tableName:tableNames) {
dataSet.append("<" + tableName + "/>");
}
dataSet.append("</dataset>");
cleanAndInsertDataSet(dataSet.toString(), dataSource);
}
/**
* Execute a DbUnit CLEAN_INSERT. Parameter xmlString must be formatted as a DBUnit
* xml dataset. This method can be safely invoked inside a Spring-managed transaction.
* @param xmlString
* @param dataSource
* @throws IOException
* @throws DataSetException
* @throws SQLException
* @throws DatabaseUnitException
*/
@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
//Rationale: You cannot define new local variables in the try block because the finally block must reference it.
public void cleanAndInsertDataSet(String xmlString, DriverManagerDataSource dataSource)
throws IOException, DataSetException, SQLException, DatabaseUnitException {
StringReader dataSetXmlStream = new StringReader(xmlString);
IDataSet dataSet = new FlatXmlDataSet(dataSetXmlStream);
cleanAndInsertDataSet(dataSource, dataSet);
}
@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
//Rationale: You cannot define new local variables in the try block because the finally block must reference it.
public void cleanAndInsertDataSetWithColumnSensing(String xmlString, DriverManagerDataSource dataSource)
throws IOException, DataSetException, SQLException, DatabaseUnitException {
IDataSet dataSet = getXmlDataSet(xmlString);
cleanAndInsertDataSet(dataSource, dataSet);
}
private void cleanAndInsertDataSet(DriverManagerDataSource dataSource,
IDataSet dataSet) throws DatabaseUnitException, SQLException {
Connection jdbcConnection = null;
ReplacementDataSet replacementDataSet = getDataSetWithNullsReplaced(dataSet);
try {
jdbcConnection = DataSourceUtils.getConnection(dataSource);
IDatabaseConnection databaseConnection = new DatabaseConnection(jdbcConnection);
databaseConnection.getConfig().setProperty(DatabaseConfig.FEATURE_CASE_SENSITIVE_TABLE_NAMES, Boolean.TRUE);
DatabaseOperation.CLEAN_INSERT.execute(databaseConnection, replacementDataSet);
}
finally {
if (null != jdbcConnection) {
jdbcConnection.close();
}
DataSourceUtils.releaseConnection(jdbcConnection, dataSource);
}
}
/**
* given an XML string, returns an data set with [null] replaced by actual null objects.
* @param xmlString
* @return IDataSet
* @throws IOException
* @throws DataSetException
*/
public IDataSet getXmlDataSet(String xmlString) throws IOException, DataSetException {
boolean dtdMetadata = false;
boolean enableColumnSensing = true;
IDataSet xmlDataSet = new FlatXmlDataSet(createTempFile(xmlString), dtdMetadata, enableColumnSensing);
return this.getDataSetWithNullsReplaced(xmlDataSet);
}
/**
* Given a data set, return a data set with [null] replaced by actual null objects
* @param dataSet
* @return replacementDataSet
*/
public ReplacementDataSet getDataSetWithNullsReplaced(IDataSet dataSet) {
ReplacementDataSet replacementDataSet = new ReplacementDataSet(dataSet);
replacementDataSet.addReplacementObject("[null]", null);
return replacementDataSet;
}
private File createTempFile(String xmlString) throws IOException {
File tempFile = File.createTempFile("simpleDataSetTemp", ".xml");
tempFile.deleteOnExit();
BufferedWriter out = new BufferedWriter(new FileWriter(tempFile));
try {
out.write(xmlString);
} finally {
out.close();
}
return tempFile;
}
/**
* Verify that a database table matches a dataSet table. dataSetXml must be formatted as a DBUnit
* xml dataset. This method can be safely invoked inside a Spring-managed transaction.
* @param dataSetXml
* @param tableName
* @param dataSource
* @throws Exception
*/
@SuppressWarnings("PMD.SignatureDeclareThrowsException") // one of the dependent methods throws Exception
public void verifyTable(String dataSetXml, String tableName, DriverManagerDataSource dataSource) throws Exception {
Connection jdbcConnection = null;
StringReader dataSetXmlStream = new StringReader(dataSetXml);
try {
jdbcConnection = DataSourceUtils.getConnection(dataSource);
IDatabaseTester databaseTester = new DataSourceDatabaseTester(dataSource);
IDatabaseConnection databaseConnection = databaseTester.getConnection();
databaseConnection.getConfig().setProperty(DatabaseConfig.FEATURE_CASE_SENSITIVE_TABLE_NAMES, Boolean.TRUE);
IDataSet databaseDataSet = databaseConnection.createDataSet();
ITable actualTable = databaseDataSet.getTable(tableName);
IDataSet expectedDataSet = new FlatXmlDataSet(dataSetXmlStream);
ITable expectedTable = expectedDataSet.getTable(tableName);
Assertion.assertEqualsIgnoreCols(expectedTable, actualTable, new String[] { "id" });
}
finally {
if (null != jdbcConnection) {
jdbcConnection.close();
}
DataSourceUtils.releaseConnection(jdbcConnection, dataSource);
}
}
/**
* Return the current contents of the specified tables as a DBUnit dataset as XML string.
* This method can be invoked safely inside a Spring-managed transaction.
*
* @param dataSource
* @param tableNames variable parameter list of table names
* @return XML string containing the current contents of the specified tables
* @throws IOException
* @throws DataSetException
* @throws SQLException
* @throws DatabaseUnitException
*/
@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
//Rationale: You cannot define new local variables in the try block because the finally block must reference it.
public String saveTables(DriverManagerDataSource dataSource, String...tableNames)
throws IOException, DataSetException, SQLException, DatabaseUnitException {
Connection jdbcConnection = null;
try {
jdbcConnection = DataSourceUtils.getConnection(dataSource);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
FlatXmlDataSet.write(new DatabaseConnection(jdbcConnection).createDataSet(tableNames),
stream);
return stream.toString();
}
finally {
if (null != jdbcConnection) {
jdbcConnection.close();
}
DataSourceUtils.releaseConnection(jdbcConnection, dataSource);
}
}
}