Skip to content

Commit 778551e

Browse files
added data access layer for realtime reporter including tests
1 parent c0c7a6b commit 778551e

File tree

3 files changed

+487
-0
lines changed

3 files changed

+487
-0
lines changed
Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
/*
2+
* Copyright 2018 Philipp Salvisberg <philipp.salvisberg@trivadis.com>
3+
*
4+
* Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
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.utplsql.sqldev.dal
17+
18+
import java.io.StringReader
19+
import java.sql.Connection
20+
import java.sql.ResultSet
21+
import java.sql.SQLException
22+
import java.util.List
23+
import java.util.logging.Logger
24+
import javax.xml.parsers.DocumentBuilderFactory
25+
import org.springframework.dao.DataAccessException
26+
import org.springframework.jdbc.core.JdbcTemplate
27+
import org.springframework.jdbc.core.ResultSetExtractor
28+
import org.springframework.jdbc.datasource.SingleConnectionDataSource
29+
import org.utplsql.sqldev.model.XMLTools
30+
import org.utplsql.sqldev.model.runner.Counter
31+
import org.utplsql.sqldev.model.runner.Expectation
32+
import org.utplsql.sqldev.model.runner.PostEvent
33+
import org.utplsql.sqldev.model.runner.PostRunEvent
34+
import org.utplsql.sqldev.model.runner.PostSuiteEvent
35+
import org.utplsql.sqldev.model.runner.PostTestEvent
36+
import org.utplsql.sqldev.model.runner.PreRunEvent
37+
import org.utplsql.sqldev.model.runner.PreSuiteEvent
38+
import org.utplsql.sqldev.model.runner.PreTestEvent
39+
import org.utplsql.sqldev.model.runner.RealtimeReporterEvent
40+
import org.utplsql.sqldev.model.runner.Suite
41+
import org.utplsql.sqldev.model.runner.Test
42+
import org.w3c.dom.Document
43+
import org.w3c.dom.Element
44+
import org.w3c.dom.Node
45+
import org.xml.sax.InputSource
46+
47+
class RealtimeReporterDao {
48+
static val Logger logger = Logger.getLogger(RealtimeReporterDao.name);
49+
static val FIRST_VERSION_WITH_REALTIME_REPORTER = 3001004
50+
val extension XMLTools xmlTools = new XMLTools
51+
var Connection conn
52+
var JdbcTemplate jdbcTemplate
53+
54+
new(Connection connection) {
55+
conn = connection
56+
jdbcTemplate = new JdbcTemplate(new SingleConnectionDataSource(conn, true))
57+
jdbcTemplate.fetchSize = 1
58+
if ((new UtplsqlDao(conn)).normalizedUtPlsqlVersionNumber < FIRST_VERSION_WITH_REALTIME_REPORTER) {
59+
throw new RuntimeException("RealtimeReporter requires utPLSQL v3.1.4 or higher to be installed.")
60+
}
61+
}
62+
63+
def produceReport(String reporterId, List<String> pathList) {
64+
var plsql = '''
65+
DECLARE
66+
l_reporter ut_realtime_reporter := ut_realtime_reporter();
67+
BEGIN
68+
l_reporter.set_reporter_id(?);
69+
l_reporter.output_buffer.init();
70+
sys.dbms_output.enable(NULL);
71+
ut_runner.run(
72+
a_paths => ut_varchar2_list(
73+
«FOR path : pathList SEPARATOR ","»
74+
'«path»'
75+
«ENDFOR»
76+
),
77+
a_reporters => ut_reporters(l_reporter)
78+
);
79+
sys.dbms_output.disable;
80+
END;
81+
'''
82+
jdbcTemplate.update(plsql, #[reporterId])
83+
}
84+
85+
def consumeReport(String reporterId, RealtimeReporterEventConsumer consumer) {
86+
var sql = '''
87+
SELECT t.item_type, t.text
88+
FROM table(ut_output_table_buffer(?).get_lines()) t
89+
'''
90+
jdbcTemplate.query(sql, new ResultSetExtractor<Void>() {
91+
override extractData(ResultSet rs) throws SQLException, DataAccessException {
92+
while(rs.next) {
93+
val itemType = rs.getString("item_type")
94+
val textClob = rs.getClob("text")
95+
val textString = textClob.getSubString(1, textClob.length as int)
96+
val event = convert(itemType, textString)
97+
if (event !== null) {
98+
consumer.process(event)
99+
}
100+
}
101+
return null
102+
}
103+
}, #[reporterId]);
104+
}
105+
106+
private def RealtimeReporterEvent convert(String itemType, String text) {
107+
logger.fine('''
108+
---- «itemType» ----
109+
«text»
110+
''')
111+
val docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
112+
val doc = docBuilder.parse(new InputSource(new StringReader(text)))
113+
var RealtimeReporterEvent event
114+
if (itemType == "pre-run") {
115+
event = doc.convertToPreRunEvent
116+
} else if (itemType == "post-run") {
117+
event = doc.convertToPostRunEvent
118+
} else if (itemType == "pre-suite") {
119+
event = doc.convertToPreSuiteEvent
120+
} else if (itemType == "post-suite") {
121+
event = doc.convertToPostSuiteEvent
122+
} else if (itemType == "pre-test") {
123+
event = doc.convertToPreTestEvent
124+
} else if (itemType == "post-test") {
125+
event = doc.convertToPostTestEvent
126+
}
127+
return event
128+
}
129+
130+
private def RealtimeReporterEvent convertToPreRunEvent(Document doc) {
131+
val event = new PreRunEvent
132+
event.totalNumberOfTests = Integer.valueOf(doc.getNode("/event/totalNumberOfTests")?.textContent)
133+
val nodeList = doc.getNodeList("/event/items/*")
134+
for (i : 0 ..< nodeList.length) {
135+
val node = nodeList.item(i)
136+
if (node.nodeName == "suite") {
137+
val suite = new Suite
138+
event.items.add(suite)
139+
suite.populate(node)
140+
} else if (node.nodeName == "test") {
141+
val test = new Test
142+
event.items.add(test)
143+
test.populate(node)
144+
}
145+
}
146+
return event
147+
}
148+
149+
private def RealtimeReporterEvent convertToPostRunEvent(Document doc) {
150+
val event = new PostRunEvent
151+
event.populate(doc.getNode("/event/run"))
152+
return event
153+
}
154+
155+
private def RealtimeReporterEvent convertToPreSuiteEvent(Document doc) {
156+
val event = new PreSuiteEvent
157+
val node = doc.getNode("/event/suite")
158+
if (node instanceof Element) {
159+
event.id = node.attributes?.getNamedItem("id")?.nodeValue
160+
}
161+
return event
162+
}
163+
164+
private def RealtimeReporterEvent convertToPostSuiteEvent(Document doc) {
165+
val event = new PostSuiteEvent
166+
val node = doc.getNode("/event/suite")
167+
if (node instanceof Element) {
168+
event.id = node.attributes?.getNamedItem("id")?.nodeValue
169+
event.populate(node)
170+
}
171+
return event
172+
}
173+
174+
private def RealtimeReporterEvent convertToPreTestEvent(Document doc) {
175+
val event = new PreTestEvent
176+
val node = doc.getNode("/event/test")
177+
if (node instanceof Element) {
178+
event.id = node.attributes?.getNamedItem("id")?.nodeValue
179+
event.testNumber = Integer.valueOf(node.getElementsByTagName("testNumber")?.item(0)?.textContent)
180+
event.totalNumberOfTests = Integer.valueOf(node.getElementsByTagName("totalNumberOfTests")?.item(0)?.textContent)
181+
}
182+
return event
183+
}
184+
185+
private def RealtimeReporterEvent convertToPostTestEvent(Document doc) {
186+
val event = new PostTestEvent
187+
val node = doc.getNode("/event/test")
188+
if (node instanceof Element) {
189+
event.id = node.attributes?.getNamedItem("id")?.nodeValue
190+
event.testNumber = Integer.valueOf(node.getElementsByTagName("testNumber")?.item(0)?.textContent)
191+
event.totalNumberOfTests = Integer.valueOf(node.getElementsByTagName("totalNumberOfTests")?.item(0)?.textContent)
192+
event.populate(node)
193+
val failedExpectations = node.getNodeList("failedExpectations/expectation")
194+
for (i : 0 ..< failedExpectations.length) {
195+
val expectationNode = failedExpectations.item(i)
196+
val expectation = new Expectation
197+
event.failedExpectations.add(expectation)
198+
expectation.populate(expectationNode)
199+
}
200+
}
201+
return event
202+
}
203+
204+
private def void populate(Suite suite, Node node) {
205+
if (node instanceof Element) {
206+
suite.id = node.attributes?.getNamedItem("id")?.nodeValue
207+
suite.name = node.getElementsByTagName("name")?.item(0)?.textContent
208+
suite.description = node.getElementsByTagName("description")?.item(0)?.textContent
209+
val nodeList = node.getNodeList("items/*")
210+
for (i : 0 ..< nodeList.length) {
211+
val childNode = nodeList.item(i)
212+
if (childNode.nodeName == "suite") {
213+
val childSuite = new Suite
214+
suite.items.add(childSuite)
215+
childSuite.populate(childNode)
216+
} else if (childNode.nodeName == "test") {
217+
val childTest = new Test
218+
suite.items.add(childTest)
219+
childTest.populate(childNode)
220+
}
221+
}
222+
}
223+
}
224+
225+
private def void populate(Test test, Node node) {
226+
if (node instanceof Element) {
227+
test.id = node.attributes?.getNamedItem("id")?.nodeValue
228+
test.executionType = node.getElementsByTagName("executionType")?.item(0)?.textContent
229+
test.ownerName = node.getElementsByTagName("ownerName")?.item(0)?.textContent
230+
test.objectName = node.getElementsByTagName("objectName")?.item(0)?.textContent
231+
test.procedureName = node.getElementsByTagName("procedureName")?.item(0)?.textContent
232+
test.disabled = node.getElementsByTagName("disabled")?.item(0)?.textContent == "true"
233+
test.name = node.getElementsByTagName("name")?.item(0)?.textContent
234+
test.description = node.getElementsByTagName("description")?.item(0)?.textContent
235+
test.testNumber = Integer.valueOf(node.getElementsByTagName("testNumber")?.item(0)?.textContent)
236+
}
237+
}
238+
239+
private def void populate(PostEvent event, Node node) {
240+
if (node instanceof Element) {
241+
event.startTime = node.getElementsByTagName("startTime")?.item(0)?.textContent
242+
event.endTime = node.getElementsByTagName("endTime")?.item(0)?.textContent
243+
event.executionTime = Double.valueOf(node.getElementsByTagName("executionTime")?.item(0)?.textContent)
244+
event.counter.populate(node)
245+
event.errorStack = node.getElementsByTagName("errorStack")?.item(0)?.textContent
246+
event.serverOutput = node.getElementsByTagName("serverOutput")?.item(0)?.textContent
247+
}
248+
}
249+
250+
private def void populate(Counter counter, Node node) {
251+
if (node instanceof Element) {
252+
val counterNode = node.getElementsByTagName("counter")?.item(0)
253+
if (counterNode instanceof Element) {
254+
counter.disabled = Integer.valueOf(counterNode.getElementsByTagName("disabled")?.item(0)?.textContent)
255+
counter.success = Integer.valueOf(counterNode.getElementsByTagName("success")?.item(0)?.textContent)
256+
counter.failure = Integer.valueOf(counterNode.getElementsByTagName("failure")?.item(0)?.textContent)
257+
counter.error = Integer.valueOf(counterNode.getElementsByTagName("error")?.item(0)?.textContent)
258+
counter.warning = Integer.valueOf(counterNode.getElementsByTagName("warning")?.item(0)?.textContent)
259+
}
260+
}
261+
}
262+
263+
private def void populate(Expectation expectation, Node node) {
264+
if (node instanceof Element) {
265+
expectation.description = node.getElementsByTagName("description")?.item(0)?.textContent
266+
expectation.message = node.getElementsByTagName("message")?.item(0)?.textContent
267+
expectation.caller = node.getElementsByTagName("caller")?.item(0)?.textContent
268+
}
269+
}
270+
}

0 commit comments

Comments
 (0)