Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/test/functional/cmdline_options_tester/src/TestConfigParser.java
6004 views
1
/*******************************************************************************
2
* Copyright (c) 2004, 2020 IBM Corp. and others
3
*
4
* This program and the accompanying materials are made available under
5
* the terms of the Eclipse Public License 2.0 which accompanies this
6
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
7
* or the Apache License, Version 2.0 which accompanies this distribution and
8
* is available at https://www.apache.org/licenses/LICENSE-2.0.
9
*
10
* This Source Code may also be made available under the following
11
* Secondary Licenses when the conditions for such availability set
12
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
13
* General Public License, version 2 with the GNU Classpath
14
* Exception [1] and GNU General Public License, version 2 with the
15
* OpenJDK Assembly Exception [2].
16
*
17
* [1] https://www.gnu.org/software/classpath/license.html
18
* [2] http://openjdk.java.net/legal/assembly-exception.html
19
*
20
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
21
*******************************************************************************/
22
23
import java.util.*;
24
import java.util.regex.Pattern;
25
26
import com.oti.j9.exclude.*;
27
28
class TestConfigParser {
29
private ExcludeList _excludes;
30
private String[] _platforms;
31
private TestSuite _suite;
32
private boolean _verbose;
33
private int _outputLimit;
34
private boolean _debugCmdOnTimeout = false;
35
private String _modeHints;
36
37
static String archName = System.getProperty("os.arch");
38
static boolean isRiscv = archName.toLowerCase().contains("riscv");
39
40
/**
41
* If true, the test suite will print out the full output for each test case, regardless of whether
42
* it passed or failed
43
*/
44
void setVerbose( boolean verbose ) {
45
_verbose = verbose;
46
if (_suite != null) {
47
_suite.setVerbose( _verbose );
48
}
49
}
50
51
void setOutputLimit ( int limit ) {
52
_outputLimit = limit;
53
if (_suite != null) {
54
_suite.setOutputLimit( _outputLimit );
55
}
56
}
57
/**
58
* Takes the given configuration file, exclude list, and optional platforms, and generates a test suite
59
* complete with test cases and expected outputs.
60
*
61
* @param configFile - The file from which to read the test case information. It should be formatted in
62
* accordance with the cmdlinetester.dtd file (see j:\j9\testing\cmdlinetester\)
63
* @param excludes - The exclude list, which specifies test cases to exclude on certain platforms. See
64
* j:\j9\testing\excludes\ for more information on the structure of this file. If null,
65
* no tests are excluded
66
* @param platforms - A comma-delimited set of strings identifying which platform-dependent output strings
67
* in the configuration file should be used.
68
* @param modeHints - List of hints specified for the mode being used to run this test suite.
69
* @return The test suite object from which the tests can be run, and which will output the pass/fail stats
70
* of the test cases.
71
*/
72
TestSuite runTests( String configFile, ExcludeList excludes, String platforms, boolean debugCmdOnTimeout, String modeHints ) {
73
_excludes = excludes;
74
_platforms = doSplit( platforms, "," );
75
_debugCmdOnTimeout = debugCmdOnTimeout;
76
_modeHints = modeHints;
77
XMLParser xmlp = new XMLParser();
78
xmlp.parse( configFile, new TestConfigDocumentHandler() );
79
return _suite;
80
}
81
82
/**
83
* Basic string-splitting function, roughly equivalent to perl's split( /delim/, s ).
84
*
85
* @param s The string to be split
86
* @param delim The delimiter between the different pieces in the string. This must be non-null
87
* @return The array of pieces in the string. This will always be non-null, although may be of size zero
88
* if <code>s</code> is null or of length zero.
89
*/
90
private static String[] doSplit( String s, String delim ) {
91
if (s == null || s.length() == 0) {
92
return new String[0];
93
}
94
StringTokenizer st = new StringTokenizer( s, delim );
95
String[] pieces = new String[ st.countTokens() ];
96
for (int i = 0; i < pieces.length; i++) {
97
pieces[i] = st.nextToken();
98
}
99
return pieces;
100
}
101
102
/**
103
* The class that is used as the document handler when SAX-ing the configuration file. This
104
* class is responsible for reading information from the configuration file, converting it to
105
* the relevant Java objects and adding them to the test suite.
106
*/
107
class TestConfigDocumentHandler implements IXMLDocumentHandler {
108
/* Test currently being processed */
109
private Test _currentTest;
110
/* Output case currently being processed */
111
private Output _currentOutput;
112
/* exec case currently being processed */
113
private CommandExecuter _currentExec;
114
/* The relevant non-element character data being spit out by the SAX parser */
115
private StringBuffer _data = new StringBuffer();
116
/* This is a single-iteration TestIterator which will run all the things given to it exactly once */
117
private TestIterator _iterator;
118
// if this is a new-style command where the executable is specified on its own, that is stored here (otherwise, this variable must be null)
119
private String _commandExecutable;
120
// this flag allows us to continue to use this parser implementation for the more complicated use of the command element without having to re-write it as a sort of delegating PDA
121
private boolean _isInNewCommandStanza;
122
// used to collect the contents of the in-order "arg" tags under the new-style command stanza (which are then passed as arguments to the underlying process)
123
private Vector _commandArgs;
124
// used to collect the contents of the in-order "input" tags under the new-style command stanza (which are then fed into the stdin of the underlying process as new-line terminated strings)
125
private Vector _commandInputLines;
126
127
/**
128
* Empty implementation
129
*/
130
public void xmlStartDocument() {
131
}
132
133
/**
134
* Empty implementation
135
*/
136
public void xmlEndDocument() {
137
}
138
139
/**
140
* @see com.oti.j9.exclude.IXMLDocumentHandler#xmlStartElement(String,Hashtable)
141
*/
142
public void xmlStartElement(String elementName, Hashtable attributes) {
143
if (elementName.equalsIgnoreCase("suite")) {
144
System.out.println("*** Starting test suite: " + attributes.get("id") + " ***");
145
long timeout = getTimeout( attributes.get("timeout"), 10000 );
146
_suite = new TestSuite( _excludes, timeout, _verbose, _outputLimit );
147
_iterator = new TestIterator( _suite );
148
149
} else if (elementName.equalsIgnoreCase("loop")) {
150
String index = (String)attributes.get("index");
151
String from = (String)attributes.get("from");
152
String until = (String)attributes.get("until");
153
String inc = (String)attributes.get("inc");
154
_iterator.addSubIterator( new TestIterator( _suite, index, from, until, inc ) );
155
156
} else if (elementName.equalsIgnoreCase("test")) {
157
if (hasAllowedPlatform((String)attributes.get("platforms"))) {
158
String id = (String)attributes.get("id");
159
String modeHints = (String)attributes.get("modeHints");
160
if (hasAllowedHints(modeHints)) {
161
String timeout = (String)attributes.get("timeout");
162
163
/* Set 16 hours (57600 secs) for timeout on RISC-V due to the lack of JIT */
164
timeout = (isRiscv) ? "57600" : timeout;
165
166
_currentTest = new Test( id, timeout, _debugCmdOnTimeout );
167
} else {
168
if ((_modeHints == null) || (_modeHints.matches("\\s*"))) {
169
_modeHints = "empty";
170
}
171
System.out
172
.println("Test Skipped: "
173
+ id
174
+ " : Hints specified for this test { "
175
+ modeHints
176
+ " } do not match with the hints for current mode { "
177
+ _modeHints + " }\n");
178
_currentTest = null;
179
}
180
} else {
181
_currentTest = null;
182
}
183
} else if (elementName.equalsIgnoreCase("output")) {
184
if (hasAllowedPlatform((String)attributes.get("platforms"))) {
185
String regex = (String)attributes.get("regex");
186
String javaUtilPattern = "no";
187
if (null != attributes.get("javaUtilPattern")) {
188
javaUtilPattern = (String)attributes.get("javaUtilPattern");
189
}
190
String showRegexMatch = "no";
191
if (null != attributes.get("showMatch")) {
192
showRegexMatch = (String)attributes.get("showMatch");
193
}
194
String caseSensitive = (String)attributes.get("caseSensitive");
195
String type = (String)attributes.get("type");
196
_currentOutput = new Output( regex, javaUtilPattern, showRegexMatch, caseSensitive, type );
197
} else {
198
_currentOutput = null;
199
}
200
201
} else if (elementName.equalsIgnoreCase("saveoutput")) {
202
if (hasAllowedPlatform((String)attributes.get("platforms"))) {
203
String regex = (String)attributes.get("regex");
204
String javaUtilPattern = "no";
205
String showRegexMatch = "no";
206
if (null != attributes.get("showMatch")) {
207
showRegexMatch = (String)attributes.get("showMatch");
208
}
209
String caseSensitive = (String)attributes.get("caseSensitive");
210
String saveName = (String)attributes.get("saveName");
211
String splitIndex = (String)attributes.get("splitIndex");
212
String splitBy = (String)attributes.get("splitBy");
213
String type = (String)attributes.get("type");
214
_currentOutput = new SaveOutput( regex, javaUtilPattern, showRegexMatch, caseSensitive, type, saveName, splitIndex, splitBy);
215
} else {
216
_currentOutput = null;
217
}
218
219
} else if (elementName.equalsIgnoreCase("return")) {
220
if ((_currentTest != null) && (hasAllowedPlatform((String)attributes.get("platforms")))) {
221
String value = (String)attributes.get("value");
222
String type = (String)attributes.get("type");
223
_currentTest.addTestCondition( new ReturnValue( value, type ) );
224
}
225
226
} else if (elementName.equalsIgnoreCase("variable")) {
227
if (hasAllowedPlatform((String)attributes.get("platforms"))) {
228
String name = (String)attributes.get("name");
229
String value = (String)attributes.get("value");
230
_iterator.addCommand( new VariableAdder( name, value ) );
231
}
232
233
} else if (elementName.equalsIgnoreCase("exec")) {
234
if (hasAllowedPlatform((String)attributes.get("platforms"))) {
235
String command = (String)attributes.get("command");
236
String background = (String)attributes.get("background");
237
String captureVarStdout = (String)attributes.get("capture");
238
String captureVarStderr = (String)attributes.get("captureStderr");
239
String returnVar = (String)attributes.get("return");
240
_currentExec = new CommandExecuter(command, background, captureVarStdout, captureVarStderr, returnVar);
241
}
242
} else if (elementName.equalsIgnoreCase("delay")) {
243
_iterator.addCommand( new Delay( (String)attributes.get("length") ) );
244
245
} else if (elementName.equalsIgnoreCase("echo")) {
246
_iterator.addCommand( new Echo( (String)attributes.get("value") ) );
247
} else if (elementName.equalsIgnoreCase("envvar")) {
248
// to get envvars to work properly in loops, changed EnvVar class to Command type
249
_iterator.addCommand( new EnvVar( (String)attributes.get("name"), (String)attributes.get("value") ) );
250
} else if (elementName.equalsIgnoreCase("command")) {
251
//the command tag can be structured multiple ways. It can just be simple like <command>echo This is what I am echoing</command> or
252
// it can be more complicated like:
253
// <command command="someCommand"><arg>one argument</arg><arg>arg two</arg><input>one line of stdin</input><input>second line of stdin</input></command>
254
// (note that the use of this "command" attribute looks odd but is to be consistent with "exec")
255
// so we will determine which one is which in this start tag since we would need a "command" attribute to be using the new style
256
String commandExecutable = (String)attributes.get("command");
257
if (null != commandExecutable)
258
{
259
//this is the "new-style" command tag so get the executable name
260
_commandExecutable = commandExecutable;
261
//also set the flag to know that we are in a command context and create the arrays for the arguments and inputs which may appear in that stanza
262
_isInNewCommandStanza = true;
263
_commandArgs = new Vector();
264
_commandInputLines = new Vector();
265
}
266
} else if (elementName.equalsIgnoreCase("if")) {
267
_iterator.addCommand( new IfTest( (String)attributes.get("testVariable"), (String)attributes.get("testValue"),
268
(String)attributes.get("resultVariable"), (String)attributes.get("resultValue") ) );
269
}
270
271
// clear buffer to read in stuff within this tag
272
_data.setLength(0);
273
}
274
275
/**
276
* @see com.oti.j9.exclude.IXMLDocumentHandler#xmlEndElement(String)
277
*/
278
public void xmlEndElement(String elementName) {
279
String readData = _data.toString();
280
281
if (elementName.equalsIgnoreCase("loop")) {
282
// </loop> - close off the most-nested loop. if _iterator doesn't have any
283
// nested loops, it will return false, so we close off _iterator by setting it
284
// to null
285
_iterator.closeInnerLoop();
286
287
} else if (elementName.equalsIgnoreCase("command")) {
288
// </command>
289
if (_currentTest != null) {
290
if (_isInNewCommandStanza) {
291
_currentTest.setSplitCommand(_commandExecutable, _commandArgs, _commandInputLines);
292
} else {
293
_currentTest.setCommand(readData);
294
}
295
_isInNewCommandStanza = false;
296
}
297
} else if (elementName.equalsIgnoreCase("output") || elementName.equalsIgnoreCase("saveoutput")) {
298
// </output> - check to make sure _currentOutput is not null
299
// before proceeding - this may happen if the output tag was thrown out
300
// due to platform-dependency-incompatibilities
301
if ((_currentTest != null) && (_currentOutput != null)) {
302
_currentOutput.setOutput(readData);
303
_currentTest.addTestCondition( _currentOutput );
304
}
305
306
} else if (elementName.equalsIgnoreCase("test")) {
307
// </test> - pass it off to the iterator to run
308
if (_currentTest != null) {
309
_iterator.addTest( _currentTest );
310
}
311
} else if (elementName.equalsIgnoreCase("exec")) {
312
if (_currentExec != null) {
313
_iterator.addCommand( _currentExec );
314
}
315
_currentExec = null;
316
} else if (elementName.equalsIgnoreCase("arg")) {
317
if (_isInNewCommandStanza) {
318
_commandArgs.add(readData);
319
} else {
320
if (_currentExec != null) {
321
_currentExec.addArg(readData);
322
}
323
}
324
} else if (elementName.equalsIgnoreCase("input")) {
325
if (_isInNewCommandStanza) {
326
_commandInputLines.add(readData);
327
}
328
}
329
_data.setLength( 0 ); // any data in here has outlived it's usefulness
330
}
331
332
/**
333
* @see com.oti.j9.exclude.IXMLDocumentHandler#xmlCharacters(String)
334
*/
335
public void xmlCharacters(String chars) {
336
_data.append( chars );
337
}
338
339
private boolean hasAllowedPlatform( String platforms ) {
340
// check the platform-dependencies. if there are no
341
// listed platforms or if any one of the listed platforms matches any one of
342
// the platforms specified on the runtime commandline, then we return true
343
String evaluatePlatforms = TestSuite.evaluateVariables(platforms);
344
String[] requiredPlatforms = doSplit( evaluatePlatforms, "," );
345
boolean allow = (requiredPlatforms.length == 0);
346
for (int i = 0; i < _platforms.length; i++) {
347
for (int j = 0; j < requiredPlatforms.length; j++) {
348
if (Pattern.matches(requiredPlatforms[j], _platforms[i])) {
349
allow = true;
350
// like a double break
351
j = requiredPlatforms.length;
352
i = _platforms.length;
353
}
354
}
355
}
356
return allow;
357
}
358
359
private boolean hasAllowedHints(String modeHints) {
360
String[] hintsSet = doSplit(modeHints, ",");
361
if (hintsSet.length == 0) {
362
return true;
363
} else if (_modeHints == null) {
364
return false;
365
} else {
366
for (int i = 0; i < hintsSet.length; i++) {
367
boolean allHintsFound = true;
368
String[] hints = doSplit(hintsSet[i], " ");
369
for (int j = 0; j < hints.length; j++) {
370
if (_modeHints.indexOf(hints[i]) == -1) {
371
allHintsFound = false;
372
break;
373
}
374
}
375
if (allHintsFound == true) {
376
return true;
377
}
378
}
379
}
380
return false;
381
}
382
383
private long getTimeout( Object attribute, long defaultValue ) {
384
long timeout = defaultValue;
385
try {
386
timeout = 1000 * Integer.parseInt( ((String)attribute).trim() );
387
} catch (Exception e) { }
388
return timeout;
389
}
390
}
391
}
392
393