Coverage Report - org.kuali.rice.test.ClearDatabaseLifecycle
 
Classes in this File Line Coverage Branch Coverage Complexity
ClearDatabaseLifecycle
0%
0/73
0%
0/32
3.059
ClearDatabaseLifecycle$1
0%
0/4
N/A
3.059
ClearDatabaseLifecycle$2
0%
0/3
N/A
3.059
ClearDatabaseLifecycle$2$1
0%
0/43
0%
0/24
3.059
 
 1  
 /**
 2  
  * Copyright 2005-2011 The Kuali Foundation
 3  
  *
 4  
  * Licensed under the Educational Community License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  * http://www.opensource.org/licenses/ecl2.php
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package org.kuali.rice.test;
 17  
 
 18  
 import org.apache.commons.lang.StringUtils;
 19  
 import org.apache.commons.lang.time.DurationFormatUtils;
 20  
 import org.apache.commons.lang.time.StopWatch;
 21  
 import org.apache.log4j.Logger;
 22  
 import org.junit.Assert;
 23  
 import org.kuali.rice.core.api.config.property.ConfigContext;
 24  
 import org.kuali.rice.core.api.lifecycle.BaseLifecycle;
 25  
 import org.springframework.dao.DataAccessException;
 26  
 import org.springframework.jdbc.core.ConnectionCallback;
 27  
 import org.springframework.jdbc.core.JdbcTemplate;
 28  
 import org.springframework.jdbc.core.StatementCallback;
 29  
 import org.springframework.transaction.PlatformTransactionManager;
 30  
 import org.springframework.transaction.TransactionStatus;
 31  
 import org.springframework.transaction.support.TransactionCallback;
 32  
 import org.springframework.transaction.support.TransactionTemplate;
 33  
 
 34  
 import javax.sql.DataSource;
 35  
 import java.sql.Connection;
 36  
 import java.sql.DatabaseMetaData;
 37  
 import java.sql.ResultSet;
 38  
 import java.sql.SQLException;
 39  
 import java.sql.Statement;
 40  
 import java.util.ArrayList;
 41  
 import java.util.HashMap;
 42  
 import java.util.List;
 43  
 import java.util.Map;
 44  
 
 45  
 /**
 46  
  * Lifecycle class to clean up the database for use in testing.
 47  
  * This lifecycle will not be run (even if it is listed in the lifecycles list)
 48  
  * if the 'use.use.clearDatabaseLifecycle' configuration property is defined, and is
 49  
  * not 'true'.  If the property is omitted the lifecycle runs as normal.
 50  
  * 
 51  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 52  
  * @since 0.9
 53  
  *
 54  
  */
 55  0
 public class ClearDatabaseLifecycle extends BaseLifecycle {
 56  
 
 57  0
     protected static final Logger LOG = Logger.getLogger(ClearDatabaseLifecycle.class);
 58  
 
 59  0
     private List<String> tablesToClear = new ArrayList<String>();
 60  0
     private List<String> tablesNotToClear = new ArrayList<String>();
 61  
 
 62  0
     public ClearDatabaseLifecycle() {
 63  0
         addStandardTables();
 64  0
     }
 65  
 
 66  0
     public ClearDatabaseLifecycle(List<String> tablesToClear, List<String> tablesNotToClear) {
 67  0
         this.tablesToClear = tablesToClear;
 68  0
         this.tablesNotToClear = tablesNotToClear;
 69  0
         addStandardTables();
 70  0
     }
 71  
 
 72  
     protected void addStandardTables() {
 73  0
         tablesNotToClear.add("BIN.*");
 74  0
         tablesNotToClear.add(".*_S");
 75  0
     }
 76  
 
 77  
     public static final String TEST_TABLE_NAME = "EN_UNITTEST_T";
 78  
 
 79  
     public void start() throws Exception {
 80  0
         String useClearDatabaseLifecycle = ConfigContext.getCurrentContextConfig().getProperty("use.clearDatabaseLifecycle");
 81  
 
 82  0
         if (useClearDatabaseLifecycle != null && !Boolean.valueOf(useClearDatabaseLifecycle)) {
 83  0
             LOG.debug("Skipping ClearDatabaseLifecycle due to property: use.clearDatabaseLifecycle=" + useClearDatabaseLifecycle);
 84  0
             return;
 85  
         }
 86  
 
 87  0
         final DataSource dataSource = TestHarnessServiceLocator.getDataSource();
 88  0
         clearTables(TestHarnessServiceLocator.getJtaTransactionManager(), dataSource);
 89  0
         super.start();
 90  0
     }
 91  
 
 92  
     protected Boolean isTestTableInSchema(final Connection connection) throws SQLException {
 93  0
         Assert.assertNotNull("Connection could not be located.", connection);
 94  0
         ResultSet resultSet = null;
 95  
         try {
 96  0
             resultSet = connection.getMetaData().getTables(null, connection.getMetaData().getUserName().toUpperCase(), TEST_TABLE_NAME, null);
 97  0
             return new Boolean(resultSet.next());
 98  
         } finally {
 99  0
             if (resultSet != null) {
 100  0
                 resultSet.close();
 101  
             }
 102  
         }
 103  
     }
 104  
 
 105  
     protected void verifyTestEnvironment(final DataSource dataSource) {
 106  0
         new JdbcTemplate(dataSource).execute(new ConnectionCallback<Object>() {
 107  
             public Object doInConnection(final Connection connection) throws SQLException {
 108  0
                 String dbUrl = connection.getMetaData().getURL();
 109  0
                 Assert.assertTrue("No table named '" + TEST_TABLE_NAME + "' was found in the configured database.  " +
 110  
                         dbUrl + "  You are attempting to run tests against a non-test database!!!", isTestTableInSchema(connection));
 111  0
                 return null;
 112  
             }
 113  
         });
 114  0
     }
 115  
 
 116  
     protected void clearTables(final PlatformTransactionManager transactionManager, final DataSource dataSource) {
 117  0
         Assert.assertNotNull("DataSource could not be located.", dataSource);
 118  
         try {
 119  0
             StopWatch s = new StopWatch();
 120  0
             s.start();
 121  0
             new TransactionTemplate(transactionManager).execute(new TransactionCallback() {
 122  
                 public Object doInTransaction(final TransactionStatus status) {
 123  0
                     verifyTestEnvironment(dataSource);
 124  0
                     return new JdbcTemplate(dataSource).execute(new StatementCallback() {
 125  
                         public Object doInStatement(Statement statement) throws SQLException {
 126  0
                             String schemaName = statement.getConnection().getMetaData().getUserName().toUpperCase();
 127  0
                             LOG.info("Clearing tables for schema " + schemaName);
 128  0
                             if (StringUtils.isBlank(schemaName)) {
 129  0
                                 Assert.fail("Empty schema name given");
 130  
                             }
 131  0
                             final List<String> reEnableConstraints = new ArrayList<String>();
 132  0
                             DatabaseMetaData metaData = statement.getConnection().getMetaData();
 133  0
                             Map<String, List<String[]>> exportedKeys = indexExportedKeys(metaData, schemaName);
 134  0
                             final ResultSet resultSet = metaData.getTables(null, schemaName, null, new String[] { "TABLE" });
 135  0
                             final StringBuilder logStatements = new StringBuilder();
 136  0
                             while (resultSet.next()) {
 137  0
                                 String tableName = resultSet.getString("TABLE_NAME");
 138  0
                                 if (shouldTableBeCleared(tableName)) {
 139  0
                                     if (!isUsingDerby(metaData) && isUsingOracle(metaData)) {
 140  0
                                             List<String[]> exportedKeyNames = exportedKeys.get(tableName);
 141  0
                                             if (exportedKeyNames != null) {
 142  0
                                                     for (String[] exportedKeyName : exportedKeyNames) {
 143  0
                                                             final String fkName = exportedKeyName[0];
 144  0
                                                             final String fkTableName = exportedKeyName[1];
 145  0
                                                             final String disableConstraint = "ALTER TABLE " + fkTableName + " DISABLE CONSTRAINT " + fkName;
 146  0
                                                             logStatements.append("Disabling constraints using statement ->" + disableConstraint + "<-\n");
 147  0
                                                             statement.addBatch(disableConstraint);
 148  0
                                                             reEnableConstraints.add("ALTER TABLE " + fkTableName + " ENABLE CONSTRAINT " + fkName);
 149  0
                                                     }
 150  
                                             }
 151  0
                                     } else if (isUsingMySQL(metaData)) {
 152  0
                                             statement.addBatch("SET FOREIGN_KEY_CHECKS = 0");
 153  
                                     }
 154  0
                                     String deleteStatement = "DELETE FROM " + tableName;
 155  0
                                     logStatements.append("Clearing contents using statement ->" + deleteStatement + "<-\n");
 156  0
                                     statement.addBatch(deleteStatement);
 157  
                                 }
 158  0
                             }
 159  0
                             for (final String constraint : reEnableConstraints) {
 160  0
                                 logStatements.append("Enabling constraints using statement ->" + constraint + "<-\n");
 161  0
                                 statement.addBatch(constraint);
 162  
                             }
 163  0
                             if (isUsingMySQL(metaData)) {
 164  0
                                     statement.addBatch("SET FOREIGN_KEY_CHECKS = 1");
 165  
                             }
 166  0
                             LOG.info(logStatements);
 167  
                             
 168  0
                             int[] results = statement.executeBatch();
 169  0
                             for (int index = 0; index < results.length; index++) {
 170  0
                                     if (results[index] == Statement.EXECUTE_FAILED) {
 171  0
                                                     Assert.fail("Execution of database clear statement failed.");
 172  
                                     }
 173  
                                     
 174  
                             }
 175  0
                             resultSet.close();
 176  0
                             LOG.info("Tables successfully cleared for schema " + schemaName);
 177  0
                             return null;
 178  
                         }
 179  
                     });
 180  
                 }
 181  
             });
 182  0
             s.stop();
 183  0
             LOG.info("Time to clear tables: " + DurationFormatUtils.formatDurationHMS(s.getTime()));
 184  0
         } catch (Exception e) {
 185  0
             LOG.error(e);
 186  0
             throw new RuntimeException(e);
 187  0
         }
 188  0
     }
 189  
     
 190  
     protected Map<String, List<String[]>> indexExportedKeys(DatabaseMetaData metaData, String schemaName) throws SQLException {
 191  0
             Map<String, List<String[]>> exportedKeys = new HashMap<String, List<String[]>>();
 192  0
         if (!isUsingDerby(metaData) && isUsingOracle(metaData)) {
 193  0
                 ResultSet keyResultSet = metaData.getExportedKeys(null, schemaName, null);
 194  0
                 while (keyResultSet.next()) {
 195  0
                         String tableName = keyResultSet.getString("PKTABLE_NAME");
 196  0
                         if (shouldTableBeCleared(tableName)) {
 197  0
                                 List<String[]> exportedKeyNames = exportedKeys.get(tableName);
 198  0
                                 if (exportedKeyNames == null) {
 199  0
                                         exportedKeyNames = new ArrayList<String[]>();
 200  0
                                         exportedKeys.put(tableName, exportedKeyNames);
 201  
                                 }
 202  0
                                 final String fkName = keyResultSet.getString("FK_NAME");
 203  0
                                 final String fkTableName = keyResultSet.getString("FKTABLE_NAME");
 204  0
                                 exportedKeyNames.add(new String[] { fkName, fkTableName });
 205  
                         }
 206  0
                 }
 207  0
                 keyResultSet.close();
 208  
         }
 209  0
         return exportedKeys;        
 210  
     }
 211  
 
 212  
     private boolean shouldTableBeCleared(String tableName) {
 213  0
         if (getTablesNotToClear() != null && !getTablesNotToClear().isEmpty()) {
 214  0
             for (String tableNotToClear : getTablesNotToClear()) {
 215  0
                 if (tableName.toUpperCase().matches(tableNotToClear.toUpperCase())) {
 216  0
                     return false;
 217  
                 }
 218  
             }
 219  
         }
 220  0
         if (getTablesToClear() != null && !getTablesToClear().isEmpty()) {
 221  0
             for (String tableToClear : getTablesToClear()) {
 222  0
                 if (tableName.toUpperCase().matches(tableToClear.toUpperCase())) {
 223  0
                     return true;
 224  
                 }
 225  
             }
 226  0
             return false;
 227  
         }
 228  
         
 229  0
         return true;
 230  
     }
 231  
 
 232  
     private boolean isUsingDerby(DatabaseMetaData metaData) throws SQLException {
 233  0
         return metaData.getDriverName().toLowerCase().contains("derby");
 234  
     }
 235  
 
 236  
     private boolean isUsingOracle(DatabaseMetaData metaData) throws SQLException {
 237  0
         return metaData.getDriverName().toLowerCase().contains("oracle");
 238  
     }
 239  
 
 240  
     private boolean isUsingMySQL(DatabaseMetaData metaData) throws SQLException {
 241  0
         return metaData.getDriverName().toLowerCase().contains("mysql");
 242  
     }
 243  
 
 244  
     
 245  
     public List<String> getTablesToClear() {
 246  0
         return this.tablesToClear;
 247  
     }
 248  
 
 249  
     public List<String> getTablesNotToClear() {
 250  0
         return this.tablesNotToClear;
 251  
     }
 252  
 }