Skip to content

Commit 21d6f96

Browse files
Merge pull request #108 from utPLSQL/bugfix/issue-107-nested-cdata
#107 - Crash of Realtime Report when server output contains <![CDATA[...]]>
2 parents c2b746d + e90a80e commit 21d6f96

File tree

7 files changed

+119
-77
lines changed

7 files changed

+119
-77
lines changed

sqldev/src/main/java/org/utplsql/sqldev/dal/RealtimeReporterDao.java

+9-8
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
/*
22
* Copyright 2018 Philipp Salvisberg <philipp.salvisberg@trivadis.com>
3-
*
3+
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
66
* You may obtain a copy of the License at
7-
*
7+
*
88
* http://www.apache.org/licenses/LICENSE-2.0
9-
*
9+
*
1010
* Unless required by applicable law or agreed to in writing, software
1111
* distributed under the License is distributed on an "AS IS" BASIS,
1212
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -28,7 +28,6 @@
2828
import org.springframework.jdbc.core.CallableStatementCallback;
2929
import org.springframework.jdbc.core.JdbcTemplate;
3030
import org.springframework.jdbc.datasource.SingleConnectionDataSource;
31-
import org.utplsql.sqldev.exception.GenericRuntimeException;
3231
import org.utplsql.sqldev.model.StringTools;
3332
import org.utplsql.sqldev.model.XMLTools;
3433
import org.utplsql.sqldev.model.runner.Counter;
@@ -211,8 +210,8 @@ public String getHtmlCoverage(final String reporterId) {
211210
rs.close();
212211
return sb1.toString();
213212
});
214-
}
215-
213+
}
214+
216215
private RealtimeReporterEvent convert(final String itemType, final String text) {
217216
logger.fine(() -> "\n---- " + itemType + " ----\n" + text);
218217
try {
@@ -234,13 +233,15 @@ private RealtimeReporterEvent convert(final String itemType, final String text)
234233
}
235234
return event;
236235
} catch (SAXException e) {
236+
// continue processing, see https://github.com/utPLSQL/utPLSQL-SQLDeveloper/issues/107
237237
final String msg = "Parse error while processing " + itemType + " with content: " + text;
238238
logger.severe(() -> msg);
239-
throw new GenericRuntimeException(msg, e);
239+
return null;
240240
} catch (IOException e) {
241+
// continue processing, see https://github.com/utPLSQL/utPLSQL-SQLDeveloper/issues/107
241242
final String msg = "I/O error while processing " + itemType + " with content: " + text;
242243
logger.severe(() -> msg);
243-
throw new GenericRuntimeException(msg, e);
244+
return null;
244245
}
245246
}
246247

sqldev/src/main/java/org/utplsql/sqldev/runner/UtplsqlRunner.java

+4
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,10 @@ public static String getSysdate() {
173173
return df.format(dateTime);
174174
}
175175

176+
public boolean isRunning() {
177+
return run != null && run.getEndTime() == null;
178+
}
179+
176180
private void initRun() {
177181
run = new Run(realtimeReporterId, connectionName, pathList);
178182
run.setStartTime(getSysdate());

sqldev/src/main/java/org/utplsql/sqldev/ui/runner/RunnerPanel.java

+59-37
Original file line numberDiff line numberDiff line change
@@ -709,6 +709,52 @@ private void runCodeCoverage(boolean selectedOnly) {
709709
reporter.showParameterWindow();
710710
}
711711

712+
private void fixCountersAndUpdate() {
713+
// fix incompleteTests
714+
List<Test> incompleteTests = currentRun.getTests().values().stream()
715+
.filter(it -> it.getEndTime() == null && !it.isDisabled()).collect(Collectors.toList());
716+
if (!incompleteTests.isEmpty()) {
717+
final Double now = (double) System.currentTimeMillis();
718+
final String sysdate = UtplsqlRunner.getSysdate();
719+
for (Test test : incompleteTests) {
720+
// fix incomplete tests, see https://github.com/utPLSQL/utPLSQL-SQLDeveloper/issues/107
721+
test.setEndTime(sysdate);
722+
test.setExecutionTime((now - currentRun.getStart()) / 1000);
723+
test.setErrorStack(UtplsqlResources.getString("RUNNER_MISSING_TEST_RESULT_MESSAGE"));
724+
test.getCounter().setError(1);
725+
}
726+
}
727+
// recalculate counters and fix inconsistencies
728+
currentRun.getCounter().setSuccess(0);
729+
currentRun.getCounter().setFailure(0);
730+
currentRun.getCounter().setError(0);
731+
currentRun.getCounter().setDisabled(0);
732+
currentRun.getCounter().setWarning(0);
733+
for (Test test : currentRun.getTests().values()) {
734+
if (test.isDisabled() && test.getCounter().getDisabled() == 0) {
735+
test.getCounter().setDisabled(1);
736+
}
737+
if (test.getFailedExpectations() != null && !test.getFailedExpectations().isEmpty() && test.getCounter().getFailure() == 0) {
738+
test.getCounter().setFailure(1);
739+
}
740+
if (test.getErrorStack() != null && test.getCounter().getError() == 0) {
741+
test.getCounter().setError(1);
742+
}
743+
currentRun.getCounter().setSuccess(currentRun.getCounter().getSuccess() + test.getCounter().getSuccess());
744+
currentRun.getCounter().setFailure(currentRun.getCounter().getFailure() + test.getCounter().getFailure());
745+
currentRun.getCounter().setError(currentRun.getCounter().getError() + test.getCounter().getError());
746+
currentRun.getCounter().setDisabled(currentRun.getCounter().getDisabled() + test.getCounter().getDisabled());
747+
currentRun.getCounter().setWarning(currentRun.getCounter().getWarning() + test.getCounter().getWarning());
748+
}
749+
// terminate run
750+
currentRun.setEndTime(UtplsqlRunner.getSysdate());
751+
double now = (double) System.currentTimeMillis();
752+
currentRun.setExecutionTime((now - currentRun.getStart()) / 1000);
753+
currentRun.setCurrentTestNumber(0);
754+
// update run in GUI
755+
update(currentRun.getReporterId());
756+
}
757+
712758
@SuppressWarnings("DuplicatedCode")
713759
private void initializeGUI() {
714760
// Base panel containing all components
@@ -767,45 +813,18 @@ private void initializeGUI() {
767813
if (currentRun.getConsumerConn() != null) {
768814
// Aborts JDBC Connection. Connection might still run in the background. That's expected.
769815
DatabaseTools.abortConnection(currentRun.getConsumerConn());
770-
for (Test test : currentRun.getTests().values()) {
771-
if (test.getEndTime() == null && !test.isDisabled()) {
772-
test.setDisabled(true);
773-
test.getCounter().setDisabled(1);
774-
test.getCounter().setWarning(1);
775-
test.setWarnings(UtplsqlResources.getString("RUNNER_STOP_TEST_MESSAGE"));
776-
test.setStartTime(null);
777-
}
816+
List<Test> notCompletedTests = currentRun.getTests().values().stream()
817+
.filter(it -> it.getTestNumber() >= currentRun.getCurrentTestNumber() && it.getEndTime() == null && !it.isDisabled())
818+
.collect(Collectors.toList());
819+
for (Test test : notCompletedTests) {
820+
test.setDisabled(true);
821+
test.getCounter().setDisabled(1);
822+
test.getCounter().setWarning(1);
823+
test.setWarnings(UtplsqlResources.getString("RUNNER_STOP_TEST_MESSAGE"));
824+
test.setStartTime(null);
778825
}
779-
// recalculate counters and fix inconsistencies
780-
currentRun.getCounter().setSuccess(0);
781-
currentRun.getCounter().setFailure(0);
782-
currentRun.getCounter().setError(0);
783-
currentRun.getCounter().setDisabled(0);
784-
currentRun.getCounter().setWarning(0);
785-
for (Test test : currentRun.getTests().values()) {
786-
if (test.isDisabled() && test.getCounter().getDisabled() == 0) {
787-
test.getCounter().setDisabled(1);
788-
}
789-
if (test.getFailedExpectations() != null && !test.getFailedExpectations().isEmpty() && test.getCounter().getFailure() == 0) {
790-
test.getCounter().setFailure(1);
791-
}
792-
if (test.getErrorStack() != null && test.getCounter().getError() == 0) {
793-
test.getCounter().setError(1);
794-
}
795-
currentRun.getCounter().setSuccess(currentRun.getCounter().getSuccess() + test.getCounter().getSuccess());
796-
currentRun.getCounter().setFailure(currentRun.getCounter().getFailure() + test.getCounter().getFailure());
797-
currentRun.getCounter().setError(currentRun.getCounter().getError() + test.getCounter().getError());
798-
currentRun.getCounter().setDisabled(currentRun.getCounter().getDisabled() + test.getCounter().getDisabled());
799-
currentRun.getCounter().setWarning(currentRun.getCounter().getWarning() + test.getCounter().getWarning());
800-
}
801-
// terminate run
802-
currentRun.setEndTime(UtplsqlRunner.getSysdate());
803-
double now = (double) System.currentTimeMillis();
804-
currentRun.setExecutionTime((now - currentRun.getStart()) / 1000);
805-
currentRun.setCurrentTestNumber(0);
806826
currentRun.setStatus(UtplsqlResources.getString("RUNNER_STOP_RUN_MESSAGE"));
807-
// update run in GUI
808-
update(currentRun.getReporterId());
827+
fixCountersAndUpdate();
809828
}
810829
});
811830
stopButton.setEnabled(false);
@@ -871,6 +890,9 @@ private void initializeGUI() {
871890
if (currentRun.getExecutionTime() != null) {
872891
time.setSeconds(currentRun.getExecutionTime());
873892
elapsedTimeTimer.stop();
893+
if (!currentRun.getTotalNumberOfTests().equals(currentRun.getTotalNumberOfCompletedTests())) {
894+
fixCountersAndUpdate();
895+
}
874896
} else {
875897
final Double now = (double) System.currentTimeMillis();
876898
time.setSeconds((now - currentRun.getStart()) / 1000);

sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources.properties

+1
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ RUNNER_CODE_COVERAGE_TOOLTIP=Rerun all tests with code coverage
9090
RUNNER_STOP_TOOLTIP=Stops the consumer session of the current test run immediately, the JDBC connection might be closed delayed
9191
RUNNER_STOP_TEST_MESSAGE=Test disabled due to abortion of the test run.
9292
RUNNER_STOP_RUN_MESSAGE=Test run aborted.
93+
RUNNER_MISSING_TEST_RESULT_MESSAGE=Missing test results.
9394
RUNNER_CLEAR_BUTTON=Clear run history
9495
RUNNER_TESTS_LABEL=Tests
9596
RUNNER_FAILURES_LABEL=Failures

sqldev/src/main/resources/org/utplsql/sqldev/resources/UtplsqlResources_de.properties

+1
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ RUNNER_CODE_COVERAGE_TOOLTIP=Alle Tests mit Codeabdeckung ausf\u00fchren
6363
RUNNER_STOP_TOOLTIP=Stoppt die Verbrauchersitzung des aktuellen Testlaufs, die JDBC-Verbindung wird m\00f6glicherweise verz\00fgert geschlossen
6464
RUNNER_STOP_TEST_MESSAGE=Test wurde aufgrund eines Abbruchs des Testlaufs deaktiviert.
6565
RUNNER_STOP_RUN_MESSAGE=Testlauf abgebrochen.
66+
RUNNER_MISSING_TEST_RESULT_MESSAGE=Testergebnis fehlt.
6667
RUNNER_CLEAR_BUTTON=Run History l\u00f6schen
6768
RUNNER_TESTS_LABEL=Tests
6869
RUNNER_FAILURES_LABEL=Fehlschl\u00e4ge

sqldev/src/test/java/org/utplsql/sqldev/test/runner/UtplsqlRunnerTest.java

+44-31
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
package org.utplsql.sqldev.test.runner;
1717

1818
import java.sql.Connection;
19-
import java.util.Arrays;
19+
import java.util.Collections;
2020

2121
import org.junit.After;
2222
import org.junit.Assert;
@@ -110,31 +110,45 @@ public void setup() {
110110
sb.append("END;");
111111
jdbcTemplate.execute(sb.toString());
112112
new CodeCoverageReporterTest().setup();
113+
sb.setLength(0);
114+
sb.append("CREATE OR REPLACE PACKAGE junit_utplsql_test2_pkg is\n");
115+
sb.append(" --%suite(JUnit testing)\n");
116+
sb.append(" --%suitepath(b)\n\n");
117+
118+
sb.append(" --%test(test XML with nested CDATA)\n");
119+
sb.append(" PROCEDURE test_nested_cdata;\n\n");
120+
sb.append("END;");
121+
jdbcTemplate.execute(sb.toString());
122+
sb.setLength(0);
123+
sb.append("CREATE OR REPLACE PACKAGE BODY junit_utplsql_test2_pkg IS\n");
124+
sb.append(" PROCEDURE test_nested_cdata IS\n");
125+
sb.append(" BEGIN\n");
126+
sb.append(" dbms_output.put_line('nested cdata block: <![CDATA[...]]>, to be handled.');\n");
127+
sb.append(" ut.expect(1).to_equal(1);\n");
128+
sb.append(" END;\n");
129+
sb.append("END;");
130+
jdbcTemplate.execute(sb.toString());
113131
}
114132

115133
@After
116134
public void teardown() {
117135
executeAndIgnore(jdbcTemplate, "DROP PACKAGE junit_utplsql_test1_pkg");
136+
executeAndIgnore(jdbcTemplate, "DROP PACKAGE junit_utplsql_test2_pkg");
118137
new CodeCoverageReporterTest().teardown();
119138
}
120139

140+
private Connection getNewConnection() {
141+
final SingleConnectionDataSource ds = new SingleConnectionDataSource();
142+
ds.setDriverClassName("oracle.jdbc.OracleDriver");
143+
ds.setUrl(dataSource.getUrl());
144+
ds.setUsername(dataSource.getUsername());
145+
ds.setPassword(dataSource.getPassword());
146+
return DatabaseTools.getConnection(ds);
147+
}
148+
121149
@Test
122150
public void runTestsWithMaxTime() {
123-
final SingleConnectionDataSource ds1 = new SingleConnectionDataSource();
124-
ds1.setDriverClassName("oracle.jdbc.OracleDriver");
125-
ds1.setUrl(dataSource.getUrl());
126-
ds1.setUsername(dataSource.getUsername());
127-
ds1.setPassword(dataSource.getPassword());
128-
final Connection producerConn = DatabaseTools.getConnection(ds1);
129-
130-
final SingleConnectionDataSource ds2 = new SingleConnectionDataSource();
131-
ds2.setDriverClassName("oracle.jdbc.OracleDriver");
132-
ds2.setUrl(dataSource.getUrl());
133-
ds2.setUsername(dataSource.getUsername());
134-
ds2.setPassword(dataSource.getPassword());
135-
final Connection consumerConn = DatabaseTools.getConnection(ds2);
136-
137-
UtplsqlRunner runner = new UtplsqlRunner(Arrays.asList(":a"), producerConn, consumerConn);
151+
UtplsqlRunner runner = new UtplsqlRunner(Collections.singletonList(":a"), getNewConnection(), getNewConnection());
138152
runner.runTestAsync();
139153

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

147161
@Test
148162
public void runTestsWithCodeCoverage() {
149-
final SingleConnectionDataSource ds1 = new SingleConnectionDataSource();
150-
ds1.setDriverClassName("oracle.jdbc.OracleDriver");
151-
ds1.setUrl(dataSource.getUrl());
152-
ds1.setUsername(dataSource.getUsername());
153-
ds1.setPassword(dataSource.getPassword());
154-
final Connection producerConn = DatabaseTools.getConnection(ds1);
155-
156-
final SingleConnectionDataSource ds2 = new SingleConnectionDataSource();
157-
ds2.setDriverClassName("oracle.jdbc.OracleDriver");
158-
ds2.setUrl(dataSource.getUrl());
159-
ds2.setUsername(dataSource.getUsername());
160-
ds2.setPassword(dataSource.getPassword());
161-
final Connection consumerConn = DatabaseTools.getConnection(ds2);
162-
163-
UtplsqlRunner runner = new UtplsqlRunner(Arrays.asList(":test_f"), null, null, null, producerConn, consumerConn);
163+
UtplsqlRunner runner = new UtplsqlRunner(Collections.singletonList(":test_f"), null, null, null, getNewConnection(), getNewConnection());
164+
runner.runTestAsync();
165+
166+
SystemTools.waitForThread(runner.getProducerThread(), 200000);
167+
SystemTools.waitForThread(runner.getConsumerThread(), 200000);
168+
SystemTools.sleep(4 * 1000);
169+
Assert.assertNotNull(runner);
170+
runner.dispose();
171+
}
172+
173+
@Test
174+
public void runTestWithNestedCdataSection() {
175+
UtplsqlRunner runner = new UtplsqlRunner(Collections.singletonList(":b"), getNewConnection(), getNewConnection());
164176
runner.runTestAsync();
165177

166178
SystemTools.waitForThread(runner.getProducerThread(), 200000);
167179
SystemTools.waitForThread(runner.getConsumerThread(), 200000);
168180
SystemTools.sleep(4 * 1000);
169181
Assert.assertNotNull(runner);
182+
Assert.assertFalse(runner.isRunning());
170183
runner.dispose();
171184
}
172185
}

sqldev/src/test/resources/logging.conf

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ handlers=java.util.logging.ConsoleHandler
1212

1313
# Loggers
1414
#oracle.level=FINE
15-
org.utplsql.level=ALL
15+
org.utplsql.level=INFO
1616

1717
# --- ConsoleHandler ---
1818
java.util.logging.ConsoleHandler.level=ALL

0 commit comments

Comments
 (0)