|  | 
| 5 | 5 | import org.utplsql.api.compatibility.CompatibilityProxy; | 
| 6 | 6 | import org.utplsql.api.db.DatabaseInformation; | 
| 7 | 7 | import org.utplsql.api.db.DefaultDatabaseInformation; | 
|  | 8 | +import org.utplsql.api.exception.OracleCreateStatmenetStuckException; | 
| 8 | 9 | import org.utplsql.api.exception.SomeTestsFailedException; | 
| 9 | 10 | import org.utplsql.api.exception.UtPLSQLNotInstalledException; | 
| 10 | 11 | import org.utplsql.api.reporter.DocumentationReporter; | 
|  | 
| 16 | 17 | import java.sql.SQLException; | 
| 17 | 18 | import java.util.ArrayList; | 
| 18 | 19 | import java.util.List; | 
|  | 20 | +import java.util.concurrent.*; | 
| 19 | 21 | 
 | 
| 20 | 22 | /** | 
| 21 | 23 |  * Created by Vinicius Avellar on 12/04/2017. | 
| @@ -124,6 +126,26 @@ private void delayedAddReporters() { | 
| 124 | 126 |         } | 
| 125 | 127 |     } | 
| 126 | 128 | 
 | 
|  | 129 | +    private void handleException(Throwable e) throws SQLException { | 
|  | 130 | +        // Just pass exceptions already categorized | 
|  | 131 | +        if ( e instanceof UtPLSQLNotInstalledException ) throw (UtPLSQLNotInstalledException)e; | 
|  | 132 | +        else if ( e instanceof SomeTestsFailedException ) throw (SomeTestsFailedException)e; | 
|  | 133 | +        else if ( e instanceof OracleCreateStatmenetStuckException ) throw (OracleCreateStatmenetStuckException)e; | 
|  | 134 | +        // Categorize exceptions | 
|  | 135 | +        else if (e instanceof SQLException) { | 
|  | 136 | +            SQLException sqlException = (SQLException) e; | 
|  | 137 | +            if (sqlException.getErrorCode() == SomeTestsFailedException.ERROR_CODE) { | 
|  | 138 | +                throw new SomeTestsFailedException(sqlException.getMessage(), e); | 
|  | 139 | +            } else if (((SQLException) e).getErrorCode() == UtPLSQLNotInstalledException.ERROR_CODE) { | 
|  | 140 | +                throw new UtPLSQLNotInstalledException(sqlException); | 
|  | 141 | +            } else { | 
|  | 142 | +                throw sqlException; | 
|  | 143 | +            } | 
|  | 144 | +        } else { | 
|  | 145 | +            throw new SQLException("Unknown exception, wrapping: " + e.getMessage(), e); | 
|  | 146 | +        } | 
|  | 147 | +    } | 
|  | 148 | + | 
| 127 | 149 |     public void run(Connection conn) throws SQLException { | 
| 128 | 150 | 
 | 
| 129 | 151 |         logger.info("TestRunner initialized"); | 
| @@ -156,19 +178,42 @@ public void run(Connection conn) throws SQLException { | 
| 156 | 178 |             options.reporterList.add(new DocumentationReporter().init(conn)); | 
| 157 | 179 |         } | 
| 158 | 180 | 
 | 
| 159 |  | -        try (TestRunnerStatement testRunnerStatement = compatibilityProxy.getTestRunnerStatement(options, conn)) { | 
|  | 181 | +        TestRunnerStatement testRunnerStatement = null; | 
|  | 182 | +        try { | 
|  | 183 | +            testRunnerStatement = initStatementWithTimeout(conn); | 
| 160 | 184 |             logger.info("Running tests"); | 
| 161 | 185 |             testRunnerStatement.execute(); | 
| 162 | 186 |             logger.info("Running tests finished."); | 
|  | 187 | +            testRunnerStatement.close(); | 
|  | 188 | +        } catch (OracleCreateStatmenetStuckException e) { | 
|  | 189 | +            // Don't close statement in this case for it will be stuck, too | 
|  | 190 | +            throw e; | 
| 163 | 191 |         } catch (SQLException e) { | 
| 164 |  | -            if (e.getErrorCode() == SomeTestsFailedException.ERROR_CODE) { | 
| 165 |  | -                throw new SomeTestsFailedException(e.getMessage(), e); | 
| 166 |  | -            } else if (e.getErrorCode() == UtPLSQLNotInstalledException.ERROR_CODE) { | 
| 167 |  | -                throw new UtPLSQLNotInstalledException(e); | 
| 168 |  | -            } else { | 
| 169 |  | -                throw e; | 
| 170 |  | -            } | 
|  | 192 | +            if (testRunnerStatement != null) testRunnerStatement.close(); | 
|  | 193 | +            handleException(e); | 
|  | 194 | +        } | 
|  | 195 | +    } | 
|  | 196 | + | 
|  | 197 | +    private TestRunnerStatement initStatementWithTimeout( Connection conn ) throws OracleCreateStatmenetStuckException, SQLException { | 
|  | 198 | +        ExecutorService executor = Executors.newSingleThreadExecutor(); | 
|  | 199 | +        Callable<TestRunnerStatement> callable = () -> compatibilityProxy.getTestRunnerStatement(options, conn); | 
|  | 200 | +        Future<TestRunnerStatement> future = executor.submit(callable); | 
|  | 201 | + | 
|  | 202 | +        // We want to leave the statement open in case of stuck scenario | 
|  | 203 | +        TestRunnerStatement testRunnerStatement = null; | 
|  | 204 | +        try { | 
|  | 205 | +            testRunnerStatement = future.get(2, TimeUnit.SECONDS); | 
|  | 206 | +        } catch (TimeoutException e) { | 
|  | 207 | +            logger.error("Detected Oracle driver stuck during Statement initialization"); | 
|  | 208 | +            executor.shutdownNow(); | 
|  | 209 | +            throw new OracleCreateStatmenetStuckException(e); | 
|  | 210 | +        } catch (InterruptedException e) { | 
|  | 211 | +            handleException(e); | 
|  | 212 | +        } catch (ExecutionException e) { | 
|  | 213 | +            handleException(e.getCause()); | 
| 171 | 214 |         } | 
|  | 215 | + | 
|  | 216 | +        return testRunnerStatement; | 
| 172 | 217 |     } | 
| 173 | 218 | 
 | 
| 174 | 219 |     /** | 
|  | 
0 commit comments