blob: f3e77dd2e8e70178679620746a43d7b0b311d6c6 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
/*
* AT&T - PROPRIETARY
* THIS FILE CONTAINS PROPRIETARY INFORMATION OF
* AT&T AND IS NOT TO BE DISCLOSED OR USED EXCEPT IN
* ACCORDANCE WITH APPLICABLE AGREEMENTS.
*
* Copyright (c) 2013 AT&T Knowledge Ventures
* Unpublished and Not for Publication
* All Rights Reserved
*/
package org.apache.openaz.xacml.pdp.std.json;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.apache.openaz.xacml.api.Advice;
import org.apache.openaz.xacml.api.Attribute;
import org.apache.openaz.xacml.api.AttributeCategory;
import org.apache.openaz.xacml.api.IdReference;
import org.apache.openaz.xacml.api.Obligation;
import org.apache.openaz.xacml.api.Response;
import org.apache.openaz.xacml.api.Result;
import org.apache.openaz.xacml.std.dom.DOMResponse;
import org.apache.openaz.xacml.std.json.JSONResponse;
import org.apache.openaz.xacml.util.ListUtil;
import org.junit.Test;
/**
* Test JSON Response convert to object - Conformance tests TO RUN - use jUnit In Eclipse select this file or
* the enclosing directory, right-click and select Run As/JUnit Test Note: some of the validation tests
* comparing the XML-derived Results to the JSON-derived Results are high-level comparisons of Collections.
* When this class was first created that was sufficient to pass all Conformance tests. However if this sees a
* failure in a Conformance test, those validations may need to be upgraded to look at the individual data
* elements to see what is wrong.
*/
public class ResponseConformanceTest {
// where to find the conformance test XML files
private final String CONFORMANCE_DIRECTORY_PATH = "testsets/conformance/xacml3.0-ct-v.0.4";
// The request object output from each test conversion from JSON string
Response response;
// test just one of each top-level element.
// For simple elements also test for incorrect type
@Test
public void testConformanceResponses() {
List<File> filesInDirectory = null;
File conformanceDirectory = null;
File currentFile = null;
try {
conformanceDirectory = new File(CONFORMANCE_DIRECTORY_PATH);
filesInDirectory = getRequestsInDirectory(conformanceDirectory);
} catch (Exception e) {
fail("Unable to set up Conformance tests for dir '" + conformanceDirectory.getAbsolutePath()
+ "' e=" + e);
}
// run through each XML file
// - load the file from XML into an internal Response object
// - generate the JSON representation of that Response object
// - load that JSON representation into a new Response object
// - compare the 2 Request objects
Response xmlResponse = null;
Response jsonResponse = null;
try {
for (File f : filesInDirectory) {
currentFile = f;
// // This is a simple way to select just one file for debugging - comment out when not being
// used
// if ( ! f.getName().equals("IIIA030Response.xml") && !
// f.getName().equals("IIIA330Response.xml")) { continue; }
// during debugging it is helpful to know what file it is starting to work on
// System.out.println("starting file="+currentFile.getName());
try {
// load XML into a Response object
xmlResponse = DOMResponse.load(f);
} catch (Exception e) {
// if XML does not load, just note it and continue with next file
System.out.println("XML file did not load: '" + f.getName() + " e=" + e);
continue;
}
// some tests have JSON response files to load, most do not
String jsonFileName = f.getName().replace(".xml", ".json");
File jsonFile = new File(conformanceDirectory, jsonFileName);
if (jsonFile.exists()) {
// System.out.println("found file "+jsonFile.getName());
// json version exists in file, so load it
jsonResponse = JSONResponse.load(jsonFile);
} else {
// json does not exist in file, so create it from the XML response using a String
// intermediate version
String jsonResponseString = JSONResponse.toString(xmlResponse, false);
// System.out.println(jsonResponseString);
// System.out.println(JSONResponse.toString(xmlResponse, true));
jsonResponse = JSONResponse.load(jsonResponseString);
}
// System.out.println(JSONResponse.toString(xmlResponse, true));
// compare the two Response objects
// compare results
assertEquals(xmlResponse.getResults().size(), jsonResponse.getResults().size());
if (xmlResponse.getResults().size() == 0) {
fail("neither XML nor JSON response have any Results");
}
// Results are an un-ordered Collection.
// There is no identifying information that is unique to a specific Result.
// If there are more than one we cannot be sure which one corresponds with which.
// The best we can do is say that one or more in the first list do not match any in the second
// list
if (xmlResponse.getResults().size() > 1) {
for (Result xmlResult : xmlResponse.getResults()) {
boolean found = false;
for (Result jsonResult : jsonResponse.getResults()) {
if (xmlResult.equals(jsonResult)) {
found = true;
break;
}
}
if (found) {
continue;
}
// no match found
System.out.println("No match for XML in " + f.getName());
System.out.println("XML =" + xmlResult.toString());
for (Result jsonResult : jsonResponse.getResults()) {
System.out.println("JSON=" + jsonResult.toString());
}
fail("JSON Response has no match for XML Result: " + xmlResult.toString());
}
// we've done the best we can for multiple decisions, so go to next file
continue;
}
// single Result in each
Result xmlResult = xmlResponse.getResults().iterator().next();
Result jsonResult = jsonResponse.getResults().iterator().next();
// The following sections have not given us trouble, so checking is very high-level.
// If we see a problem in one of these elements, the single line will need to be replaced with
// detailed examination of the objects.
assertEquals(f.getName() + " Decision", xmlResult.getDecision(), jsonResult.getDecision());
assertEquals(f.getName() + " Status", xmlResult.getStatus(), jsonResult.getStatus());
// Obligations
if (xmlResult.getObligations() != jsonResult.getObligations()) {
Collection<Obligation> xmlObligations = xmlResult.getObligations();
Collection<Obligation> jsonObligations = jsonResult.getObligations();
// if both are null we do not get here
if (xmlObligations == null || jsonObligations == null) {
fail(f.getName() + " Obligations has null \nXML=" + xmlObligations + "\nJSON="
+ jsonObligations);
}
if (!ListUtil.equalsAllowNulls(xmlObligations, jsonObligations)) {
// collections are not equal, so need to examine further
fail(f.getName() + " Obligation collections not equal\nXML=" + xmlObligations
+ "\nJSON=" + jsonObligations);
}
}
// AssociatedAdvice
if (xmlResult.getAssociatedAdvice() != jsonResult.getAssociatedAdvice()) {
Collection<Advice> xmlAdvice = xmlResult.getAssociatedAdvice();
Collection<Advice> jsonAdvice = jsonResult.getAssociatedAdvice();
// if both are null we do not get here
if (xmlAdvice == null || jsonAdvice == null) {
fail(f.getName() + " Advice has null \nXML=" + xmlAdvice + "\nJSON=" + jsonAdvice);
}
if (!ListUtil.equalsAllowNulls(xmlAdvice, jsonAdvice)) {
// collections are not equal, so need to examine further
fail(f.getName() + " Advice collections not equal\nXML=" + xmlAdvice + "\nJSON="
+ jsonAdvice);
}
}
// check Attributes in more detail
Collection<AttributeCategory> xmlAttributes = xmlResult.getAttributes();
Collection<AttributeCategory> jsonAttributes = jsonResult.getAttributes();
if (xmlAttributes == null && jsonAttributes != null || xmlAttributes != null
&& jsonAttributes == null) {
fail(f.getName() + " XML Attributes=" + xmlAttributes + " but JSON Attributes="
+ jsonAttributes);
}
if (xmlAttributes != null) {
// both are non-null
if (xmlAttributes.size() != jsonAttributes.size()) {
String xmlAttributesString = "XML categorys=";
for (AttributeCategory ac : xmlAttributes) {
xmlAttributesString += " " + ac.getCategory().stringValue();
}
String jsonAttributesString = "JSON categorys=";
for (AttributeCategory ac : jsonAttributes) {
jsonAttributesString += " " + ac.getCategory().stringValue();
}
fail(f.getName() + " XML and JSON have different number of Category elements: "
+ xmlAttributesString + ", " + jsonAttributesString);
}
// Attribute collections are the same size but may be in different orders.
// for each XML category try to find the corresponding JSON category.
// ASSUME that each category only shows up once!!!!
for (AttributeCategory xmlAttributeCategory : xmlAttributes) {
boolean attributeCategoryFound = false;
for (AttributeCategory jsonAttributeCategory : jsonAttributes) {
if (xmlAttributeCategory.equals(jsonAttributeCategory)) {
attributeCategoryFound = true;
break;
}
// not an exact match, but if same CategoryId then need to check individual
// Attribute objects
if (xmlAttributeCategory.getCategory()
.equals(jsonAttributeCategory.getCategory())) {
// same category
if (xmlAttributeCategory.getAttributes().size() != jsonAttributeCategory
.getAttributes().size()) {
System.out.println("XML =" + xmlAttributeCategory.getAttributes());
System.out.println("JSON=" + jsonAttributeCategory.getAttributes());
fail(f.getName() + " Attributes Category '"
+ xmlAttributeCategory.getCategory().stringValue()
+ "' size mismatch; XML="
+ xmlAttributeCategory.getAttributes().size() + ", JSON="
+ jsonAttributeCategory.getAttributes().size());
}
for (Attribute xmlAttr : xmlAttributeCategory.getAttributes()) {
boolean attributeFound = false;
for (Attribute jsonAttr : jsonAttributeCategory.getAttributes()) {
if (xmlAttr.equals(jsonAttr)) {
attributeFound = true;
break;
}
}
if (attributeFound) {
// check next XML attribute
continue;
}
System.out.println("Attribute not found in JSON, Category="
+ xmlAttributeCategory.getCategory());
System.out.println("XML Attribute =" + xmlAttr);
System.out.println("JSON Attributes=" + jsonAttributeCategory.toString());
fail(f.getName() + " Attribute not found in JSON, Category="
+ xmlAttributeCategory.getCategory() + "/nXML Attribute=" + xmlAttr
+ "\nJSON Category Attributes=" + jsonAttributeCategory.toString());
}
}
}
if (attributeCategoryFound) {
continue;
}
fail("XML Category not found in JSON; xml=" + xmlAttributeCategory.toString());
}
}
// PolicyIdentifiers
if (xmlResult.getPolicyIdentifiers() != jsonResult.getPolicyIdentifiers()) {
Collection<IdReference> xmlIdReferences = xmlResult.getPolicyIdentifiers();
Collection<IdReference> jsonIdReferences = jsonResult.getPolicyIdentifiers();
// if both are null we do not get here
if (xmlIdReferences == null || jsonIdReferences == null) {
fail(f.getName() + " PolicyIdentifiers has null \nXML=" + xmlIdReferences + "\nJSON="
+ jsonIdReferences);
}
if (!ListUtil.equalsAllowNulls(xmlIdReferences, jsonIdReferences)) {
// collections are not equal, so need to examine further
fail(f.getName() + " PolicyIdentifiers collections not equal\nXML=" + xmlIdReferences
+ "\nJSON=" + jsonIdReferences);
}
}
// PolicySetIdentifiers
if (xmlResult.getPolicySetIdentifiers() != jsonResult.getPolicySetIdentifiers()) {
Collection<IdReference> xmlIdReferences = xmlResult.getPolicySetIdentifiers();
Collection<IdReference> jsonIdReferences = jsonResult.getPolicySetIdentifiers();
// if both are null we do not get here
if (xmlIdReferences == null || jsonIdReferences == null) {
fail(f.getName() + " PolicySetIdentifiers has null \nXML=" + xmlIdReferences
+ "\nJSON=" + jsonIdReferences);
}
if (!ListUtil.equalsAllowNulls(xmlIdReferences, jsonIdReferences)) {
// collections are not equal, so need to examine further
fail(f.getName() + " PolicySetIdentifiers collections not equal\nXML="
+ xmlIdReferences + "\nJSON=" + jsonIdReferences);
}
}
}
} catch (Exception e) {
fail("Failed test with '" + currentFile.getName() + "', e=" + e);
}
}
//
// HELPER to get list of all Request files in the given directory
//
private List<File> getRequestsInDirectory(File directory) {
List<File> fileList = new ArrayList<File>();
File[] fileArray = directory.listFiles();
for (File f : fileArray) {
if (f.isDirectory()) {
List<File> subDirList = getRequestsInDirectory(f);
fileList.addAll(subDirList);
}
if (f.getName().endsWith("Response.xml")) {
fileList.add(f);
}
}
return fileList;
}
}
/*
* This is a place to copy the really long output from test rigs that need to be manually edited for
* readability....
* {"Response":[{"Status":{"StatusCode":{"Value":"urn:oasis:names:tc:xacml:1.0:status:ok"}},"Obligations"
* :[{"Id":"urn:oasis:names:tc:xacml:2.0:conformance-test:IIIA030:obligation-1","AttributeAssignment":[
* {"Value":"assignment1","DataType":"string","AttributeId":
* "urn:oasis:names:tc:xacml:2.0:conformance-test:IIIA030:assignment1"},
* {"Value":{"Namespaces":[{"Namespace":"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17"
* },{"Namespace":"http://www.w3.org/2001/XMLSchema-instance","Prefix":"xsi"}],
* "XPathCategory":"urn:oasis:names:tc:xacml:3.0:attribute-category:resource",
* "XPath":"//md:records/md:record"}, "DataType":"xpathExpression",
* "AttributeId":"urn:oasis:names:tc:xacml:2.0:conformance-test:IIIA030:assignment2"
* }]}],"Decision":"Permit"}]}
*/