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