/* * Copyright (c) 2010-2016 Evolveum * * 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. */ package com.evolveum.midpoint.model.common.expression.script; import static org.testng.AssertJUnit.assertNotNull; import com.evolveum.midpoint.model.common.expression.ExpressionUtil; import com.evolveum.midpoint.model.common.expression.ExpressionVariables; import com.evolveum.midpoint.model.common.expression.functions.FunctionLibrary; import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.ItemDefinition; import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismPropertyDefinition; import com.evolveum.midpoint.prism.PrismPropertyValue; import com.evolveum.midpoint.prism.crypto.ProtectorImpl; import com.evolveum.midpoint.prism.crypto.Protector; import com.evolveum.midpoint.prism.util.PrismTestUtil; import com.evolveum.midpoint.schema.MidPointPrismContextFactory; import com.evolveum.midpoint.schema.constants.MidPointConstants; import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.util.MiscSchemaUtil; import com.evolveum.midpoint.schema.util.ObjectResolver; import com.evolveum.midpoint.test.util.DirectoryFileObjectResolver; import com.evolveum.midpoint.test.util.TestUtil; import com.evolveum.midpoint.util.DOMUtil; import com.evolveum.midpoint.util.PrettyPrinter; import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; import com.evolveum.midpoint.util.exception.ObjectNotFoundException; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.xml.ns._public.common.common_3.ScriptExpressionEvaluatorType; import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; import org.testng.AssertJUnit; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Test; import org.xml.sax.SAXException; import javax.xml.bind.JAXBException; import javax.xml.namespace.QName; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import static org.testng.AssertJUnit.assertEquals; /** * @author Radovan Semancik */ public abstract class AbstractScriptTest { protected static final QName PROPERTY_NAME = new QName(MidPointConstants.NS_MIDPOINT_TEST_PREFIX, "whatever"); protected static final String NS_X = "http://example.com/xxx"; protected static final String NS_Y = "http://example.com/yyy"; protected static File BASE_TEST_DIR = new File("src/test/resources/expression"); protected static File OBJECTS_DIR = new File("src/test/resources/objects"); protected static final String USER_OID = "c0c010c0-d34d-b33f-f00d-111111111111"; public static final Trace LOGGER = TraceManager.getTrace(AbstractScriptTest.class); protected ScriptExpressionFactory scriptExpressionfactory; protected ScriptEvaluator evaluator; @BeforeSuite public void setup() throws SchemaException, SAXException, IOException { PrettyPrinter.setDefaultNamespacePrefix(MidPointConstants.NS_MIDPOINT_PUBLIC_PREFIX); PrismTestUtil.resetPrismContext(MidPointPrismContextFactory.FACTORY); } @BeforeClass public void setupFactory() { PrismContext prismContext = PrismTestUtil.getPrismContext(); ObjectResolver resolver = new DirectoryFileObjectResolver(OBJECTS_DIR); Protector protector = new ProtectorImpl(); Collection<FunctionLibrary> functions = new ArrayList<FunctionLibrary>(); functions.add(ExpressionUtil.createBasicFunctionLibrary(prismContext, protector)); scriptExpressionfactory = new ScriptExpressionFactory(resolver, prismContext, protector); scriptExpressionfactory.setFunctions(functions); evaluator = createEvaluator(prismContext, protector); String languageUrl = evaluator.getLanguageUrl(); System.out.println("Expression test for "+evaluator.getLanguageName()+": registering "+evaluator+" with URL "+languageUrl); scriptExpressionfactory.registerEvaluator(languageUrl, evaluator); } protected abstract ScriptEvaluator createEvaluator(PrismContext prismContext, Protector protector); protected abstract File getTestDir(); protected boolean supportsRootNode() { return false; } @Test public void testExpressionSimple() throws Exception { evaluateAndAssertStringScalarExpresssion("expression-simple.xml", "testExpressionSimple", null, "foobar"); } @Test public void testExpressionStringVariables() throws Exception { evaluateAndAssertStringScalarExpresssion( "expression-string-variables.xml", "testExpressionStringVariables", ExpressionVariables.create( new QName(NS_X, "foo"), "FOO", new QName(NS_Y, "bar"), "BAR" ), "FOOBAR"); } @Test public void testExpressionObjectRefVariables() throws Exception { evaluateAndAssertStringScalarExpresssion( "expression-objectref-variables.xml", "testExpressionObjectRefVariables", ExpressionVariables.create( new QName(NS_X, "foo"), "Captain", new QName(NS_Y, "jack"), MiscSchemaUtil.createObjectReference(USER_OID, UserType.COMPLEX_TYPE) ), "Captain emp1234"); } @Test public void testExpressionObjectRefVariablesPolyString() throws Exception { evaluateAndAssertStringScalarExpresssion( "expression-objectref-variables-polystring.xml", "testExpressionObjectRefVariablesPolyString", ExpressionVariables.create( new QName(NS_X, "foo"), "Captain", new QName(NS_Y, "jack"), MiscSchemaUtil.createObjectReference(USER_OID, UserType.COMPLEX_TYPE) ), "Captain Jack Sparrow"); } // Using similar settings that will be used with mapping and SYSTEM VARIABLES @Test public void testUserGivenName() throws Exception { evaluateAndAssertStringScalarExpresssion( "expression-user-given-name.xml", "testUserGivenName", createUserScriptVariables(), "Jack"); } @Test public void testUserExtensionShip() throws Exception { evaluateAndAssertStringScalarExpresssion( "expression-user-extension-ship.xml", "testUserExtensionShip", createUserScriptVariables(), "Black Pearl"); } @Test public void testUserExtensionShipPath() throws Exception { evaluateAndAssertStringScalarExpresssion( "expression-user-extension-ship-path.xml", "testUserExtensionShipPath", createUserScriptVariables(), "Black Pearl"); } @Test public void testUserExtensionStringifyFullName() throws Exception { evaluateAndAssertStringScalarExpresssion( "expression-user-stringify-full-name.xml", "testUserExtensionStringifyFullName", createUserScriptVariables(), "Jack Sparrow"); } // TODO: user + multivalue (organizationalUnit) // TODO: user + polystring // TODO: user + numeric // TODO: user + no property value private ExpressionVariables createUserScriptVariables() { return ExpressionVariables.create(SchemaConstants.C_USER, MiscSchemaUtil.createObjectReference(USER_OID, UserType.COMPLEX_TYPE)); } // TODO: shadow + attributes @Test public void testRootNode() throws Exception { if (!supportsRootNode()) { return; } evaluateAndAssertStringScalarExpresssion( "expression-root-node.xml", "testRootNode", ExpressionVariables.create(null, MiscSchemaUtil.createObjectReference(USER_OID, UserType.COMPLEX_TYPE)), "Black Pearl"); } @Test public void testExpressionList() throws Exception { evaluateAndAssertStringListExpresssion( "expression-list.xml", "testExpressionList", ExpressionVariables.create( new QName(NS_Y, "jack"), MiscSchemaUtil.createObjectReference(USER_OID, UserType.COMPLEX_TYPE) ), "Leaders", "Followers"); } @Test public void testExpressionFunc() throws Exception { evaluateAndAssertStringScalarExpresssion("expression-func.xml", "testExpressionFunc", null, "gulocka v jamocke"); } @Test public void testExpressionFuncConcatName() throws Exception { evaluateAndAssertStringScalarExpresssion("expression-func-concatname.xml", "testExpressionFuncConcatName", null, "Horatio Torquemada Marley"); } private ScriptExpressionEvaluatorType parseScriptType(String fileName) throws SchemaException, IOException, JAXBException { ScriptExpressionEvaluatorType expressionType = PrismTestUtil.parseAtomicValue( new File(getTestDir(), fileName), ScriptExpressionEvaluatorType.COMPLEX_TYPE); return expressionType; } private <T> List<PrismPropertyValue<T>> evaluateExpression(ScriptExpressionEvaluatorType scriptType, ItemDefinition outputDefinition, ExpressionVariables variables, String shortDesc, OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException { ScriptExpression scriptExpression = scriptExpressionfactory.createScriptExpression(scriptType, outputDefinition, shortDesc); List<PrismPropertyValue<T>> resultValues = scriptExpression.evaluate(variables, null, false, shortDesc, null, result); if (resultValues != null) { for (PrismPropertyValue<T> resultVal: resultValues) { if (resultVal.getParent() != null) { AssertJUnit.fail("Result value "+resultVal+" from expression "+scriptExpression+" has parent"); } } } return resultValues; } private <T> List<PrismPropertyValue<T>> evaluateExpression(ScriptExpressionEvaluatorType scriptType, QName typeName, boolean scalar, ExpressionVariables variables, String shortDesc, OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException { ItemDefinition outputDefinition = new PrismPropertyDefinitionImpl(PROPERTY_NAME, typeName, PrismTestUtil.getPrismContext()); if (!scalar) { ((ItemDefinitionImpl) outputDefinition).setMaxOccurs(-1); } return evaluateExpression(scriptType, outputDefinition, variables, shortDesc, result); } private <T> PrismPropertyValue<T> evaluateExpressionScalar(ScriptExpressionEvaluatorType scriptType, QName typeName, ExpressionVariables variables, String shortDesc, OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException { List<PrismPropertyValue<T>> expressionResultList = evaluateExpression(scriptType, typeName, true, variables, shortDesc, result); return asScalar(expressionResultList, shortDesc); } private <T> PrismPropertyValue<T> asScalar(List<PrismPropertyValue<T>> expressionResultList, String shortDesc) { if (expressionResultList.size() > 1) { AssertJUnit.fail("Expression "+shortDesc+" produces a list of "+expressionResultList.size()+" while only expected a single value: "+expressionResultList); } if (expressionResultList.isEmpty()) { return null; } return expressionResultList.iterator().next(); } protected void evaluateAndAssertStringScalarExpresssion(String fileName, String testName, ExpressionVariables variables, String expectedValue) throws SchemaException, IOException, JAXBException, ExpressionEvaluationException, ObjectNotFoundException { List<PrismPropertyValue<String>> expressionResultList = evaluateStringExpresssion(fileName, testName, variables, true); PrismPropertyValue<String> expressionResult = asScalar(expressionResultList, testName); assertNotNull("Expression "+testName+" resulted in null value (expected '"+expectedValue+"')", expressionResult); assertEquals("Expression "+testName+" resulted in wrong value", expectedValue, expressionResult.getValue()); } private void evaluateAndAssertStringListExpresssion(String fileName, String testName, ExpressionVariables variables, String... expectedValues) throws SchemaException, IOException, JAXBException, ExpressionEvaluationException, ObjectNotFoundException { List<PrismPropertyValue<String>> expressionResultList = evaluateStringExpresssion(fileName, testName, variables, true); TestUtil.assertSetEquals("Expression "+testName+" resulted in wrong values", PrismPropertyValue.getValues(expressionResultList), expectedValues); } protected void evaluateAndAssertBooleanScalarExpresssion(String fileName, String testName, ExpressionVariables variables, Boolean expectedValue) throws SchemaException, IOException, JAXBException, ExpressionEvaluationException, ObjectNotFoundException { List<PrismPropertyValue<Boolean>> expressionResultList = evaluateBooleanExpresssion(fileName, testName, variables, true); PrismPropertyValue<Boolean> expressionResult = asScalar(expressionResultList, testName); assertNotNull("Expression "+testName+" resulted in null value (expected '"+expectedValue+"')", expressionResult); assertEquals("Expression "+testName+" resulted in wrong value", expectedValue, expressionResult.getValue()); } private List<PrismPropertyValue<String>> evaluateStringExpresssion(String fileName, String testName, ExpressionVariables variables, boolean scalar) throws SchemaException, IOException, JAXBException, ExpressionEvaluationException, ObjectNotFoundException { displayTestTitle(testName); ScriptExpressionEvaluatorType scriptType = parseScriptType(fileName); OperationResult opResult = new OperationResult(testName); return evaluateExpression(scriptType, DOMUtil.XSD_STRING, true, variables, testName, opResult); } private List<PrismPropertyValue<Boolean>> evaluateBooleanExpresssion(String fileName, String testName, ExpressionVariables variables, boolean scalar) throws SchemaException, IOException, JAXBException, ExpressionEvaluationException, ObjectNotFoundException { displayTestTitle(testName); ScriptExpressionEvaluatorType scriptType = parseScriptType(fileName); OperationResult opResult = new OperationResult(testName); return evaluateExpression(scriptType, DOMUtil.XSD_BOOLEAN, true, variables, testName, opResult); } private void displayTestTitle(String testName) { System.out.println("===[ "+evaluator.getLanguageName()+": "+testName+" ]==========================="); LOGGER.info("===[ "+evaluator.getLanguageName()+": "+testName+" ]==========================="); } }