2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.onap.policy.pdp.test.custom;
23 import java.io.BufferedReader;
24 import java.io.ByteArrayInputStream;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.InputStreamReader;
28 import java.io.OutputStream;
29 import java.net.HttpURLConnection;
30 import java.net.MalformedURLException;
32 import java.nio.file.FileVisitResult;
33 import java.nio.file.Files;
34 import java.nio.file.Path;
35 import java.nio.file.Paths;
36 import java.nio.file.SimpleFileVisitor;
37 import java.nio.file.attribute.BasicFileAttributes;
38 import java.util.ArrayList;
39 import java.util.List;
40 import java.util.regex.Matcher;
41 import java.util.regex.Pattern;
43 import org.apache.commons.cli.CommandLine;
44 import org.apache.commons.cli.GnuParser;
45 import org.apache.commons.cli.HelpFormatter;
46 import org.apache.commons.cli.Option;
47 import org.apache.commons.cli.Options;
48 import org.apache.commons.cli.ParseException;
49 import org.apache.commons.io.IOUtils;
50 import org.apache.http.entity.ContentType;
51 import org.onap.policy.common.logging.flexlogger.FlexLogger;
52 import org.onap.policy.common.logging.flexlogger.Logger;
54 import com.att.research.xacml.api.AttributeValue;
55 import com.att.research.xacml.api.DataType;
56 import com.att.research.xacml.api.DataTypeException;
57 import com.att.research.xacml.api.DataTypeFactory;
58 import com.att.research.xacml.api.Decision;
59 import com.att.research.xacml.api.Identifier;
60 import com.att.research.xacml.api.Request;
61 import com.att.research.xacml.api.RequestAttributes;
62 import com.att.research.xacml.api.Response;
63 import com.att.research.xacml.api.Result;
64 import com.att.research.xacml.api.pdp.PDPEngine;
65 import com.att.research.xacml.api.pdp.PDPEngineFactory;
66 import com.att.research.xacml.api.pdp.PDPException;
67 import com.att.research.xacml.api.pep.PEPException;
68 import com.att.research.xacml.std.IdentifierImpl;
69 import com.att.research.xacml.std.StdAttributeValue;
70 import com.att.research.xacml.std.StdMutableAttribute;
71 import com.att.research.xacml.std.StdMutableRequest;
72 import com.att.research.xacml.std.StdMutableRequestAttributes;
73 import com.att.research.xacml.std.dom.DOMRequest;
74 import com.att.research.xacml.std.dom.DOMResponse;
75 import com.att.research.xacml.std.dom.DOMStructureException;
76 import com.att.research.xacml.std.json.JSONRequest;
77 import com.att.research.xacml.std.json.JSONResponse;
78 import com.att.research.xacml.std.json.JSONStructureException;
79 import com.att.research.xacml.util.FactoryException;
80 import com.att.research.xacml.util.XACMLProperties;
81 import com.google.common.base.Splitter;
82 import com.google.common.collect.Lists;
85 * This is a base class for setting up a test environment. Using properties files, it contains the
86 * necessary information for
87 * 1. defining and providing attributes
88 * 2. defining and instantiating the PDP engine
89 * 3. creating PEP requests and calling the PDP engine
93 public class TestBase extends SimpleFileVisitor<Path> {
94 private static final Logger logger = FlexLogger.getLogger(TestBase.class);
96 public class HelpException extends Exception {
97 private static final long serialVersionUID = 1L;
102 * This private class holds information for properties defined for attribute
103 * generation. The user can configure the properties file such that attributes
104 * can be automatically generated and added into each request.
111 BufferedReader reader;
112 List<StdMutableAttribute> attributes = new ArrayList<>();
114 public Generator(Path path) {
119 * read - reads in the next line of data
121 * @return String - a line from the csv containing attribute data
123 public String read() {
127 is = Files.newInputStream(file);
128 } catch (IOException e) {
133 if (reader == null) {
134 reader = new BufferedReader(new InputStreamReader(this.is));
137 str = reader.readLine();
140 // No more strings, close up
144 if (logger.isDebugEnabled()) {
147 } catch (IOException e) {
153 public void close() {
154 if (this.reader != null) {
157 } catch (IOException idontcare) {
167 public static final String PROP_GENERATOR = "xacml.attribute.generator";
169 public static final String OPTION_HELP = "help";
170 public static final String OPTION_TESTDIR = "dir";
171 public static final String OPTION_TESTREST = "rest";
172 public static final String OPTION_TESTURL = "url";
173 public static final String OPTION_TESTOUTPUT = "output";
174 public static final String OPTION_LOOP = "loop";
175 public static final String OPTION_TESTNUMBERS = "testNumbers";
177 public static final String DEFAULT_RESTURL = "https://localhost:8080/pdp/"; // Modified for test purpose. Port no. 8443 to 8080
179 public static Options options = new Options();
181 options.addOption(new Option(OPTION_HELP, false, "Prints help."));
182 options.addOption(new Option(OPTION_TESTDIR, true, "Directory path where all the test properties and data are located."));
183 options.addOption(new Option(OPTION_TESTREST, false, "Test against RESTful PDP."));
184 options.addOption(new Option(OPTION_TESTURL, true, "URL to the RESTful PDP. Default is " + DEFAULT_RESTURL));
185 options.addOption(new Option(OPTION_TESTOUTPUT, true, "Specify a different location for dumping responses."));
186 options.addOption(new Option(OPTION_LOOP, true, "Number of times to loop through the tests. Default is 1. A value of -1 runs indefinitely."));
187 options.addOption(new Option(OPTION_TESTNUMBERS, true, "Comma-separated list of numbers found in the names of the test files to be run. Numbers must exactly match the file name, e.g. '02'. Used to limit testing to specific set of tests."));
190 protected String directory = null;
191 protected Path output = null;
192 protected boolean isREST;
193 protected URL restURL = null;
194 protected int loop = 1;
195 protected PDPEngine engine = null;
196 protected List<Generator> generators = new ArrayList<>();
197 protected static DataTypeFactory dataTypeFactory = null;
199 private long permits = 0;
200 private long denies = 0;
201 private long notapplicables = 0;
202 private long indeterminates = 0;
204 private long expectedPermits = 0;
205 private long expectedDenies = 0;
206 private long expectedNotApplicables = 0;
207 private long expectedIndeterminates = 0;
209 private long generatedpermits = 0;
210 private long generateddenies = 0;
211 private long generatednotapplicables = 0;
212 private long generatedindeterminates = 0;
214 private long responseMatches = 0;
215 private long responseNotMatches = 0;
217 private String[] testNumbersArray = null;
219 protected final Pattern pattern = Pattern.compile("Request[.]\\d+[.](Permit|Deny|NA|Indeterminate|Generate|Unknown)\\.(json|xml)");
221 public static boolean isJSON(Path file) {
222 return file.toString().endsWith(".json");
225 public static boolean isXML(Path file) {
226 return file.toString().endsWith(".xml");
229 public TestBase(String[] args) throws ParseException, MalformedURLException, HelpException {
231 // Finish Initialization
233 this.restURL = new URL(DEFAULT_RESTURL);
237 this.parseCommands(args);
241 * Parse in the command line arguments that the following parameters:
243 * @param args - command line arguments
244 * @throws ParseException
245 * @throws MalformedURLException
246 * @throws HelpException
248 protected void parseCommands(String[] args) throws ParseException, MalformedURLException, HelpException {
250 // Parse the command line options
253 cl = new GnuParser().parse(options, args);
255 // Check for what we have
257 if (cl.hasOption(OPTION_HELP)) {
258 new HelpFormatter().printHelp("Usage: -dir testdirectory OPTIONS",
260 throw new HelpException();
262 if (cl.hasOption(OPTION_TESTDIR)) {
263 this.directory = cl.getOptionValue(OPTION_TESTDIR);
265 throw new IllegalArgumentException("You must specify a test directory. -dir path/to/some/where");
267 if (cl.hasOption(OPTION_TESTREST)) {
272 if (cl.hasOption(OPTION_TESTURL)) {
273 this.restURL = new URL(cl.getOptionValue(OPTION_TESTURL));
275 if (cl.hasOption(OPTION_TESTOUTPUT)) {
276 this.output = Paths.get(cl.getOptionValue(OPTION_TESTOUTPUT));
278 this.output = Paths.get(this.directory, "results");
280 if (cl.hasOption(OPTION_LOOP)) {
281 this.loop = Integer.parseInt(cl.getOptionValue(OPTION_LOOP));
283 if (cl.hasOption(OPTION_TESTNUMBERS)) {
284 String testNumberString = cl.getOptionValue(OPTION_TESTNUMBERS);
285 testNumbersArray = testNumberString.split(",");
287 // reset strings to include dots so they exactly match pattern in file name
289 for (int i = 0; i < testNumbersArray.length; i++) {
290 testNumbersArray[i] = "." + testNumbersArray[i] + ".";
296 * Using the command line options that were parsed, configures our test instance.
298 * @throws FactoryException
300 protected void configure() throws FactoryException {
302 // Setup the xacml.properties file
304 if (this.directory == null) {
305 throw new IllegalArgumentException("Must supply a path to a test directory.");
307 Path pathDir = Paths.get(this.directory, "xacml.properties");
308 if (Files.notExists(pathDir)) {
309 throw new IllegalArgumentException(pathDir.toString() + " does not exist.");
312 // Set it as the System variable so the XACML factories know where the properties are
315 System.setProperty(XACMLProperties.XACML_PROPERTIES_NAME, pathDir.toString());
317 // Now we can create the data type factory
319 dataTypeFactory = DataTypeFactory.newInstance();
321 // Load in what generators we are to create
323 String generators = XACMLProperties.getProperty(PROP_GENERATOR);
324 if (generators != null) {
326 // Parse the generators
328 for (String generator : Splitter.on(',').trimResults().omitEmptyStrings().split(generators)) {
329 this.configureGenerator(generator);
333 // If we are embedded, create our engine
335 if (this.isREST == false) {
336 PDPEngineFactory factory = PDPEngineFactory.newInstance();
337 this.engine = factory.newEngine();
340 // Remove all the responses from the results directory
342 this.removeResults();
346 * Removes all the Response* files from the results directory.
349 public void removeResults() {
352 // Determine where the results are supposed to be written to
355 if (this.output != null) {
356 resultsPath = this.output;
358 resultsPath = Paths.get(this.directory.toString(), "results");
363 Files.walkFileTree(resultsPath, new SimpleFileVisitor<Path>() {
366 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
367 if (file.getFileName().toString().startsWith("Response")) {
370 return super.visitFile(file, attrs);
373 } catch (IOException e) {
374 logger.error("Failed to removeRequests from " + this.directory + " " + e);
379 * Configure's a specific generator instance from the properties file.
383 protected void configureGenerator(String generator) {
384 String prefix = PROP_GENERATOR + "." + generator;
385 String file = XACMLProperties.getProperty(prefix + ".file");
387 // Create a generator object
389 Generator gen = new Generator(Paths.get(this.directory, file));
390 this.generators.add(gen);
394 String attributes = XACMLProperties.getProperty(prefix + ".attributes");
395 for (String attribute : Splitter.on(',').trimResults().omitEmptyStrings().split(attributes)) {
396 String attributePrefix = prefix + ".attributes." + attribute;
398 // Create an attribute value. It is simply a placeholder for the field within
399 // the CSV that contains the actual attribute value. It mainly holds the data type
401 Identifier datatype = new IdentifierImpl(XACMLProperties.getProperty(attributePrefix + ".datatype"));
402 Integer field = Integer.parseInt(XACMLProperties.getProperty(attributePrefix + ".field"));
403 StdAttributeValue<?> value = new StdAttributeValue<>(datatype, field);
405 // Get the rest of the attribute properties
407 Identifier category = new IdentifierImpl(XACMLProperties.getProperty(attributePrefix + ".category"));
408 Identifier id = new IdentifierImpl(XACMLProperties.getProperty(attributePrefix + ".id"));
409 String issuer = XACMLProperties.getProperty(attributePrefix + ".issuer");
410 boolean include = Boolean.parseBoolean(XACMLProperties.getProperty(attributePrefix + ".include", "false"));
412 // Now we have a skeleton attribute
414 gen.attributes.add(new StdMutableAttribute(category, id, value, issuer, include));
419 * This runs() the test instance. It first configure's itself and then walks the
420 * requests directory issue each request to the PDP engine.
422 * @throws IOException
423 * @throws FactoryException
426 public void run() throws IOException, FactoryException {
428 // Configure ourselves
436 long lTimeStart = System.currentTimeMillis();
437 logger.info("Run number: " + runs);
439 // Walk the request directory
441 Files.walkFileTree(Paths.get(this.directory.toString(), "requests"), this);
442 long lTimeEnd = System.currentTimeMillis();
443 logger.info("Run elapsed time: " + (lTimeEnd - lTimeStart) + "ms");
453 } while ((this.loop == -1 ? true : runs <= this.loop));
457 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
459 // Sanity check the file name
461 Matcher matcher = this.pattern.matcher(file.getFileName().toString());
462 if (matcher.matches()) {
464 // if user has limited which files to use, check that here
466 if (testNumbersArray != null) {
467 String fileNameString = file.getFileName().toString();
468 boolean found = false;
469 for (String numberString : testNumbersArray) {
470 if (fileNameString.contains(numberString)) {
475 if (found == false) {
477 // this test is not in the list to be run, so skip it
479 return super.visitFile(file, attrs);
484 // Pull what this request is supposed to be
487 int count = matcher.groupCount();
489 group = matcher.group(count-1);
494 this.sendRequest(file, group);
495 } catch (Exception e) {
497 logger.error("Exception Occured"+e);
500 return super.visitFile(file, attrs);
504 * When a request file is encountered, this method is called send the request to the PDP engine. It will also dump
505 * the response object. If the group equals "Generate", then it will loop and send the request with generated attributes
506 * until that list is empty.
508 * @param file - Request file. Eg. Request-01-Permit.json
509 * @param group - This is the parsed out string of the request file that defines if it is a Permit/Deny/Generate etc.
512 protected void sendRequest(Path file, String group) throws Exception {
513 logger.info(file.toString());
514 int requestCount = 0;
517 // Generate the request
519 Request request = this.generateRequest(file, group);
521 // Was something generated?
523 if (request == null) {
525 // Get out of the loop
527 logger.info("NULL request generated.");
530 logger.info(request);
534 Response response = this.callPDP(request);
536 // Process the response
538 this.processResponse(file, request, response, group, requestCount);
540 // Is this a generated request?
542 if (group.equals("Generate")) {
544 // Yes, increment counter and move
545 // on to the next generated request.
550 // Nope, exit the loop
554 } while (group.equals("Generate"));
558 * Sends the request object to the PDP engine. Either the embedded engine or the RESTful engine.
560 * @param request - XACML request object
561 * @return Response - returns the XACML response object
563 protected Response callPDP(Request request) {
565 // Send it to the PDP
567 Response response = null;
570 String jsonString = JSONRequest.toString(request, false);
574 response = this.callRESTfulPDP(new ByteArrayInputStream(jsonString.getBytes()));
575 } catch (Exception e) {
576 logger.error("Error in sending RESTful request: " + e, e);
580 // Embedded call to PDP
582 long lTimeStart = System.currentTimeMillis();
584 response = this.engine.decide(request);
585 } catch (PDPException e) {
588 long lTimeEnd = System.currentTimeMillis();
589 logger.info("Elapsed Time: " + (lTimeEnd - lTimeStart) + "ms");
595 * Reads the request file into a Request object based on its type.
597 * If the request has "Generate" in its filename, then this function will add
598 * generated attributes into the request.
600 * @param file - Request file. Eg. Request-01-Permit.json
601 * @param group - This is the parsed out string of the request file that defines if it is a Permit/Deny/Generate etc.
603 * @throws JSONStructureException
604 * @throws DOMStructureException
605 * @throws PEPException
607 protected Request generateRequest(Path file, String group) throws JSONStructureException, DOMStructureException, PEPException {
609 // Convert to a XACML Request Object
611 Request request = null;
612 if (TestBase.isJSON(file)) {
613 request = JSONRequest.load(file.toFile());
614 } else if (TestBase.isXML(file)) {
615 request = DOMRequest.load(file.toFile());
617 if (request == null) {
618 throw new PEPException("Invalid Request File: " + file.toString());
621 // Only if this request has "Generate"
622 // Request.XX.Generate.[json|xml]
624 if (group.equals("Generate")) {
626 // Add attributes to it
628 request = this.onNextRequest(request);
637 * Called to add in generated attributes into the request.
642 protected Request onNextRequest(Request request) {
644 // If we have no generators, just return
646 if (this.generators.isEmpty()) {
650 // Copy the request attributes
652 List<StdMutableRequestAttributes> attributes = new ArrayList<>();
653 for (RequestAttributes a : request.getRequestAttributes()) {
654 attributes.add(new StdMutableRequestAttributes(a));
657 // Iterate the generators
659 for (Generator generator : this.generators) {
663 String line = generator.read();
665 // Was something read?
669 // No more rows to read, return null
676 List<String> fields = Lists.newArrayList(Splitter.on(',').trimResults().split(line));
678 // Now work on the attributes
680 for (StdMutableAttribute attribute : generator.attributes) {
682 // Grab the attribute holder, which holds the datatype and field. There should
683 // be only ONE object in the collection.
685 AttributeValue<?> value = attribute.getValues().iterator().next();
686 Integer field = (Integer) value.getValue();
688 // Is the field number valid?
690 if (field >= fields.size()) {
691 logger.error("Not enough fields: " + field + "(" + fields.size() + ")");
695 // Determine what datatype it is
697 DataType<?> dataTypeExtended = dataTypeFactory.getDataType(value.getDataTypeId());
698 if (dataTypeExtended == null) {
699 logger.error("Failed to determine datatype");
703 // Create the attribute value
706 AttributeValue<?> attributeValue = dataTypeExtended.createAttributeValue(fields.get(field));
708 // Create the attribute
710 StdMutableAttribute newAttribute = new StdMutableAttribute(attribute.getCategory(),
711 attribute.getAttributeId(),
713 attribute.getIssuer(),
714 attribute.getIncludeInResults());
715 boolean added = false;
716 for (StdMutableRequestAttributes a : attributes) {
718 // Does the category exist?
720 if (a.getCategory().equals(attribute.getCategory())) {
722 // Yes - add in the new attribute value
729 if (added == false) {
731 // New category - create it and add it in
733 StdMutableRequestAttributes a = new StdMutableRequestAttributes();
734 a.setCategory(newAttribute.getCategory());
738 } catch (DataTypeException e) {
745 // Now form our final request
747 StdMutableRequest newRequest = new StdMutableRequest();
748 newRequest.setCombinedDecision(request.getCombinedDecision());
749 newRequest.setRequestDefaults(request.getRequestDefaults());
750 newRequest.setReturnPolicyIdList(request.getReturnPolicyIdList());
751 newRequest.setStatus(request.getStatus());
752 for (StdMutableRequestAttributes a : attributes) {
759 * This makes an HTTP POST call to a running PDP RESTful servlet to get a decision.
764 protected Response callRESTfulPDP(InputStream is) {
765 Response response = null;
766 HttpURLConnection connection = null;
770 // Open up the connection
772 connection = (HttpURLConnection) this.restURL.openConnection();
773 connection.setRequestProperty("Content-Type", "application/json");
775 // Setup our method and headers
777 connection.setRequestMethod("POST");
778 connection.setUseCaches(false);
780 // Adding this in. It seems the HttpUrlConnection class does NOT
781 // properly forward our headers for POST re-direction. It does so
782 // for a GET re-direction.
784 // So we need to handle this ourselves.
786 connection.setInstanceFollowRedirects(false);
787 connection.setDoOutput(true);
788 connection.setDoInput(true);
792 try (OutputStream os = connection.getOutputStream()) {
793 IOUtils.copy(is, os);
798 connection.connect();
799 if (connection.getResponseCode() == 200) {
803 ContentType contentType = null;
805 contentType = ContentType.parse(connection.getContentType());
807 if (contentType.getMimeType().equalsIgnoreCase(ContentType.APPLICATION_JSON.getMimeType())) {
808 response = JSONResponse.load(connection.getInputStream());
809 } else if (contentType.getMimeType().equalsIgnoreCase(ContentType.APPLICATION_XML.getMimeType()) ||
810 contentType.getMimeType().equalsIgnoreCase("application/xacml+xml") ) {
811 response = DOMResponse.load(connection.getInputStream());
813 logger.error("unknown content-type: " + contentType);
816 } catch (Exception e) {
817 String message = "Parsing Content-Type: " + connection.getContentType() + ", error=" + e.getMessage();
818 logger.error(message, e);
822 logger.error(connection.getResponseCode() + " " + connection.getResponseMessage());
824 } catch (Exception e) {
832 * This processes a response. Saves the response out to disk. If there is a corresponding response file for the request located
833 * in the "responses" sub-directory, then this method will compare that response file with what the engine returned to see if it
843 protected void processResponse(Path requestFile, Request request, Response response, String group, int count) throws Exception {
845 // Construct the output filename
847 Path responseFile = null;
848 Path resultFile = null;
849 int num = requestFile.getNameCount();
851 logger.error("Too few dir's in request filename.");
852 throw new Exception("Too few dir's in request filename. Format should be Request.[0-9]+.{Permit|Deny|NA|Indeterminate}.{json|xml}");
854 String filename = requestFile.getFileName().toString();
855 if (group.equals("Generate")) {
857 // Using count variable, construct a filename
859 // i.e. Response.03.Generate.{count}.json
861 filename = "Response" + filename.substring(filename.indexOf('.'), filename.lastIndexOf('.')) + String.format("%03d", count) + filename.substring(filename.lastIndexOf('.'));
864 // Construct filename
866 filename = "Response" + filename.substring(filename.indexOf('.'));
869 // Determine equivalent response file path
871 responseFile = Paths.get(requestFile.subpath(0, num - 2).toString(), "responses");
872 if (Files.notExists(responseFile)) {
876 logger.warn(responseFile.toString() + " does NOT exist, creating...");
878 Files.createDirectories(responseFile);
879 } catch (IOException e) {
881 throw new Exception("Cannot proceed without an output directory.");
884 responseFile = Paths.get(responseFile.toString(), filename);
886 // Determine path to write result file
888 if (this.output != null) {
890 // User specified an output path
892 resultFile = this.output;
897 resultFile = Paths.get(requestFile.subpath(0, num - 2).toString(), "results");
900 // Check if the path exists
902 if (Files.notExists(resultFile)) {
906 logger.warn(resultFile.toString() + " does NOT exist, creating...");
908 Files.createDirectories(resultFile);
909 } catch (IOException e) {
911 throw new Exception("Cannot proceed without an output directory.");
915 // Add the filename to the path
917 resultFile = Paths.get(resultFile.toString(), filename);
919 // Check if there is an equivalent response in the response
920 // directory. If so, compare our response result with that one.
922 boolean succeeded = true;
923 if (responseFile != null && Files.exists(responseFile)) {
927 Response expectedResponse = null;
928 if (TestBase.isJSON(responseFile)) {
929 expectedResponse = JSONResponse.load(responseFile);
930 } else if (TestBase.isXML(responseFile)) {
931 expectedResponse = DOMResponse.load(responseFile);
933 if (expectedResponse != null) {
937 if (response == null) {
938 logger.error("NULL response returned.");
939 this.responseNotMatches++;
942 if (response.equals(expectedResponse)) {
943 logger.info("Response matches expected response.");
944 this.responseMatches++;
946 logger.error("Response does not match expected response.");
947 logger.error("Expected: ");
948 logger.error(expectedResponse.toString());
949 this.responseNotMatches++;
956 // Write the response to the result file
958 logger.info("Request: " + requestFile.getFileName() + " response is: " + (response == null ? "null" : response.toString()));
959 if (resultFile != null && response != null) {
960 if (TestBase.isJSON(resultFile)) {
961 Files.write(resultFile, JSONResponse.toString(response, true).getBytes());
962 } else if (TestBase.isXML(resultFile)) {
963 Files.write(resultFile, DOMResponse.toString(response, true).getBytes());
969 if (group.equals("Permit")) {
970 this.expectedPermits++;
971 } else if (group.equals("Deny")) {
972 this.expectedDenies++;
973 } else if (group.equals("NA")) {
974 this.expectedNotApplicables++;
975 } else if (group.equals("Indeterminate")) {
976 this.expectedIndeterminates++;
978 if (response != null) {
979 for (Result result : response.getResults()) {
980 Decision decision = result.getDecision();
981 if (group.equals("Generate")) {
982 if (decision.equals(Decision.PERMIT)) {
983 this.generatedpermits++;
984 } else if (decision.equals(Decision.DENY)) {
985 this.generateddenies++;
986 } else if (decision.equals(Decision.NOTAPPLICABLE)) {
987 this.generatednotapplicables++;
988 } else if (decision.equals(Decision.INDETERMINATE)) {
989 this.generatedindeterminates++;
993 if (decision.equals(Decision.PERMIT)) {
995 if (group.equals("Permit") == false) {
997 logger.error("Expected " + group + " got " + decision);
999 } else if (decision.equals(Decision.DENY)) {
1001 if (group.equals("Deny") == false) {
1003 logger.error("Expected " + group + " got " + decision);
1005 } else if (decision.equals(Decision.NOTAPPLICABLE)) {
1006 this.notapplicables++;
1007 if (group.equals("NA") == false) {
1009 logger.error("Expected " + group + " got " + decision);
1011 } else if (decision.equals(Decision.INDETERMINATE)) {
1012 this.indeterminates++;
1013 if (group.equals("Indeterminate") == false) {
1015 logger.error("Expected " + group + " got " + decision);
1021 logger.info("REQUEST SUCCEEDED");
1023 logger.info("REQUEST FAILED");
1027 protected void dumpStats() {
1028 StringBuilder dump = new StringBuilder();
1029 dump.append(System.lineSeparator());
1030 dump.append("Permits: " + this.permits + " Expected: " + this.expectedPermits);
1031 dump.append(System.lineSeparator());
1032 dump.append("Denies: " + this.denies + " Expected: " + this.expectedDenies);
1033 dump.append(System.lineSeparator());
1034 dump.append("NA: " + this.notapplicables + " Expected: " + this.expectedNotApplicables);
1035 dump.append(System.lineSeparator());
1036 dump.append("Indeterminates: " + this.indeterminates + " Expected: " + this.expectedIndeterminates);
1037 dump.append(System.lineSeparator());
1038 dump.append("Generated Permits: " + this.generatedpermits);
1039 dump.append(System.lineSeparator());
1040 dump.append("Generated Denies: " + this.generateddenies);
1041 dump.append(System.lineSeparator());
1042 dump.append("Generated NA: " + this.generatednotapplicables);
1043 dump.append(System.lineSeparator());
1044 dump.append("Generated Indeterminates: " + this.generatedindeterminates);
1045 dump.append(System.lineSeparator());
1046 dump.append("Responses Matched: " + this.responseMatches);
1047 dump.append(System.lineSeparator());
1048 dump.append("Responses NOT Matched: " + this.responseNotMatches);
1050 if (this.permits != this.expectedPermits ||
1051 this.denies != this.expectedDenies ||
1052 this.notapplicables != this.expectedNotApplicables ||
1053 this.indeterminates != this.expectedIndeterminates ||
1054 this.responseNotMatches > 0) {
1055 logger.error(dump.toString());
1057 logger.info(dump.toString());
1061 protected void resetStats() {
1064 this.notapplicables = 0;
1065 this.indeterminates = 0;
1066 this.generatedpermits = 0;
1067 this.generateddenies = 0;
1068 this.generatednotapplicables = 0;
1069 this.generatedindeterminates = 0;
1070 this.responseMatches = 0;
1071 this.responseNotMatches = 0;
1074 public static void main(String[] args) {
1076 new TestBase(args).run();
1077 } catch (ParseException | IOException | FactoryException e) {
1079 } catch (HelpException e) {