/*- * ============LICENSE_START======================================================= * ECOMP-TEST * ================================================================================ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed 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. * ============LICENSE_END========================================================= */ package org.openecomp.policy.pdp.test.std.functions; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.math.BigInteger; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import javax.xml.namespace.NamespaceContext; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathFactory; import org.junit.Test; import com.att.research.xacml.api.Request; import com.att.research.xacml.api.XACML3; import com.att.research.xacml.std.IdentifierImpl; import com.att.research.xacml.std.StdRequest; import com.att.research.xacml.std.StdStatus; import com.att.research.xacml.std.datatypes.DataTypes; import com.att.research.xacml.std.datatypes.XPathExpressionWrapper; import com.att.research.xacml.std.dom.DOMRequest; import com.att.research.xacmlatt.pdp.policy.ExpressionResult; import com.att.research.xacmlatt.pdp.policy.FunctionArgument; import com.att.research.xacmlatt.pdp.policy.FunctionArgumentAttributeValue; import com.att.research.xacmlatt.pdp.std.StdEvaluationContext; import com.att.research.xacmlatt.pdp.std.StdFunctions; import com.att.research.xacmlatt.pdp.std.functions.FunctionDefinitionXPath; /** * Test of PDP Functions (See XACML core spec section A.3) * * TO RUN - use jUnit * In Eclipse select this file or the enclosing directory, right-click and select Run As/JUnit Test * * */ public class FunctionDefinitionXPathTest { // // Strings for the Request contents // String reqStrMainStart = "" + "" + " " + " " + " Julius Hibbert" + " " + " " + " This is IT! " + " " + " " + " This is IT! " + " " + ""; String reqStrResourceStart = ""; String reqStrContentMdRecord = " " + "" + "" + "ABC Hospital" + "Surgery" + "" + "" + "Bart Simpson" + "60" + "male" + "123456" + "" + "" + "" + "Gastric Cancer" + "Hyper tension" + "" + "" + "" + "Well differentiated adeno carcinoma" + "" + "2000-10-05" + "" + "" + " " + " " + ""; String reqStrMalformedContent = " " + "" + "" + "ABC Hospital" + "" + ""; String reqStrResourceEnd = " " + " http://medico.com/record/patient/BartSimpson" + " " + " "; String reqStrActionStart = ""; String reqStrActionEnd = "" + "read" + "" + " "; String reqStrEnvironmentStartEnd = " "; String reqStrMainEnd = " "; // combined strings for convenience String reqStrMainResourceStart = reqStrMainStart + reqStrResourceStart; String reqStrResourceAllEnd = reqStrResourceEnd + reqStrActionStart + reqStrActionEnd + reqStrEnvironmentStartEnd + reqStrMainEnd; /* * variables useful in the following tests */ List arguments = new ArrayList(); // Name Spaces used in the XML as part of these examples (copied from the Conformance tests) - needed for compiling XPaths NamespaceContext nameSpaceContext = new NamespaceContext() { @Override public Iterator getPrefixes(String arg0) { return null;} @Override public String getPrefix(String arg0) {return null;} @Override public String getNamespaceURI(String arg0) { if("md".equals(arg0)) { return "http://www.medico.com/schemas/record"; } else if ("xacml-context".equals(arg0)) { return "urn:oasis:names:tc:xacml:3.0:context:schema:os"; } else if ("xsi".equals(arg0)) { return "http://www.w3.org/2001/XMLSchema-instance"; } return null; } }; // // XPath Function Attributes available for use in tests (representing appropriate fragment of Policy) // FunctionArgumentAttributeValue attrXnull = null; FunctionArgumentAttributeValue attrXEmpty = null; FunctionArgumentAttributeValue attrXNoCategory = null; FunctionArgumentAttributeValue attrXNoValue = null; FunctionArgumentAttributeValue attrXSlashSlashMdRecord = null; FunctionArgumentAttributeValue attrXSlashSlashStar = null; FunctionArgumentAttributeValue attrXSlashSlashMdName = null; FunctionArgumentAttributeValue attrXSlashSlashMdMalignancy = null; FunctionArgumentAttributeValue attrXNotInRequest = null; FunctionArgumentAttributeValue attrXSlashSlashMdRecordSlashStar = null; FunctionArgumentAttributeValue attrXMdPatientInfo = null; FunctionArgumentAttributeValue attrBadType = null; // String version of attrs for use in Deprecated functions FunctionArgumentAttributeValue attrStrnull = null; FunctionArgumentAttributeValue attrStrEmpty = null; FunctionArgumentAttributeValue attrStrNoCategory = null; FunctionArgumentAttributeValue attrStrNoValue = null; FunctionArgumentAttributeValue attrStrSlashSlashMdRecord = null; FunctionArgumentAttributeValue attrStrSlashSlashStar = null; FunctionArgumentAttributeValue attrStrSlashSlashMdName = null; FunctionArgumentAttributeValue attrStrSlashSlashMdMalignancy = null; FunctionArgumentAttributeValue attrStrNotInRequest = null; FunctionArgumentAttributeValue attrStrSlashSlashMdRecordSlashStar = null; FunctionArgumentAttributeValue attrStrMdPatientInfo = null; // // REQUEST objects available for use in tests // Request requestEmpty = new StdRequest(StdStatus.STATUS_OK); Request requestMdRecord = null; Request requestDoubleResources = null; Request requestResourceActionContent = null; Request requestContentInAction = null; /** * Set up all variables in one place because it is complicated (lots of steps needed for each attribute) */ public FunctionDefinitionXPathTest() { try { XPathFactory xPathFactory = XPathFactory.newInstance(); XPath xpath = xPathFactory.newXPath(); xpath.setNamespaceContext(nameSpaceContext); // Create XPaths to use in expressions XPathExpressionWrapper xEmpty = new XPathExpressionWrapper(""); XPathExpressionWrapper xSlashSlashMdRecord = new XPathExpressionWrapper(xpath.compile("//md:record")); XPathExpressionWrapper xSlashSlashStar = new XPathExpressionWrapper(xpath.compile("//*")); XPathExpressionWrapper xSlashSlashMdName = new XPathExpressionWrapper(xpath.compile("//md:name")); XPathExpressionWrapper xSlashSlashMdMalignancy = new XPathExpressionWrapper(xpath.compile("//md:malignancy")); XPathExpressionWrapper xNotInRequest = new XPathExpressionWrapper(xpath.compile("value_Not_in_request")); XPathExpressionWrapper xSlashSlashMdRecordSlashStar = new XPathExpressionWrapper(xpath.compile("//md:record/*")); XPathExpressionWrapper xMdPatientInfo = new XPathExpressionWrapper(xpath.compile("md:patient_info")); // create Function Attributes out of the XPathExpressions attrXnull = new FunctionArgumentAttributeValue(null); attrXEmpty = new FunctionArgumentAttributeValue(DataTypes.DT_XPATHEXPRESSION.createAttributeValue(xEmpty)); attrXNoCategory = new FunctionArgumentAttributeValue(DataTypes.DT_XPATHEXPRESSION.createAttributeValue(xSlashSlashMdRecord)); attrXNoValue = new FunctionArgumentAttributeValue(DataTypes.DT_XPATHEXPRESSION.createAttributeValue(xEmpty, new IdentifierImpl("urn:oasis:names:tc:xacml:3.0:attribute-category:resource" ))); attrXSlashSlashMdRecord = new FunctionArgumentAttributeValue(DataTypes.DT_XPATHEXPRESSION.createAttributeValue(xSlashSlashMdRecord, new IdentifierImpl("urn:oasis:names:tc:xacml:3.0:attribute-category:resource" ))); attrXSlashSlashStar = new FunctionArgumentAttributeValue(DataTypes.DT_XPATHEXPRESSION.createAttributeValue(xSlashSlashStar, new IdentifierImpl("urn:oasis:names:tc:xacml:3.0:attribute-category:resource" ))); attrXSlashSlashMdName = new FunctionArgumentAttributeValue(DataTypes.DT_XPATHEXPRESSION.createAttributeValue(xSlashSlashMdName, new IdentifierImpl("urn:oasis:names:tc:xacml:3.0:attribute-category:resource" ))); attrXSlashSlashMdMalignancy = new FunctionArgumentAttributeValue(DataTypes.DT_XPATHEXPRESSION.createAttributeValue(xSlashSlashMdMalignancy, new IdentifierImpl("urn:oasis:names:tc:xacml:3.0:attribute-category:resource" ))); attrXNotInRequest = new FunctionArgumentAttributeValue(DataTypes.DT_XPATHEXPRESSION.createAttributeValue(xNotInRequest, new IdentifierImpl("urn:oasis:names:tc:xacml:3.0:attribute-category:resource" ))); attrXSlashSlashMdRecordSlashStar = new FunctionArgumentAttributeValue(DataTypes.DT_XPATHEXPRESSION.createAttributeValue(xSlashSlashMdRecordSlashStar, new IdentifierImpl("urn:oasis:names:tc:xacml:3.0:attribute-category:resource" ))); attrXMdPatientInfo = new FunctionArgumentAttributeValue(DataTypes.DT_XPATHEXPRESSION.createAttributeValue(xMdPatientInfo, new IdentifierImpl("urn:oasis:names:tc:xacml:3.0:attribute-category:resource" ))); // Deprecated versions of args attrStrnull = new FunctionArgumentAttributeValue(null); attrStrEmpty = new FunctionArgumentAttributeValue(DataTypes.DT_STRING.createAttributeValue("")); attrStrNoCategory = new FunctionArgumentAttributeValue(DataTypes.DT_STRING.createAttributeValue("//md:record")); attrStrNoValue = new FunctionArgumentAttributeValue(DataTypes.DT_STRING.createAttributeValue("", new IdentifierImpl("urn:oasis:names:tc:xacml:3.0:attribute-category:resource" ))); attrStrSlashSlashMdRecord = new FunctionArgumentAttributeValue(DataTypes.DT_STRING.createAttributeValue("//md:record", new IdentifierImpl("urn:oasis:names:tc:xacml:3.0:attribute-category:resource" ))); attrStrSlashSlashStar = new FunctionArgumentAttributeValue(DataTypes.DT_STRING.createAttributeValue("//*", new IdentifierImpl("urn:oasis:names:tc:xacml:3.0:attribute-category:resource" ))); attrStrSlashSlashMdName = new FunctionArgumentAttributeValue(DataTypes.DT_STRING.createAttributeValue("//md:name", new IdentifierImpl("urn:oasis:names:tc:xacml:3.0:attribute-category:resource" ))); attrStrSlashSlashMdMalignancy = new FunctionArgumentAttributeValue(DataTypes.DT_STRING.createAttributeValue("//md:malignancy", new IdentifierImpl("urn:oasis:names:tc:xacml:3.0:attribute-category:resource" ))); attrStrNotInRequest = new FunctionArgumentAttributeValue(DataTypes.DT_STRING.createAttributeValue("value_Not_in_request", new IdentifierImpl("urn:oasis:names:tc:xacml:3.0:attribute-category:resource" ))); attrStrSlashSlashMdRecordSlashStar = new FunctionArgumentAttributeValue(DataTypes.DT_STRING.createAttributeValue("//md:record/*", new IdentifierImpl("urn:oasis:names:tc:xacml:3.0:attribute-category:resource" ))); attrStrMdPatientInfo = new FunctionArgumentAttributeValue(DataTypes.DT_STRING.createAttributeValue("md:patient_info", new IdentifierImpl("urn:oasis:names:tc:xacml:3.0:attribute-category:resource" ))); attrBadType = new FunctionArgumentAttributeValue(DataTypes.DT_STRING.createAttributeValue("some string")); // Request objects // to create a Request object the easiest way is to put the xml into a file and use the DOMRequest to load it. // single Content in the Resources section (normal valid request) String reqString = reqStrMainResourceStart + reqStrContentMdRecord + reqStrResourceAllEnd; File tFile = File.createTempFile("functionJunit", "request"); BufferedWriter bw = new BufferedWriter(new FileWriter(tFile)); bw.append(reqString); bw.flush(); bw.close(); requestMdRecord = DOMRequest.load(tFile); tFile.delete(); // Resources included twice reqString = reqStrMainResourceStart + reqStrContentMdRecord + reqStrResourceEnd + reqStrResourceStart + reqStrContentMdRecord +reqStrResourceAllEnd; tFile = File.createTempFile("functionJunit", "request"); bw = new BufferedWriter(new FileWriter(tFile)); bw.append(reqString); bw.flush(); bw.close(); requestDoubleResources = DOMRequest.load(tFile); tFile.delete(); // content included in both Resource and Action - ok reqString = reqStrMainResourceStart + reqStrContentMdRecord + reqStrResourceEnd + reqStrActionStart + reqStrContentMdRecord + reqStrActionEnd + reqStrMainEnd; tFile = File.createTempFile("functionJunit", "request"); bw = new BufferedWriter(new FileWriter(tFile)); bw.append(reqString); bw.flush(); bw.close(); requestResourceActionContent = DOMRequest.load(tFile); tFile.delete(); // Content included only in Action - missing content produces non-error result according to spec reqString = reqStrMainResourceStart + reqStrResourceEnd + reqStrActionStart + reqStrContentMdRecord + reqStrActionEnd + reqStrMainEnd; tFile = File.createTempFile("functionJunit", "request"); bw = new BufferedWriter(new FileWriter(tFile)); bw.append(reqString); bw.flush(); bw.close(); requestContentInAction = DOMRequest.load(tFile); tFile.delete(); // Test that Bad XML is caught @SuppressWarnings("unused") Request requestContentMisplaced = null; @SuppressWarnings("unused") Request requestMalformedContent = null; @SuppressWarnings("unused") Request requestDoubleContent = null; // Content included twice - error reqString = reqStrMainResourceStart + reqStrContentMdRecord + reqStrContentMdRecord +reqStrResourceAllEnd; tFile = File.createTempFile("functionJunit", "request"); bw = new BufferedWriter(new FileWriter(tFile)); bw.append(reqString); bw.flush(); bw.close(); try { requestDoubleContent = DOMRequest.load(tFile); tFile.delete(); } catch (com.att.research.xacml.std.dom.DOMStructureException e) { // this is what it should do, so just continue } catch (Exception e) { fail("Unexpected exception for bad XML, e="+e); } // Bad XML - Content not under a Category reqString = reqStrMainStart + reqStrContentMdRecord + reqStrResourceStart + reqStrResourceEnd + reqStrActionStart + reqStrActionEnd + reqStrMainEnd; tFile = File.createTempFile("functionJunit", "request"); bw = new BufferedWriter(new FileWriter(tFile)); bw.append(reqString); bw.flush(); bw.close(); try { requestContentMisplaced = DOMRequest.load(tFile); tFile.delete(); } catch (com.att.research.xacml.std.dom.DOMStructureException e) { // this is what it should do, so just continue } catch (Exception e) { fail("Unexpected exception for bad XML, e="+e); } // Bad XML - Content is not valid XML reqString = reqStrMainResourceStart + reqStrMalformedContent + reqStrResourceAllEnd; tFile = File.createTempFile("functionJunit", "request"); bw = new BufferedWriter(new FileWriter(tFile)); bw.append(reqString); bw.flush(); bw.close(); try { requestMalformedContent = DOMRequest.load(tFile); tFile.delete(); } catch (com.att.research.xacml.std.dom.DOMStructureException e) { // this is what it should do, so just continue } catch (Exception e) { fail("Unexpected exception for bad XML, e="+e); } } catch (Exception e) { fail("Constructor initializing variables, e="+ e + " cause="+e.getCause()); } } @Test public void testXpath_node_count() { FunctionDefinitionXPath fd = (FunctionDefinitionXPath) StdFunctions.FD_XPATH_NODE_COUNT; // check identity and type of the thing created assertEquals(XACML3.ID_FUNCTION_XPATH_NODE_COUNT, fd.getId()); assertEquals(DataTypes.DT_XPATHEXPRESSION.getId(), fd.getDataTypeArgs().getId()); assertEquals(DataTypes.DT_INTEGER.getId(), fd.getDataTypeId()); // just to be safe... If tests take too long these can probably be eliminated assertFalse(fd.returnsBag()); assertEquals(new Integer(1), fd.getNumArgs()); // match all elements within context arguments.clear(); arguments.add(attrXSlashSlashStar); ExpressionResult res = fd.evaluate(new StdEvaluationContext(requestMdRecord, null, null), arguments); assertTrue(res.isOk()); BigInteger resValue = (BigInteger)res.getValue().getValue(); assertEquals(new BigInteger("18"), resValue); // match exactly 1 element arguments.clear(); arguments.add(attrXSlashSlashMdMalignancy); res = fd.evaluate(new StdEvaluationContext(requestMdRecord, null, null), arguments); assertTrue(res.isOk()); resValue = (BigInteger)res.getValue().getValue(); assertEquals(new BigInteger("1"), resValue); // match a few but not all arguments.clear(); arguments.add(attrXSlashSlashMdName); res = fd.evaluate(new StdEvaluationContext(requestMdRecord, null, null), arguments); assertTrue(res.isOk()); resValue = (BigInteger)res.getValue().getValue(); assertEquals(new BigInteger("2"), resValue); // verify variables using in other tests: count nodes immediately under md:record arguments.clear(); arguments.add(attrXSlashSlashMdRecordSlashStar); res = fd.evaluate(new StdEvaluationContext(requestMdRecord, null, null), arguments); assertTrue(res.isOk()); resValue = (BigInteger)res.getValue().getValue(); assertEquals(new BigInteger("3"), resValue); // verify variables using in other tests: count number of records containing patient_info arguments.clear(); arguments.add(attrXMdPatientInfo); res = fd.evaluate(new StdEvaluationContext(requestMdRecord, null, null), arguments); assertTrue(res.isOk()); resValue = (BigInteger)res.getValue().getValue(); assertEquals(new BigInteger("1"), resValue); // verify variables using in other tests: count number of records containing md:name arguments.clear(); arguments.add(attrXSlashSlashMdName); res = fd.evaluate(new StdEvaluationContext(requestMdRecord, null, null), arguments); assertTrue(res.isOk()); resValue = (BigInteger)res.getValue().getValue(); assertEquals(new BigInteger("2"), resValue); // verify variables using in other tests: count number of records containing md:malignancy arguments.clear(); arguments.add(attrXSlashSlashMdMalignancy); res = fd.evaluate(new StdEvaluationContext(requestMdRecord, null, null), arguments); assertTrue(res.isOk()); resValue = (BigInteger)res.getValue().getValue(); assertEquals(new BigInteger("1"), resValue); // match no element arguments.clear(); arguments.add(attrXNotInRequest); res = fd.evaluate(new StdEvaluationContext(requestMdRecord, null, null), arguments); assertTrue(res.isOk()); resValue = (BigInteger)res.getValue().getValue(); assertEquals(new BigInteger("0"), resValue); // Resources included twice arguments.clear(); arguments.add(attrXSlashSlashMdName); res = fd.evaluate(new StdEvaluationContext(requestDoubleResources, null, null), arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-count More than one Content section for id 'urn:oasis:names:tc:xacml:3.0:attribute-category:resource'", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:syntax-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); // Content in both Resource and Action categories (ok) arguments.clear(); arguments.add(attrXSlashSlashMdName); res = fd.evaluate(new StdEvaluationContext(requestResourceActionContent, null, null), arguments); assertTrue(res.isOk()); resValue = (BigInteger)res.getValue().getValue(); assertEquals(new BigInteger("2"), resValue); // Content only in Action category (missing in Resources -> 0 according to spec) arguments.clear(); arguments.add(attrXSlashSlashMdName); res = fd.evaluate(new StdEvaluationContext(requestContentInAction, null, null), arguments); assertTrue(res.isOk()); resValue = (BigInteger)res.getValue().getValue(); assertEquals(new BigInteger("0"), resValue); //TODO - any other tests???? // null Evaluation Context arguments.clear(); arguments.add(attrXEmpty); res = fd.evaluate(null, arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-count Got null EvaluationContext", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); // null Request arguments.clear(); arguments.add(attrXSlashSlashMdRecord); res = fd.evaluate(new StdEvaluationContext(null, null, null), arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-count Got null Request in EvaluationContext", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); // null attribute arguments.clear(); arguments.add(attrXnull); res = fd.evaluate(new StdEvaluationContext(requestEmpty, null, null), arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-count Got null attribute at arg index 0", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); // no value arguments.clear(); arguments.add(attrXNoValue); res = fd.evaluate(new StdEvaluationContext(requestEmpty, null, null), arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-count XPathExpression returned null at index 0", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); // no category arguments.clear(); arguments.add(attrXNoCategory); res = fd.evaluate(new StdEvaluationContext(requestEmpty, null, null), arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-count Got null Category at index 0", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:syntax-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); // too many args arguments.clear(); arguments.add(attrXEmpty); arguments.add(attrXEmpty); res = fd.evaluate(null, arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-count Expected 1 arguments, got 2", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); // too few args arguments.clear(); res = fd.evaluate(null, arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-count Expected 1 arguments, got 0", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); // bad arg type arguments.clear(); arguments.add(attrBadType); res = fd.evaluate(null, arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-count Expected data type 'xpathExpression' saw 'string' at arg index 0", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); // null args arguments.clear(); arguments.add(null); res = fd.evaluate(null, arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-count Got null argument at arg index 0", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); } @Test public void testXpath_node_equal() { FunctionDefinitionXPath fd = (FunctionDefinitionXPath) StdFunctions.FD_XPATH_NODE_EQUAL; // check identity and type of the thing created assertEquals(XACML3.ID_FUNCTION_XPATH_NODE_EQUAL, fd.getId()); assertEquals(DataTypes.DT_XPATHEXPRESSION.getId(), fd.getDataTypeArgs().getId()); assertEquals(DataTypes.DT_BOOLEAN.getId(), fd.getDataTypeId()); // just to be safe... If tests take too long these can probably be eliminated assertFalse(fd.returnsBag()); assertEquals(new Integer(2), fd.getNumArgs()); // test normal success - exactly the same set arguments.clear(); arguments.add(attrXSlashSlashMdName); arguments.add(attrXSlashSlashMdName); ExpressionResult res = fd.evaluate(new StdEvaluationContext(requestMdRecord, null, null), arguments); assertTrue(res.isOk()); Boolean resValue = (Boolean)res.getValue().getValue(); assertTrue(resValue); // success - second list is subset of first list arguments.clear(); arguments.add(attrXSlashSlashMdRecordSlashStar); arguments.add(attrXMdPatientInfo); res = fd.evaluate(new StdEvaluationContext(requestMdRecord, null, null), arguments); assertTrue(res.isOk()); resValue = (Boolean)res.getValue().getValue(); assertTrue(resValue); // success - first list is subset of second list arguments.clear(); arguments.add(attrXMdPatientInfo); arguments.add(attrXSlashSlashMdRecordSlashStar); res = fd.evaluate(new StdEvaluationContext(requestMdRecord, null, null), arguments); assertTrue(res.isOk()); resValue = (Boolean)res.getValue().getValue(); assertTrue(resValue); // success - second list contains children of first list arguments.clear(); arguments.add(attrXSlashSlashMdRecord); arguments.add(attrXSlashSlashMdName); res = fd.evaluate(new StdEvaluationContext(requestMdRecord, null, null), arguments); assertTrue(res.isOk()); resValue = (Boolean)res.getValue().getValue(); assertFalse(resValue); // success - first list contains children of second list arguments.clear(); arguments.add(attrXSlashSlashMdName); arguments.add(attrXSlashSlashMdRecord); res = fd.evaluate(new StdEvaluationContext(requestMdRecord, null, null), arguments); assertTrue(res.isOk()); resValue = (Boolean)res.getValue().getValue(); assertFalse(resValue); // two non-overlapping sets arguments.clear(); arguments.add(attrXSlashSlashMdMalignancy); arguments.add(attrXSlashSlashMdName); res = fd.evaluate(new StdEvaluationContext(requestMdRecord, null, null), arguments); assertTrue(res.isOk()); resValue = (Boolean)res.getValue().getValue(); assertFalse(resValue); // first list contains nothing arguments.clear(); arguments.add(attrXNotInRequest); arguments.add(attrXSlashSlashMdName); res = fd.evaluate(new StdEvaluationContext(requestMdRecord, null, null), arguments); assertTrue(res.isOk()); resValue = (Boolean)res.getValue().getValue(); assertFalse(resValue); // second list contains nothing arguments.clear(); arguments.add(attrXSlashSlashMdName); arguments.add(attrXNotInRequest); res = fd.evaluate(new StdEvaluationContext(requestMdRecord, null, null), arguments); assertTrue(res.isOk()); resValue = (Boolean)res.getValue().getValue(); assertFalse(resValue); //TODO //????? ///??????? add real tests ////// // Resources included twice arguments.clear(); arguments.add(attrXSlashSlashMdName); arguments.add(attrXSlashSlashMdName); res = fd.evaluate(new StdEvaluationContext(requestDoubleResources, null, null), arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-equal More than one Content section for id 'urn:oasis:names:tc:xacml:3.0:attribute-category:resource'", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:syntax-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); // Content in both Resource and Action categories (ok) arguments.clear(); arguments.add(attrXSlashSlashMdName); arguments.add(attrXSlashSlashMdName); res = fd.evaluate(new StdEvaluationContext(requestResourceActionContent, null, null), arguments); assertTrue(res.isOk()); resValue = (Boolean)res.getValue().getValue(); assertTrue(resValue); // Content only in Action category (missing in Resources -> 0 according to spec) arguments.clear(); arguments.add(attrXSlashSlashMdName); arguments.add(attrXSlashSlashMdName); res = fd.evaluate(new StdEvaluationContext(requestContentInAction, null, null), arguments); assertTrue(res.isOk()); resValue = (Boolean)res.getValue().getValue(); assertFalse(resValue); // null Evaluation Context arguments.clear(); arguments.add(attrXSlashSlashMdRecord); arguments.add(attrXSlashSlashMdRecord); res = fd.evaluate(null, arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-equal Got null EvaluationContext", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); // null Request arguments.clear(); arguments.add(attrXSlashSlashMdRecord); arguments.add(attrXSlashSlashMdRecord); res = fd.evaluate(new StdEvaluationContext(null, null, null), arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-equal Got null Request in EvaluationContext", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); // null attribute arguments.clear(); arguments.add(attrXnull); arguments.add(attrXSlashSlashMdRecord); res = fd.evaluate(new StdEvaluationContext(requestEmpty, null, null), arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-equal Got null attribute at arg index 0", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); arguments.clear(); arguments.add(attrXSlashSlashMdRecord); arguments.add(attrXnull); res = fd.evaluate(new StdEvaluationContext(requestEmpty, null, null), arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-equal Got null attribute at arg index 1", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); // no value arguments.clear(); arguments.add(attrXNoValue); arguments.add(attrXSlashSlashMdRecord); res = fd.evaluate(new StdEvaluationContext(requestEmpty, null, null), arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-equal XPathExpression returned null at index 0", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); arguments.clear(); arguments.add(attrXSlashSlashMdRecord); arguments.add(attrXNoValue); res = fd.evaluate(new StdEvaluationContext(requestEmpty, null, null), arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-equal XPathExpression returned null at index 0", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); // no category arguments.clear(); arguments.add(attrXNoCategory); arguments.add(attrXSlashSlashMdRecord); res = fd.evaluate(new StdEvaluationContext(requestEmpty, null, null), arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-equal Got null Category at index 0", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:syntax-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); arguments.clear(); arguments.add(attrXSlashSlashMdRecord); arguments.add(attrXNoCategory); res = fd.evaluate(new StdEvaluationContext(requestEmpty, null, null), arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-equal XPathExpression returned null at index 0", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); // too many args arguments.clear(); arguments.add(attrXEmpty); arguments.add(attrXEmpty); arguments.add(attrXEmpty); res = fd.evaluate(null, arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-equal Expected 2 arguments, got 3", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); // too few args arguments.clear(); res = fd.evaluate(null, arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-equal Expected 2 arguments, got 0", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); arguments.clear(); arguments.add(attrXEmpty); res = fd.evaluate(null, arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-equal Expected 2 arguments, got 1", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); // bad arg type arguments.clear(); arguments.add(attrBadType); arguments.add(attrXEmpty); res = fd.evaluate(null, arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-equal Expected data type 'xpathExpression' saw 'string' at arg index 0", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); arguments.clear(); arguments.add(attrXEmpty); arguments.add(attrBadType); res = fd.evaluate(null, arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-equal Expected data type 'xpathExpression' saw 'string' at arg index 1", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); // null args arguments.clear(); arguments.add(attrXEmpty); arguments.add(null); res = fd.evaluate(null, arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-equal Got null argument at arg index 1", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); arguments.clear(); arguments.add(null); arguments.add(attrXEmpty); res = fd.evaluate(null, arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-equal Got null argument at arg index 0", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); } @Test public void testXpath_node_match() { FunctionDefinitionXPath fd = (FunctionDefinitionXPath) StdFunctions.FD_XPATH_NODE_MATCH; // check identity and type of the thing created assertEquals(XACML3.ID_FUNCTION_XPATH_NODE_MATCH, fd.getId()); assertEquals(DataTypes.DT_XPATHEXPRESSION.getId(), fd.getDataTypeArgs().getId()); assertEquals(DataTypes.DT_BOOLEAN.getId(), fd.getDataTypeId()); // just to be safe... If tests take too long these can probably be eliminated assertFalse(fd.returnsBag()); assertEquals(new Integer(2), fd.getNumArgs()); // test normal success - exactly the same set arguments.clear(); arguments.add(attrXSlashSlashMdName); arguments.add(attrXSlashSlashMdName); ExpressionResult res = fd.evaluate(new StdEvaluationContext(requestMdRecord, null, null), arguments); assertTrue(res.isOk()); Boolean resValue = (Boolean)res.getValue().getValue(); assertTrue(resValue); // success - second list is subset of first list arguments.clear(); arguments.add(attrXSlashSlashMdRecordSlashStar); arguments.add(attrXMdPatientInfo); res = fd.evaluate(new StdEvaluationContext(requestMdRecord, null, null), arguments); assertTrue(res.isOk()); resValue = (Boolean)res.getValue().getValue(); assertTrue(resValue); // success - first list is subset of second list arguments.clear(); arguments.add(attrXMdPatientInfo); arguments.add(attrXSlashSlashMdRecordSlashStar); res = fd.evaluate(new StdEvaluationContext(requestMdRecord, null, null), arguments); assertTrue(res.isOk()); resValue = (Boolean)res.getValue().getValue(); assertTrue(resValue); // success - second list contains children of first list arguments.clear(); arguments.add(attrXSlashSlashMdRecord); arguments.add(attrXSlashSlashMdName); res = fd.evaluate(new StdEvaluationContext(requestMdRecord, null, null), arguments); assertTrue(res.isOk()); resValue = (Boolean)res.getValue().getValue(); assertTrue(resValue); // success - first list contains children of second list arguments.clear(); arguments.add(attrXSlashSlashMdName); arguments.add(attrXSlashSlashMdRecord); res = fd.evaluate(new StdEvaluationContext(requestMdRecord, null, null), arguments); assertTrue(res.isOk()); resValue = (Boolean)res.getValue().getValue(); assertFalse(resValue); // two non-overlapping sets arguments.clear(); arguments.add(attrXSlashSlashMdMalignancy); arguments.add(attrXSlashSlashMdName); res = fd.evaluate(new StdEvaluationContext(requestMdRecord, null, null), arguments); assertTrue(res.isOk()); resValue = (Boolean)res.getValue().getValue(); assertFalse(resValue); // first list contains nothing arguments.clear(); arguments.add(attrXNotInRequest); arguments.add(attrXSlashSlashMdName); res = fd.evaluate(new StdEvaluationContext(requestMdRecord, null, null), arguments); assertTrue(res.isOk()); resValue = (Boolean)res.getValue().getValue(); assertFalse(resValue); // second list contains nothing arguments.clear(); arguments.add(attrXSlashSlashMdName); arguments.add(attrXNotInRequest); res = fd.evaluate(new StdEvaluationContext(requestMdRecord, null, null), arguments); assertTrue(res.isOk()); resValue = (Boolean)res.getValue().getValue(); assertFalse(resValue); //TODO //????? ///??????? add real tests ////// // Resources included twice arguments.clear(); arguments.add(attrXSlashSlashMdName); arguments.add(attrXSlashSlashMdName); res = fd.evaluate(new StdEvaluationContext(requestDoubleResources, null, null), arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-match More than one Content section for id 'urn:oasis:names:tc:xacml:3.0:attribute-category:resource'", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:syntax-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); // Content in both Resource and Action categories (ok) arguments.clear(); arguments.add(attrXSlashSlashMdName); arguments.add(attrXSlashSlashMdName); res = fd.evaluate(new StdEvaluationContext(requestResourceActionContent, null, null), arguments); assertTrue(res.isOk()); resValue = (Boolean)res.getValue().getValue(); assertTrue(resValue); // Content only in Action category (missing in Resources -> 0 according to spec) arguments.clear(); arguments.add(attrXSlashSlashMdName); arguments.add(attrXSlashSlashMdName); res = fd.evaluate(new StdEvaluationContext(requestContentInAction, null, null), arguments); assertTrue(res.isOk()); resValue = (Boolean)res.getValue().getValue(); assertFalse(resValue); // null Evaluation Context arguments.clear(); arguments.add(attrXSlashSlashMdRecord); arguments.add(attrXSlashSlashMdRecord); res = fd.evaluate(null, arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-match Got null EvaluationContext", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); // null Request arguments.clear(); arguments.add(attrXSlashSlashMdRecord); arguments.add(attrXSlashSlashMdRecord); res = fd.evaluate(new StdEvaluationContext(null, null, null), arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-match Got null Request in EvaluationContext", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); // null attribute arguments.clear(); arguments.add(attrXnull); arguments.add(attrXSlashSlashMdRecord); res = fd.evaluate(new StdEvaluationContext(requestEmpty, null, null), arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-match Got null attribute at arg index 0", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); arguments.clear(); arguments.add(attrXSlashSlashMdRecord); arguments.add(attrXnull); res = fd.evaluate(new StdEvaluationContext(requestEmpty, null, null), arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-match Got null attribute at arg index 1", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); // no value arguments.clear(); arguments.add(attrXNoValue); arguments.add(attrXSlashSlashMdRecord); res = fd.evaluate(new StdEvaluationContext(requestEmpty, null, null), arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-match XPathExpression returned null at index 0", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); arguments.clear(); arguments.add(attrXSlashSlashMdRecord); arguments.add(attrXNoValue); res = fd.evaluate(new StdEvaluationContext(requestEmpty, null, null), arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-match XPathExpression returned null at index 0", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); // no category arguments.clear(); arguments.add(attrXNoCategory); arguments.add(attrXSlashSlashMdRecord); res = fd.evaluate(new StdEvaluationContext(requestEmpty, null, null), arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-match Got null Category at index 0", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:syntax-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); arguments.clear(); arguments.add(attrXSlashSlashMdRecord); arguments.add(attrXNoCategory); res = fd.evaluate(new StdEvaluationContext(requestEmpty, null, null), arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-match XPathExpression returned null at index 0", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); // too many args arguments.clear(); arguments.add(attrXEmpty); arguments.add(attrXEmpty); arguments.add(attrXEmpty); res = fd.evaluate(null, arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-match Expected 2 arguments, got 3", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); // too few args arguments.clear(); res = fd.evaluate(null, arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-match Expected 2 arguments, got 0", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); arguments.clear(); arguments.add(attrXEmpty); res = fd.evaluate(null, arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-match Expected 2 arguments, got 1", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); // bad arg type arguments.clear(); arguments.add(attrBadType); arguments.add(attrXEmpty); res = fd.evaluate(null, arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-match Expected data type 'xpathExpression' saw 'string' at arg index 0", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); arguments.clear(); arguments.add(attrXEmpty); arguments.add(attrBadType); res = fd.evaluate(null, arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-match Expected data type 'xpathExpression' saw 'string' at arg index 1", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); // null args arguments.clear(); arguments.add(attrXEmpty); arguments.add(null); res = fd.evaluate(null, arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-match Got null argument at arg index 1", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); arguments.clear(); arguments.add(null); arguments.add(attrXEmpty); res = fd.evaluate(null, arguments); assertFalse(res.getStatus().isOk()); assertEquals( "function:xpath-node-match Got null argument at arg index 0", res.getStatus().getStatusMessage()); assertEquals("urn:oasis:names:tc:xacml:1.0:status:processing-error", res.getStatus().getStatusCode().getStatusCodeValue().stringValue()); } // // DEPRECATED versions that use String arguments rather than XPATHEXPRESSIONs // are NOT supported due to ambiguity in the semantics between 2.0 ( is root and has only one in resources) // and 3.0 ( is root and there are multiple sections in any category) // }