/* * @(#)BasicTest.java * * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistribution of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Sun Microsystems, Inc. or the names of contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that this software is not designed or intended for use in * the design, construction, operation or maintenance of any nuclear facility. */ package com.sun.xacml.test; import java.io.FileInputStream; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import com.sun.xacml.PDP; import com.sun.xacml.ctx.RequestCtx; import com.sun.xacml.ctx.ResponseCtx; /** * A simple implementation of a single conformance test case. * * @author Seth Proctor */ public class BasicTest implements Test { // the PDP and module that manage this test's policies private PDP pdp; private TestPolicyFinderModule module; // the policies and references used by this test private Set<String> policies; private Map<String, String> policyRefs; private Map<String, String> policySetRefs; // meta-data associated with this test private String name; private boolean errorExpected; private boolean experimental; /** * Constructor that accepts all values associatd with a test. * * @param pdp * the pdp that manages this test's evaluations * @param module * the module that manages this test's policies * @param policies * the files containing the policies used by this test, or null if we only use the * default policy for this test * @param policyRefs * the policy references used by this test * @param policySetRefs * the policy set references used by this test * @param name * the name of this test * @param errorExpected * true if en error is expected from a normal run * @param experimental * true if this is an experimental test */ public BasicTest(PDP pdp, TestPolicyFinderModule module, Set<String> policies, Map<String, String> policyRefs, Map<String, String> policySetRefs, String name, boolean errorExpected, boolean experimental) { this.pdp = pdp; this.module = module; this.policies = policies; this.policyRefs = policyRefs; this.policySetRefs = policySetRefs; this.name = name; this.errorExpected = errorExpected; this.experimental = experimental; } /** * Creates an instance of a test from its XML representation. * * @param root * the root of the XML-encoded data for this test * @param pdp * the <code>PDP</code> used by this test * @param module * the module used for this test's policies */ public static BasicTest getInstance(Node root, PDP pdp, TestPolicyFinderModule module) { NamedNodeMap map = root.getAttributes(); // the name is required... String name = map.getNamedItem("name").getNodeValue(); // ...but the other two aren't boolean errorExpected = isAttrTrue(map, "errorExpected"); boolean experimental = isAttrTrue(map, "experimental"); // see if there's any content Set<String> policies = null; Map<String, String> policyRefs = null; Map<String, String> policySetRefs = null; if (root.hasChildNodes()) { NodeList children = root.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { Node child = children.item(i); String childName = child.getNodeName(); if (childName.equals("policy")) { if (policies == null) policies = new HashSet<String>(); policies.add(child.getFirstChild().getNodeValue()); } else if (childName.equals("policyReference")) { if (policyRefs == null) policyRefs = new HashMap<String, String>(); policyRefs.put(child.getAttributes().getNamedItem("ref").getNodeValue(), child .getFirstChild().getNodeValue()); } else if (childName.equals("policySetReference")) { if (policySetRefs == null) policySetRefs = new HashMap<String, String>(); policySetRefs.put(child.getAttributes().getNamedItem("ref").getNodeValue(), child.getFirstChild().getNodeValue()); } } } return new BasicTest(pdp, module, policies, policyRefs, policySetRefs, name, errorExpected, experimental); } /** * Private helper that reads a attribute to see if it's set, and if so if its value is "true". */ private static boolean isAttrTrue(NamedNodeMap map, String attrName) { Node attrNode = map.getNamedItem(attrName); if (attrNode == null) return false; return attrNode.getNodeValue().equals("true"); } public String getName() { return name; } public boolean isErrorExpected() { return errorExpected; } public boolean isExperimental() { return experimental; } public int run(String testPrefix) { System.out.print("test " + name + ": "); int errorCount = 0; boolean failurePointReached = false; // FIXME: we sould get more specific with the exceptions, so we can // make sure that an error happened _for the right reason_ try { // load the request for this test RequestCtx request = RequestCtx.getInstance(new FileInputStream(testPrefix + name + "Request.xml")); // re-set the module to use this test's policies if (policies == null) { module.setPolicies(testPrefix + name + "Policy.xml"); } else { Iterator<String> it = policies.iterator(); Set<String> set = new HashSet<String>(); while (it.hasNext()) set.add(testPrefix + it.next()); module.setPolicies(set); } // re-set any references we're using module.setPolicyRefs(policyRefs, testPrefix); module.setPolicySetRefs(policySetRefs, testPrefix); // actually do the evaluation ResponseCtx response = pdp.evaluate(request); // if we're supposed to fail, we should have done so by now if (errorExpected) { System.out.println("failed"); errorCount++; } else { failurePointReached = true; // load the reponse that we expectd to get ResponseCtx expectedResponse = ResponseCtx.getInstance(new FileInputStream( testPrefix + name + "Response.xml")); // see if the actual result matches the expected result boolean equiv = TestUtil.areEquivalent(response, expectedResponse); if (equiv) { System.out.println("passed"); } else { System.out.println("failed:"); response.encode(System.out); errorCount++; } } } catch (Exception e) { // any errors happen as exceptions, and may be successes if we're // supposed to fail and we haven't reached the failure point yet if (!failurePointReached) { if (errorExpected) { System.out.println("passed"); } else { System.out.println("EXCEPTION: " + e.getMessage()); errorCount++; } } else { System.out.println("UNEXPECTED EXCEPTION: " + e.getMessage()); errorCount++; } } // return the number of errors that occured return errorCount; } }