Skip to content

#107 - Crash of Realtime Report when server output contains <![CDATA[...]]> #108

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jun 4, 2020
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
/*
* Copyright 2018 Philipp Salvisberg <[email protected]>
*
*
* 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.
Expand All @@ -28,7 +28,6 @@
import org.springframework.jdbc.core.CallableStatementCallback;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.SingleConnectionDataSource;
import org.utplsql.sqldev.exception.GenericRuntimeException;
import org.utplsql.sqldev.model.StringTools;
import org.utplsql.sqldev.model.XMLTools;
import org.utplsql.sqldev.model.runner.Counter;
Expand Down Expand Up @@ -211,8 +210,8 @@ public String getHtmlCoverage(final String reporterId) {
rs.close();
return sb1.toString();
});
}
}

private RealtimeReporterEvent convert(final String itemType, final String text) {
logger.fine(() -> "\n---- " + itemType + " ----\n" + text);
try {
Expand All @@ -234,13 +233,15 @@ private RealtimeReporterEvent convert(final String itemType, final String text)
}
return event;
} catch (SAXException e) {
// continue processing, see https://github.com/utPLSQL/utPLSQL-SQLDeveloper/issues/107
final String msg = "Parse error while processing " + itemType + " with content: " + text;
logger.severe(() -> msg);
throw new GenericRuntimeException(msg, e);
return null;
} catch (IOException e) {
// continue processing, see https://github.com/utPLSQL/utPLSQL-SQLDeveloper/issues/107
final String msg = "I/O error while processing " + itemType + " with content: " + text;
logger.severe(() -> msg);
throw new GenericRuntimeException(msg, e);
return null;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,10 @@ public static String getSysdate() {
return df.format(dateTime);
}

public boolean isRunning() {
return run != null && run.getEndTime() == null;
}

private void initRun() {
run = new Run(realtimeReporterId, connectionName, pathList);
run.setStartTime(getSysdate());
Expand Down
96 changes: 59 additions & 37 deletions sqldev/src/main/java/org/utplsql/sqldev/ui/runner/RunnerPanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,52 @@ private void runCodeCoverage(boolean selectedOnly) {
reporter.showParameterWindow();
}

private void fixCountersAndUpdate() {
// fix incompleteTests
List<Test> incompleteTests = currentRun.getTests().values().stream()
.filter(it -> it.getEndTime() == null && !it.isDisabled()).collect(Collectors.toList());
if (!incompleteTests.isEmpty()) {
final Double now = (double) System.currentTimeMillis();
final String sysdate = UtplsqlRunner.getSysdate();
for (Test test : incompleteTests) {
// fix incomplete tests, see https://github.com/utPLSQL/utPLSQL-SQLDeveloper/issues/107
test.setEndTime(sysdate);
test.setExecutionTime((now - currentRun.getStart()) / 1000);
test.setErrorStack(UtplsqlResources.getString("RUNNER_MISSING_TEST_RESULT_MESSAGE"));
test.getCounter().setError(1);
}
}
// recalculate counters and fix inconsistencies
currentRun.getCounter().setSuccess(0);
currentRun.getCounter().setFailure(0);
currentRun.getCounter().setError(0);
currentRun.getCounter().setDisabled(0);
currentRun.getCounter().setWarning(0);
for (Test test : currentRun.getTests().values()) {
if (test.isDisabled() && test.getCounter().getDisabled() == 0) {
test.getCounter().setDisabled(1);
}
if (test.getFailedExpectations() != null && !test.getFailedExpectations().isEmpty() && test.getCounter().getFailure() == 0) {
test.getCounter().setFailure(1);
}
if (test.getErrorStack() != null && test.getCounter().getError() == 0) {
test.getCounter().setError(1);
}
currentRun.getCounter().setSuccess(currentRun.getCounter().getSuccess() + test.getCounter().getSuccess());
currentRun.getCounter().setFailure(currentRun.getCounter().getFailure() + test.getCounter().getFailure());
currentRun.getCounter().setError(currentRun.getCounter().getError() + test.getCounter().getError());
currentRun.getCounter().setDisabled(currentRun.getCounter().getDisabled() + test.getCounter().getDisabled());
currentRun.getCounter().setWarning(currentRun.getCounter().getWarning() + test.getCounter().getWarning());
}
// terminate run
currentRun.setEndTime(UtplsqlRunner.getSysdate());
double now = (double) System.currentTimeMillis();
currentRun.setExecutionTime((now - currentRun.getStart()) / 1000);
currentRun.setCurrentTestNumber(0);
// update run in GUI
update(currentRun.getReporterId());
}

@SuppressWarnings("DuplicatedCode")
private void initializeGUI() {
// Base panel containing all components
Expand Down Expand Up @@ -767,45 +813,18 @@ private void initializeGUI() {
if (currentRun.getConsumerConn() != null) {
// Aborts JDBC Connection. Connection might still run in the background. That's expected.
DatabaseTools.abortConnection(currentRun.getConsumerConn());
for (Test test : currentRun.getTests().values()) {
if (test.getEndTime() == null && !test.isDisabled()) {
test.setDisabled(true);
test.getCounter().setDisabled(1);
test.getCounter().setWarning(1);
test.setWarnings(UtplsqlResources.getString("RUNNER_STOP_TEST_MESSAGE"));
test.setStartTime(null);
}
List<Test> notCompletedTests = currentRun.getTests().values().stream()
.filter(it -> it.getTestNumber() >= currentRun.getCurrentTestNumber() && it.getEndTime() == null && !it.isDisabled())
.collect(Collectors.toList());
for (Test test : notCompletedTests) {
test.setDisabled(true);
test.getCounter().setDisabled(1);
test.getCounter().setWarning(1);
test.setWarnings(UtplsqlResources.getString("RUNNER_STOP_TEST_MESSAGE"));
test.setStartTime(null);
}
// recalculate counters and fix inconsistencies
currentRun.getCounter().setSuccess(0);
currentRun.getCounter().setFailure(0);
currentRun.getCounter().setError(0);
currentRun.getCounter().setDisabled(0);
currentRun.getCounter().setWarning(0);
for (Test test : currentRun.getTests().values()) {
if (test.isDisabled() && test.getCounter().getDisabled() == 0) {
test.getCounter().setDisabled(1);
}
if (test.getFailedExpectations() != null && !test.getFailedExpectations().isEmpty() && test.getCounter().getFailure() == 0) {
test.getCounter().setFailure(1);
}
if (test.getErrorStack() != null && test.getCounter().getError() == 0) {
test.getCounter().setError(1);
}
currentRun.getCounter().setSuccess(currentRun.getCounter().getSuccess() + test.getCounter().getSuccess());
currentRun.getCounter().setFailure(currentRun.getCounter().getFailure() + test.getCounter().getFailure());
currentRun.getCounter().setError(currentRun.getCounter().getError() + test.getCounter().getError());
currentRun.getCounter().setDisabled(currentRun.getCounter().getDisabled() + test.getCounter().getDisabled());
currentRun.getCounter().setWarning(currentRun.getCounter().getWarning() + test.getCounter().getWarning());
}
// terminate run
currentRun.setEndTime(UtplsqlRunner.getSysdate());
double now = (double) System.currentTimeMillis();
currentRun.setExecutionTime((now - currentRun.getStart()) / 1000);
currentRun.setCurrentTestNumber(0);
currentRun.setStatus(UtplsqlResources.getString("RUNNER_STOP_RUN_MESSAGE"));
// update run in GUI
update(currentRun.getReporterId());
fixCountersAndUpdate();
}
});
stopButton.setEnabled(false);
Expand Down Expand Up @@ -871,6 +890,9 @@ private void initializeGUI() {
if (currentRun.getExecutionTime() != null) {
time.setSeconds(currentRun.getExecutionTime());
elapsedTimeTimer.stop();
if (!currentRun.getTotalNumberOfTests().equals(currentRun.getTotalNumberOfCompletedTests())) {
fixCountersAndUpdate();
}
} else {
final Double now = (double) System.currentTimeMillis();
time.setSeconds((now - currentRun.getStart()) / 1000);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ RUNNER_CODE_COVERAGE_TOOLTIP=Rerun all tests with code coverage
RUNNER_STOP_TOOLTIP=Stops the consumer session of the current test run immediately, the JDBC connection might be closed delayed
RUNNER_STOP_TEST_MESSAGE=Test disabled due to abortion of the test run.
RUNNER_STOP_RUN_MESSAGE=Test run aborted.
RUNNER_MISSING_TEST_RESULT_MESSAGE=Missing test results.
RUNNER_CLEAR_BUTTON=Clear run history
RUNNER_TESTS_LABEL=Tests
RUNNER_FAILURES_LABEL=Failures
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ RUNNER_CODE_COVERAGE_TOOLTIP=Alle Tests mit Codeabdeckung ausf\u00fchren
RUNNER_STOP_TOOLTIP=Stoppt die Verbrauchersitzung des aktuellen Testlaufs, die JDBC-Verbindung wird m\00f6glicherweise verz\00fgert geschlossen
RUNNER_STOP_TEST_MESSAGE=Test wurde aufgrund eines Abbruchs des Testlaufs deaktiviert.
RUNNER_STOP_RUN_MESSAGE=Testlauf abgebrochen.
RUNNER_MISSING_TEST_RESULT_MESSAGE=Testergebnis fehlt.
RUNNER_CLEAR_BUTTON=Run History l\u00f6schen
RUNNER_TESTS_LABEL=Tests
RUNNER_FAILURES_LABEL=Fehlschl\u00e4ge
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
package org.utplsql.sqldev.test.runner;

import java.sql.Connection;
import java.util.Arrays;
import java.util.Collections;

import org.junit.After;
import org.junit.Assert;
Expand Down Expand Up @@ -110,31 +110,45 @@ public void setup() {
sb.append("END;");
jdbcTemplate.execute(sb.toString());
new CodeCoverageReporterTest().setup();
sb.setLength(0);
sb.append("CREATE OR REPLACE PACKAGE junit_utplsql_test2_pkg is\n");
sb.append(" --%suite(JUnit testing)\n");
sb.append(" --%suitepath(b)\n\n");

sb.append(" --%test(test XML with nested CDATA)\n");
sb.append(" PROCEDURE test_nested_cdata;\n\n");
sb.append("END;");
jdbcTemplate.execute(sb.toString());
sb.setLength(0);
sb.append("CREATE OR REPLACE PACKAGE BODY junit_utplsql_test2_pkg IS\n");
sb.append(" PROCEDURE test_nested_cdata IS\n");
sb.append(" BEGIN\n");
sb.append(" dbms_output.put_line('nested cdata block: <![CDATA[...]]>, to be handled.');\n");
sb.append(" ut.expect(1).to_equal(1);\n");
sb.append(" END;\n");
sb.append("END;");
jdbcTemplate.execute(sb.toString());
}

@After
public void teardown() {
executeAndIgnore(jdbcTemplate, "DROP PACKAGE junit_utplsql_test1_pkg");
executeAndIgnore(jdbcTemplate, "DROP PACKAGE junit_utplsql_test2_pkg");
new CodeCoverageReporterTest().teardown();
}

private Connection getNewConnection() {
final SingleConnectionDataSource ds = new SingleConnectionDataSource();
ds.setDriverClassName("oracle.jdbc.OracleDriver");
ds.setUrl(dataSource.getUrl());
ds.setUsername(dataSource.getUsername());
ds.setPassword(dataSource.getPassword());
return DatabaseTools.getConnection(ds);
}

@Test
public void runTestsWithMaxTime() {
final SingleConnectionDataSource ds1 = new SingleConnectionDataSource();
ds1.setDriverClassName("oracle.jdbc.OracleDriver");
ds1.setUrl(dataSource.getUrl());
ds1.setUsername(dataSource.getUsername());
ds1.setPassword(dataSource.getPassword());
final Connection producerConn = DatabaseTools.getConnection(ds1);

final SingleConnectionDataSource ds2 = new SingleConnectionDataSource();
ds2.setDriverClassName("oracle.jdbc.OracleDriver");
ds2.setUrl(dataSource.getUrl());
ds2.setUsername(dataSource.getUsername());
ds2.setPassword(dataSource.getPassword());
final Connection consumerConn = DatabaseTools.getConnection(ds2);

UtplsqlRunner runner = new UtplsqlRunner(Arrays.asList(":a"), producerConn, consumerConn);
UtplsqlRunner runner = new UtplsqlRunner(Collections.singletonList(":a"), getNewConnection(), getNewConnection());
runner.runTestAsync();

SystemTools.waitForThread(runner.getProducerThread(), 200000);
Expand All @@ -146,27 +160,26 @@ public void runTestsWithMaxTime() {

@Test
public void runTestsWithCodeCoverage() {
final SingleConnectionDataSource ds1 = new SingleConnectionDataSource();
ds1.setDriverClassName("oracle.jdbc.OracleDriver");
ds1.setUrl(dataSource.getUrl());
ds1.setUsername(dataSource.getUsername());
ds1.setPassword(dataSource.getPassword());
final Connection producerConn = DatabaseTools.getConnection(ds1);

final SingleConnectionDataSource ds2 = new SingleConnectionDataSource();
ds2.setDriverClassName("oracle.jdbc.OracleDriver");
ds2.setUrl(dataSource.getUrl());
ds2.setUsername(dataSource.getUsername());
ds2.setPassword(dataSource.getPassword());
final Connection consumerConn = DatabaseTools.getConnection(ds2);

UtplsqlRunner runner = new UtplsqlRunner(Arrays.asList(":test_f"), null, null, null, producerConn, consumerConn);
UtplsqlRunner runner = new UtplsqlRunner(Collections.singletonList(":test_f"), null, null, null, getNewConnection(), getNewConnection());
runner.runTestAsync();

SystemTools.waitForThread(runner.getProducerThread(), 200000);
SystemTools.waitForThread(runner.getConsumerThread(), 200000);
SystemTools.sleep(4 * 1000);
Assert.assertNotNull(runner);
runner.dispose();
}

@Test
public void runTestWithNestedCdataSection() {
UtplsqlRunner runner = new UtplsqlRunner(Collections.singletonList(":b"), getNewConnection(), getNewConnection());
runner.runTestAsync();

SystemTools.waitForThread(runner.getProducerThread(), 200000);
SystemTools.waitForThread(runner.getConsumerThread(), 200000);
SystemTools.sleep(4 * 1000);
Assert.assertNotNull(runner);
Assert.assertFalse(runner.isRunning());
runner.dispose();
}
}
2 changes: 1 addition & 1 deletion sqldev/src/test/resources/logging.conf
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ handlers=java.util.logging.ConsoleHandler

# Loggers
#oracle.level=FINE
org.utplsql.level=ALL
org.utplsql.level=INFO

# --- ConsoleHandler ---
java.util.logging.ConsoleHandler.level=ALL
Expand Down