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.openecomp.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.commons.logging.Log;
51 import org.apache.commons.logging.LogFactory;
52 import org.apache.http.entity.ContentType;
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;
83 import org.openecomp.policy.common.logging.flexlogger.FlexLogger;
84 import org.openecomp.policy.common.logging.flexlogger.Logger;
87 * This is a base class for setting up a test environment. Using properties files, it contains the
88 * necessary information for
89 * 1. defining and providing attributes
90 * 2. defining and instantiating the PDP engine
91 * 3. creating PEP requests and calling the PDP engine
95 public class TestBase extends SimpleFileVisitor<Path> {
96 private static final Logger logger = FlexLogger.getLogger(TestBase.class);
98 public class HelpException extends Exception {
99 private static final long serialVersionUID = 1L;
104 * This private class holds information for properties defined for attribute
105 * generation. The user can configure the properties file such that attributes
106 * can be automatically generated and added into each request.
113 BufferedReader reader;
114 List<StdMutableAttribute> attributes = new ArrayList<StdMutableAttribute>();
116 public Generator(Path path) {
121 * read - reads in the next line of data
123 * @return String - a line from the csv containing attribute data
125 public String read() {
129 is = Files.newInputStream(file);
130 } catch (IOException e) {
135 if (reader == null) {
136 reader = new BufferedReader(new InputStreamReader(this.is));
139 str = reader.readLine();
142 // No more strings, close up
146 if (logger.isDebugEnabled()) {
149 } catch (IOException e) {
155 public void close() {
156 if (this.reader != null) {
159 } catch (IOException idontcare) {
169 public static final String PROP_GENERATOR = "xacml.attribute.generator";
171 public static final String OPTION_HELP = "help";
172 public static final String OPTION_TESTDIR = "dir";
173 public static final String OPTION_TESTREST = "rest";
174 public static final String OPTION_TESTURL = "url";
175 public static final String OPTION_TESTOUTPUT = "output";
176 public static final String OPTION_LOOP = "loop";
177 public static final String OPTION_TESTNUMBERS = "testNumbers";
179 public static final String DEFAULT_RESTURL = "https://localhost:8080/pdp/"; // Modified for test purpose. Port no. 8443 to 8080
181 public static Options options = new Options();
183 options.addOption(new Option(OPTION_HELP, false, "Prints help."));
184 options.addOption(new Option(OPTION_TESTDIR, true, "Directory path where all the test properties and data are located."));
185 options.addOption(new Option(OPTION_TESTREST, false, "Test against RESTful PDP."));
186 options.addOption(new Option(OPTION_TESTURL, true, "URL to the RESTful PDP. Default is " + DEFAULT_RESTURL));
187 options.addOption(new Option(OPTION_TESTOUTPUT, true, "Specify a different location for dumping responses."));
188 options.addOption(new Option(OPTION_LOOP, true, "Number of times to loop through the tests. Default is 1. A value of -1 runs indefinitely."));
189 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."));
192 protected String directory = null;
193 protected Path output = null;
194 protected boolean isREST;
195 protected URL restURL = null;
196 protected int loop = 1;
197 protected PDPEngine engine = null;
198 protected List<Generator> generators = new ArrayList<Generator>();
199 protected static DataTypeFactory dataTypeFactory = null;
201 private long permits = 0;
202 private long denies = 0;
203 private long notapplicables = 0;
204 private long indeterminates = 0;
206 private long expectedPermits = 0;
207 private long expectedDenies = 0;
208 private long expectedNotApplicables = 0;
209 private long expectedIndeterminates = 0;
211 private long generatedpermits = 0;
212 private long generateddenies = 0;
213 private long generatednotapplicables = 0;
214 private long generatedindeterminates = 0;
216 private long responseMatches = 0;
217 private long responseNotMatches = 0;
219 private String[] testNumbersArray = null;
221 protected final Pattern pattern = Pattern.compile("Request[.]\\d+[.](Permit|Deny|NA|Indeterminate|Generate|Unknown)\\.(json|xml)");
223 public static boolean isJSON(Path file) {
224 return file.toString().endsWith(".json");
227 public static boolean isXML(Path file) {
228 return file.toString().endsWith(".xml");
231 public TestBase(String[] args) throws ParseException, MalformedURLException, HelpException {
233 // Finish Initialization
235 this.restURL = new URL(DEFAULT_RESTURL);
239 this.parseCommands(args);
243 * Parse in the command line arguments that the following parameters:
245 * @param args - command line arguments
246 * @throws ParseException
247 * @throws MalformedURLException
248 * @throws HelpException
250 protected void parseCommands(String[] args) throws ParseException, MalformedURLException, HelpException {
252 // Parse the command line options
255 cl = new GnuParser().parse(options, args);
257 // Check for what we have
259 if (cl.hasOption(OPTION_HELP)) {
260 new HelpFormatter().printHelp("Usage: -dir testdirectory OPTIONS",
262 throw new HelpException();
264 if (cl.hasOption(OPTION_TESTDIR)) {
265 this.directory = cl.getOptionValue(OPTION_TESTDIR);
267 throw new IllegalArgumentException("You must specify a test directory. -dir path/to/some/where");
269 if (cl.hasOption(OPTION_TESTREST)) {
274 if (cl.hasOption(OPTION_TESTURL)) {
275 this.restURL = new URL(cl.getOptionValue(OPTION_TESTURL));
277 if (cl.hasOption(OPTION_TESTOUTPUT)) {
278 this.output = Paths.get(cl.getOptionValue(OPTION_TESTOUTPUT));
280 this.output = Paths.get(this.directory, "results");
282 if (cl.hasOption(OPTION_LOOP)) {
283 this.loop = Integer.parseInt(cl.getOptionValue(OPTION_LOOP));
285 if (cl.hasOption(OPTION_TESTNUMBERS)) {
286 String testNumberString = cl.getOptionValue(OPTION_TESTNUMBERS);
287 testNumbersArray = testNumberString.split(",");
289 // reset strings to include dots so they exactly match pattern in file name
291 for (int i = 0; i < testNumbersArray.length; i++) {
292 testNumbersArray[i] = "." + testNumbersArray[i] + ".";
298 * Using the command line options that were parsed, configures our test instance.
300 * @throws FactoryException
302 protected void configure() throws FactoryException {
304 // Setup the xacml.properties file
306 if (this.directory == null) {
307 throw new IllegalArgumentException("Must supply a path to a test directory.");
309 Path pathDir = Paths.get(this.directory, "xacml.properties");
310 if (Files.notExists(pathDir)) {
311 throw new IllegalArgumentException(pathDir.toString() + " does not exist.");
314 // Set it as the System variable so the XACML factories know where the properties are
317 System.setProperty(XACMLProperties.XACML_PROPERTIES_NAME, pathDir.toString());
319 // Now we can create the data type factory
321 dataTypeFactory = DataTypeFactory.newInstance();
323 // Load in what generators we are to create
325 String generators = XACMLProperties.getProperty(PROP_GENERATOR);
326 if (generators != null) {
328 // Parse the generators
330 for (String generator : Splitter.on(',').trimResults().omitEmptyStrings().split(generators)) {
331 this.configureGenerator(generator);
335 // If we are embedded, create our engine
337 if (this.isREST == false) {
338 PDPEngineFactory factory = PDPEngineFactory.newInstance();
339 this.engine = factory.newEngine();
342 // Remove all the responses from the results directory
344 this.removeResults();
348 * Removes all the Response* files from the results directory.
351 public void removeResults() {
354 // Determine where the results are supposed to be written to
357 if (this.output != null) {
358 resultsPath = this.output;
360 resultsPath = Paths.get(this.directory.toString(), "results");
365 Files.walkFileTree(resultsPath, new SimpleFileVisitor<Path>() {
368 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
369 if (file.getFileName().toString().startsWith("Response")) {
372 return super.visitFile(file, attrs);
375 } catch (IOException e) {
376 logger.error("Failed to removeRequests from " + this.directory + " " + e);
381 * Configure's a specific generator instance from the properties file.
385 protected void configureGenerator(String generator) {
386 String prefix = PROP_GENERATOR + "." + generator;
387 String file = XACMLProperties.getProperty(prefix + ".file");
389 // Create a generator object
391 Generator gen = new Generator(Paths.get(this.directory, file));
392 this.generators.add(gen);
396 String attributes = XACMLProperties.getProperty(prefix + ".attributes");
397 for (String attribute : Splitter.on(',').trimResults().omitEmptyStrings().split(attributes)) {
398 String attributePrefix = prefix + ".attributes." + attribute;
400 // Create an attribute value. It is simply a placeholder for the field within
401 // the CSV that contains the actual attribute value. It mainly holds the data type
403 Identifier datatype = new IdentifierImpl(XACMLProperties.getProperty(attributePrefix + ".datatype"));
404 Integer field = Integer.parseInt(XACMLProperties.getProperty(attributePrefix + ".field"));
405 StdAttributeValue<?> value = new StdAttributeValue<>(datatype, field);
407 // Get the rest of the attribute properties
409 Identifier category = new IdentifierImpl(XACMLProperties.getProperty(attributePrefix + ".category"));
410 Identifier id = new IdentifierImpl(XACMLProperties.getProperty(attributePrefix + ".id"));
411 String issuer = XACMLProperties.getProperty(attributePrefix + ".issuer");
412 boolean include = Boolean.parseBoolean(XACMLProperties.getProperty(attributePrefix + ".include", "false"));
414 // Now we have a skeleton attribute
416 gen.attributes.add(new StdMutableAttribute(category, id, value, issuer, include));
421 * This runs() the test instance. It first configure's itself and then walks the
422 * requests directory issue each request to the PDP engine.
424 * @throws IOException
425 * @throws FactoryException
428 public void run() throws IOException, FactoryException {
430 // Configure ourselves
438 long lTimeStart = System.currentTimeMillis();
439 logger.info("Run number: " + runs);
441 // Walk the request directory
443 Files.walkFileTree(Paths.get(this.directory.toString(), "requests"), this);
444 long lTimeEnd = System.currentTimeMillis();
445 logger.info("Run elapsed time: " + (lTimeEnd - lTimeStart) + "ms");
455 } while ((this.loop == -1 ? true : runs <= this.loop));
459 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
461 // Sanity check the file name
463 Matcher matcher = this.pattern.matcher(file.getFileName().toString());
464 if (matcher.matches()) {
466 // if user has limited which files to use, check that here
468 if (testNumbersArray != null) {
469 String fileNameString = file.getFileName().toString();
470 boolean found = false;
471 for (String numberString : testNumbersArray) {
472 if (fileNameString.contains(numberString)) {
477 if (found == false) {
479 // this test is not in the list to be run, so skip it
481 return super.visitFile(file, attrs);
486 // Pull what this request is supposed to be
489 int count = matcher.groupCount();
491 group = matcher.group(count-1);
496 this.sendRequest(file, group);
497 } catch (Exception e) {
502 return super.visitFile(file, attrs);
506 * When a request file is encountered, this method is called send the request to the PDP engine. It will also dump
507 * the response object. If the group equals "Generate", then it will loop and send the request with generated attributes
508 * until that list is empty.
510 * @param file - Request file. Eg. Request-01-Permit.json
511 * @param group - This is the parsed out string of the request file that defines if it is a Permit/Deny/Generate etc.
514 protected void sendRequest(Path file, String group) throws Exception {
515 logger.info(file.toString());
516 int requestCount = 0;
519 // Generate the request
521 Request request = this.generateRequest(file, group);
523 // Was something generated?
525 if (request == null) {
527 // Get out of the loop
529 logger.info("NULL request generated.");
532 logger.info(request);
536 Response response = this.callPDP(request);
538 // Process the response
540 this.processResponse(file, request, response, group, requestCount);
542 // Is this a generated request?
544 if (group.equals("Generate")) {
546 // Yes, increment counter and move
547 // on to the next generated request.
552 // Nope, exit the loop
556 } while (group.equals("Generate"));
560 * Sends the request object to the PDP engine. Either the embedded engine or the RESTful engine.
562 * @param request - XACML request object
563 * @return Response - returns the XACML response object
565 protected Response callPDP(Request request) {
567 // Send it to the PDP
569 Response response = null;
572 String jsonString = JSONRequest.toString(request, false);
576 response = this.callRESTfulPDP(new ByteArrayInputStream(jsonString.getBytes()));
577 } catch (Exception e) {
578 logger.error("Error in sending RESTful request: " + e, e);
582 // Embedded call to PDP
584 long lTimeStart = System.currentTimeMillis();
586 response = this.engine.decide(request);
587 } catch (PDPException e) {
590 long lTimeEnd = System.currentTimeMillis();
591 logger.info("Elapsed Time: " + (lTimeEnd - lTimeStart) + "ms");
597 * Reads the request file into a Request object based on its type.
599 * If the request has "Generate" in its filename, then this function will add
600 * generated attributes into the request.
602 * @param file - Request file. Eg. Request-01-Permit.json
603 * @param group - This is the parsed out string of the request file that defines if it is a Permit/Deny/Generate etc.
605 * @throws JSONStructureException
606 * @throws DOMStructureException
607 * @throws PEPException
609 protected Request generateRequest(Path file, String group) throws JSONStructureException, DOMStructureException, PEPException {
611 // Convert to a XACML Request Object
613 Request request = null;
614 if (TestBase.isJSON(file)) {
615 request = JSONRequest.load(file.toFile());
616 } else if (TestBase.isXML(file)) {
617 request = DOMRequest.load(file.toFile());
619 if (request == null) {
620 throw new PEPException("Invalid Request File: " + file.toString());
623 // Only if this request has "Generate"
624 // Request.XX.Generate.[json|xml]
626 if (group.equals("Generate")) {
628 // Add attributes to it
630 request = this.onNextRequest(request);
639 * Called to add in generated attributes into the request.
644 protected Request onNextRequest(Request request) {
646 // If we have no generators, just return
648 if (this.generators.isEmpty()) {
652 // Copy the request attributes
654 List<StdMutableRequestAttributes> attributes = new ArrayList<StdMutableRequestAttributes>();
655 for (RequestAttributes a : request.getRequestAttributes()) {
656 attributes.add(new StdMutableRequestAttributes(a));
659 // Iterate the generators
661 for (Generator generator : this.generators) {
665 String line = generator.read();
667 // Was something read?
671 // No more rows to read, return null
678 List<String> fields = Lists.newArrayList(Splitter.on(',').trimResults().split(line));
680 // Now work on the attributes
682 for (StdMutableAttribute attribute : generator.attributes) {
684 // Grab the attribute holder, which holds the datatype and field. There should
685 // be only ONE object in the collection.
687 AttributeValue<?> value = attribute.getValues().iterator().next();
688 Integer field = (Integer) value.getValue();
690 // Is the field number valid?
692 if (field >= fields.size()) {
693 logger.error("Not enough fields: " + field + "(" + fields.size() + ")");
697 // Determine what datatype it is
699 DataType<?> dataTypeExtended = dataTypeFactory.getDataType(value.getDataTypeId());
700 if (dataTypeExtended == null) {
701 logger.error("Failed to determine datatype");
705 // Create the attribute value
708 AttributeValue<?> attributeValue = dataTypeExtended.createAttributeValue(fields.get(field));
710 // Create the attribute
712 StdMutableAttribute newAttribute = new StdMutableAttribute(attribute.getCategory(),
713 attribute.getAttributeId(),
715 attribute.getIssuer(),
716 attribute.getIncludeInResults());
717 boolean added = false;
718 for (StdMutableRequestAttributes a : attributes) {
720 // Does the category exist?
722 if (a.getCategory().equals(attribute.getCategory())) {
724 // Yes - add in the new attribute value
731 if (added == false) {
733 // New category - create it and add it in
735 StdMutableRequestAttributes a = new StdMutableRequestAttributes();
736 a.setCategory(newAttribute.getCategory());
740 } catch (DataTypeException e) {
747 // Now form our final request
749 StdMutableRequest newRequest = new StdMutableRequest();
750 newRequest.setCombinedDecision(request.getCombinedDecision());
751 newRequest.setRequestDefaults(request.getRequestDefaults());
752 newRequest.setReturnPolicyIdList(request.getReturnPolicyIdList());
753 newRequest.setStatus(request.getStatus());
754 for (StdMutableRequestAttributes a : attributes) {
761 * This makes an HTTP POST call to a running PDP RESTful servlet to get a decision.
766 protected Response callRESTfulPDP(InputStream is) {
767 Response response = null;
768 HttpURLConnection connection = null;
772 // Open up the connection
774 connection = (HttpURLConnection) this.restURL.openConnection();
775 connection.setRequestProperty("Content-Type", "application/json");
777 // Setup our method and headers
779 connection.setRequestMethod("POST");
780 connection.setUseCaches(false);
782 // Adding this in. It seems the HttpUrlConnection class does NOT
783 // properly forward our headers for POST re-direction. It does so
784 // for a GET re-direction.
786 // So we need to handle this ourselves.
788 connection.setInstanceFollowRedirects(false);
789 connection.setDoOutput(true);
790 connection.setDoInput(true);
794 try (OutputStream os = connection.getOutputStream()) {
795 IOUtils.copy(is, os);
800 connection.connect();
801 if (connection.getResponseCode() == 200) {
805 ContentType contentType = null;
807 contentType = ContentType.parse(connection.getContentType());
809 if (contentType.getMimeType().equalsIgnoreCase(ContentType.APPLICATION_JSON.getMimeType())) {
810 response = JSONResponse.load(connection.getInputStream());
811 } else if (contentType.getMimeType().equalsIgnoreCase(ContentType.APPLICATION_XML.getMimeType()) ||
812 contentType.getMimeType().equalsIgnoreCase("application/xacml+xml") ) {
813 response = DOMResponse.load(connection.getInputStream());
815 logger.error("unknown content-type: " + contentType);
818 } catch (Exception e) {
819 String message = "Parsing Content-Type: " + connection.getContentType() + ", error=" + e.getMessage();
820 logger.error(message, e);
824 logger.error(connection.getResponseCode() + " " + connection.getResponseMessage());
826 } catch (Exception e) {
834 * This processes a response. Saves the response out to disk. If there is a corresponding response file for the request located
835 * in the "responses" sub-directory, then this method will compare that response file with what the engine returned to see if it
845 protected void processResponse(Path requestFile, Request request, Response response, String group, int count) throws Exception {
847 // Construct the output filename
849 Path responseFile = null;
850 Path resultFile = null;
851 int num = requestFile.getNameCount();
853 logger.error("Too few dir's in request filename.");
854 throw new Exception("Too few dir's in request filename. Format should be Request.[0-9]+.{Permit|Deny|NA|Indeterminate}.{json|xml}");
856 String filename = requestFile.getFileName().toString();
857 if (group.equals("Generate")) {
859 // Using count variable, construct a filename
861 // i.e. Response.03.Generate.{count}.json
863 filename = "Response" + filename.substring(filename.indexOf('.'), filename.lastIndexOf('.')) + String.format("%03d", count) + filename.substring(filename.lastIndexOf('.'));
866 // Construct filename
868 filename = "Response" + filename.substring(filename.indexOf('.'));
871 // Determine equivalent response file path
873 responseFile = Paths.get(requestFile.subpath(0, num - 2).toString(), "responses");
874 if (Files.notExists(responseFile)) {
878 logger.warn(responseFile.toString() + " does NOT exist, creating...");
880 Files.createDirectories(responseFile);
881 } catch (IOException e) {
883 throw new Exception("Cannot proceed without an output directory.");
886 responseFile = Paths.get(responseFile.toString(), filename);
888 // Determine path to write result file
890 if (this.output != null) {
892 // User specified an output path
894 resultFile = this.output;
899 resultFile = Paths.get(requestFile.subpath(0, num - 2).toString(), "results");
902 // Check if the path exists
904 if (Files.notExists(resultFile)) {
908 logger.warn(resultFile.toString() + " does NOT exist, creating...");
910 Files.createDirectories(resultFile);
911 } catch (IOException e) {
913 throw new Exception("Cannot proceed without an output directory.");
917 // Add the filename to the path
919 resultFile = Paths.get(resultFile.toString(), filename);
921 // Check if there is an equivalent response in the response
922 // directory. If so, compare our response result with that one.
924 boolean succeeded = true;
925 if (responseFile != null && Files.exists(responseFile)) {
929 Response expectedResponse = null;
930 if (TestBase.isJSON(responseFile)) {
931 expectedResponse = JSONResponse.load(responseFile);
932 } else if (TestBase.isXML(responseFile)) {
933 expectedResponse = DOMResponse.load(responseFile);
935 if (expectedResponse != null) {
939 if (response == null) {
940 logger.error("NULL response returned.");
941 this.responseNotMatches++;
944 if (response.equals(expectedResponse)) {
945 logger.info("Response matches expected response.");
946 this.responseMatches++;
948 logger.error("Response does not match expected response.");
949 logger.error("Expected: ");
950 logger.error(expectedResponse.toString());
951 this.responseNotMatches++;
958 // Write the response to the result file
960 logger.info("Request: " + requestFile.getFileName() + " response is: " + (response == null ? "null" : response.toString()));
961 if (resultFile != null && response != null) {
962 if (TestBase.isJSON(resultFile)) {
963 Files.write(resultFile, JSONResponse.toString(response, true).getBytes());
964 } else if (TestBase.isXML(resultFile)) {
965 Files.write(resultFile, DOMResponse.toString(response, true).getBytes());
971 if (group.equals("Permit")) {
972 this.expectedPermits++;
973 } else if (group.equals("Deny")) {
974 this.expectedDenies++;
975 } else if (group.equals("NA")) {
976 this.expectedNotApplicables++;
977 } else if (group.equals("Indeterminate")) {
978 this.expectedIndeterminates++;
980 if (response != null) {
981 for (Result result : response.getResults()) {
982 Decision decision = result.getDecision();
983 if (group.equals("Generate")) {
984 if (decision.equals(Decision.PERMIT)) {
985 this.generatedpermits++;
986 } else if (decision.equals(Decision.DENY)) {
987 this.generateddenies++;
988 } else if (decision.equals(Decision.NOTAPPLICABLE)) {
989 this.generatednotapplicables++;
990 } else if (decision.equals(Decision.INDETERMINATE)) {
991 this.generatedindeterminates++;
995 if (decision.equals(Decision.PERMIT)) {
997 if (group.equals("Permit") == false) {
999 logger.error("Expected " + group + " got " + decision);
1001 } else if (decision.equals(Decision.DENY)) {
1003 if (group.equals("Deny") == false) {
1005 logger.error("Expected " + group + " got " + decision);
1007 } else if (decision.equals(Decision.NOTAPPLICABLE)) {
1008 this.notapplicables++;
1009 if (group.equals("NA") == false) {
1011 logger.error("Expected " + group + " got " + decision);
1013 } else if (decision.equals(Decision.INDETERMINATE)) {
1014 this.indeterminates++;
1015 if (group.equals("Indeterminate") == false) {
1017 logger.error("Expected " + group + " got " + decision);
1023 logger.info("REQUEST SUCCEEDED");
1025 logger.info("REQUEST FAILED");
1029 protected void dumpStats() {
1030 StringBuilder dump = new StringBuilder();
1031 dump.append(System.lineSeparator());
1032 dump.append("Permits: " + this.permits + " Expected: " + this.expectedPermits);
1033 dump.append(System.lineSeparator());
1034 dump.append("Denies: " + this.denies + " Expected: " + this.expectedDenies);
1035 dump.append(System.lineSeparator());
1036 dump.append("NA: " + this.notapplicables + " Expected: " + this.expectedNotApplicables);
1037 dump.append(System.lineSeparator());
1038 dump.append("Indeterminates: " + this.indeterminates + " Expected: " + this.expectedIndeterminates);
1039 dump.append(System.lineSeparator());
1040 dump.append("Generated Permits: " + this.generatedpermits);
1041 dump.append(System.lineSeparator());
1042 dump.append("Generated Denies: " + this.generateddenies);
1043 dump.append(System.lineSeparator());
1044 dump.append("Generated NA: " + this.generatednotapplicables);
1045 dump.append(System.lineSeparator());
1046 dump.append("Generated Indeterminates: " + this.generatedindeterminates);
1047 dump.append(System.lineSeparator());
1048 dump.append("Responses Matched: " + this.responseMatches);
1049 dump.append(System.lineSeparator());
1050 dump.append("Responses NOT Matched: " + this.responseNotMatches);
1052 if (this.permits != this.expectedPermits ||
1053 this.denies != this.expectedDenies ||
1054 this.notapplicables != this.expectedNotApplicables ||
1055 this.indeterminates != this.expectedIndeterminates ||
1056 this.responseNotMatches > 0) {
1057 logger.error(dump.toString());
1059 logger.info(dump.toString());
1063 protected void resetStats() {
1066 this.notapplicables = 0;
1067 this.indeterminates = 0;
1068 this.generatedpermits = 0;
1069 this.generateddenies = 0;
1070 this.generatednotapplicables = 0;
1071 this.generatedindeterminates = 0;
1072 this.responseMatches = 0;
1073 this.responseNotMatches = 0;
1076 public static void main(String[] args) {
1078 new TestBase(args).run();
1079 } catch (ParseException | IOException | FactoryException e) {
1081 } catch (HelpException e) {