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