/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.engine.function.resolver; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.Map; import java.util.Set; import org.mockito.Mockito; import org.testng.annotations.Test; import org.threeten.bp.Instant; import com.opengamma.core.position.Position; import com.opengamma.core.position.Trade; import com.opengamma.core.position.impl.SimplePosition; import com.opengamma.core.position.impl.SimpleTrade; import com.opengamma.core.security.Security; import com.opengamma.engine.ComputationTarget; import com.opengamma.engine.ComputationTargetResolver; import com.opengamma.engine.ComputationTargetSpecification; import com.opengamma.engine.DefaultComputationTargetResolver; import com.opengamma.engine.function.AbstractFunction; import com.opengamma.engine.function.CompiledFunctionDefinition; import com.opengamma.engine.function.FunctionCompilationContext; import com.opengamma.engine.function.FunctionInvoker; import com.opengamma.engine.function.ParameterizedFunction; import com.opengamma.engine.target.ComputationTargetType; import com.opengamma.engine.test.PrimitiveTestFunction; import com.opengamma.engine.value.ValueProperties; import com.opengamma.engine.value.ValueRequirement; import com.opengamma.engine.value.ValueSpecification; import com.opengamma.id.ExternalIdBundle; import com.opengamma.id.UniqueId; import com.opengamma.id.UniqueIdentifiable; import com.opengamma.id.VersionCorrection; import com.opengamma.util.test.TestGroup; import com.opengamma.util.tuple.Triple; /** * */ @Test(groups = TestGroup.UNIT) public class DefaultCompiledFunctionResolverTest { private static ParameterizedFunction function(final CompiledFunctionDefinition cfd, final String uid) { ((AbstractFunction) cfd).setUniqueId(uid); return new ParameterizedFunction(cfd, cfd.getFunctionDefinition().getDefaultParameters()); } private FunctionCompilationContext createFunctionCompilationContext() { final FunctionCompilationContext context = new FunctionCompilationContext(); context.setRawComputationTargetResolver(new DefaultComputationTargetResolver()); context.setComputationTargetResolver(context.getRawComputationTargetResolver().atVersionCorrection(VersionCorrection.of(Instant.now(), Instant.now()))); return context; } public void testBasicResolution() { final ComputationTarget target = new ComputationTarget(ComputationTargetType.PRIMITIVE, UniqueId.of("scheme", "test_target")); final ParameterizedFunction parameterizedF1 = function(new PrimitiveTestFunction("req1"), "1"); final ParameterizedFunction parameterizedF2 = function(new PrimitiveTestFunction("req1"), "2"); final DefaultCompiledFunctionResolver resolver = new DefaultCompiledFunctionResolver(createFunctionCompilationContext()); resolver.addRule(new ResolutionRule(parameterizedF1, ApplyToAllTargets.INSTANCE, 100)); resolver.addRule(new ResolutionRule(parameterizedF2, ApplyToAllTargets.INSTANCE, 200)); resolver.compileRules(); Triple<ParameterizedFunction, ValueSpecification, Collection<ValueSpecification>> result = resolver.resolveFunction("req1", target, ValueProperties.none()).next(); assertEquals(result.getFirst(), parameterizedF2); } private static class Filter implements ComputationTargetFilter { private final ComputationTarget _match; public Filter(final ComputationTarget match) { _match = match; } @Override public boolean accept(final ComputationTarget target) { return _match.getValue().equals(target.getValue()); } } public void testFilteredRule() { final ComputationTarget target = new ComputationTarget(ComputationTargetType.PRIMITIVE, UniqueId.of("scheme", "test_target")); final ParameterizedFunction parameterizedF1 = function(new PrimitiveTestFunction("req1"), "1"); final ParameterizedFunction parameterizedF2 = function(new PrimitiveTestFunction("req1"), "2"); final DefaultCompiledFunctionResolver resolver = new DefaultCompiledFunctionResolver(createFunctionCompilationContext()); resolver.addRule(new ResolutionRule(parameterizedF1, ApplyToAllTargets.INSTANCE, 100)); resolver.addRule(new ResolutionRule(parameterizedF2, new Filter(target), 200)); resolver.compileRules(); Triple<ParameterizedFunction, ValueSpecification, Collection<ValueSpecification>> result = resolver.resolveFunction("req1", target, ValueProperties.none()).next(); assertEquals(result.getFirst(), parameterizedF2); ComputationTarget anotherTarget = new ComputationTarget(ComputationTargetType.PRIMITIVE, UniqueId.of("scheme", "target2")); result = resolver.resolveFunction("req1", anotherTarget, ValueProperties.none()).next(); assertEquals(result.getFirst(), parameterizedF1); } private static class TestSecurityFunction extends AbstractFunction.NonCompiled { @Override public ComputationTargetType getTargetType() { return ComputationTargetType.SECURITY; } @Override public boolean canApplyTo(final FunctionCompilationContext context, final ComputationTarget target) { assertTrue(getTargetType().isCompatible(target.getType())); return true; } @Override public Set<ValueSpecification> getResults(final FunctionCompilationContext context, final ComputationTarget target) { return Collections.singleton(new ValueSpecification("Value", target.toSpecification(), createValueProperties().get())); } @Override public Set<ValueRequirement> getRequirements(FunctionCompilationContext context, ComputationTarget target, ValueRequirement desiredValue) { fail(); return null; } @Override public FunctionInvoker getFunctionInvoker() { fail(); return null; } } private static class MockSecurityA implements Security { @Override public Map<String, String> getAttributes() { return null; } @Override public void setAttributes(Map<String, String> attributes) { } @Override public void addAttribute(String key, String value) { } @Override public UniqueId getUniqueId() { return UniqueId.of("Sec", "A"); } @Override public ExternalIdBundle getExternalIdBundle() { return null; } @Override public String getSecurityType() { return "A"; } @Override public String getName() { return "Name"; } } public void testSecurityFunction() { final ComputationTarget target = new ComputationTarget(ComputationTargetType.SECURITY, new MockSecurityA()); final ParameterizedFunction pfn = function(new TestSecurityFunction(), "1"); final DefaultCompiledFunctionResolver resolver = new DefaultCompiledFunctionResolver(createFunctionCompilationContext()); resolver.addRule(new ResolutionRule(pfn, ApplyToAllTargets.INSTANCE, 0)); resolver.compileRules(); Triple<ParameterizedFunction, ValueSpecification, Collection<ValueSpecification>> result = resolver.resolveFunction("Value", target, ValueProperties.none()).next(); assertEquals(result.getFirst(), pfn); } private static class MockSecurityB implements Security { @Override public Map<String, String> getAttributes() { return null; } @Override public void setAttributes(Map<String, String> attributes) { } @Override public void addAttribute(String key, String value) { } @Override public UniqueId getUniqueId() { return UniqueId.of("Sec", "B"); } @Override public ExternalIdBundle getExternalIdBundle() { return null; } @Override public String getSecurityType() { return "B"; } @Override public String getName() { return "Name"; } } private static class TestSecuritySubClassFunction extends TestSecurityFunction { @Override public ComputationTargetType getTargetType() { return ComputationTargetType.of(MockSecurityA.class); } @Override public boolean canApplyTo(final FunctionCompilationContext context, final ComputationTarget target) { assertTrue(getTargetType().isCompatible(target.getType())); assertTrue(target.getSecurity() instanceof MockSecurityA); return true; } } public void testSecuritySubClassFunction() { final ParameterizedFunction pfn1 = function(new TestSecurityFunction(), "1"); final ParameterizedFunction pfn2 = function(new TestSecuritySubClassFunction(), "2"); final DefaultCompiledFunctionResolver resolver = new DefaultCompiledFunctionResolver(createFunctionCompilationContext()); resolver.addRule(new ResolutionRule(pfn1, ApplyToAllTargets.INSTANCE, 0)); resolver.addRule(new ResolutionRule(pfn2, ApplyToAllTargets.INSTANCE, 1)); resolver.compileRules(); Triple<ParameterizedFunction, ValueSpecification, Collection<ValueSpecification>> result = resolver.resolveFunction("Value", new ComputationTarget(ComputationTargetType.of(MockSecurityA.class), new MockSecurityA()), ValueProperties.none()).next(); assertEquals(result.getFirst(), pfn2); result = resolver.resolveFunction("Value", new ComputationTarget(ComputationTargetType.of(MockSecurityB.class), new MockSecurityB()), ValueProperties.none()).next(); assertEquals(result.getFirst(), pfn1); } private static class TestPositionFunction extends AbstractFunction.NonCompiled { @Override public ComputationTargetType getTargetType() { return ComputationTargetType.POSITION; } @Override public boolean canApplyTo(final FunctionCompilationContext context, final ComputationTarget target) { assertTrue(getTargetType().isCompatible(target.getType())); return true; } @Override public Set<ValueSpecification> getResults(final FunctionCompilationContext context, final ComputationTarget target) { return Collections.singleton(new ValueSpecification("Value", target.toSpecification(), createValueProperties().get())); } @Override public Set<ValueRequirement> getRequirements(FunctionCompilationContext context, ComputationTarget target, ValueRequirement desiredValue) { fail(); return null; } @Override public FunctionInvoker getFunctionInvoker() { fail(); return null; } } private <T extends UniqueIdentifiable> T mock(final Class<T> clazz) { final T object = Mockito.mock(clazz); Mockito.when(object.getUniqueId()).thenReturn(UniqueId.of(clazz.getSimpleName(), Integer.toString(object.hashCode()))); return object; } public void testPositionFunction() { final ComputationTarget target = new ComputationTarget(ComputationTargetType.of(SimplePosition.class), mock(SimplePosition.class)); final ParameterizedFunction pfn = function(new TestPositionFunction(), "1"); final DefaultCompiledFunctionResolver resolver = new DefaultCompiledFunctionResolver(createFunctionCompilationContext()); resolver.addRule(new ResolutionRule(pfn, ApplyToAllTargets.INSTANCE, 0)); resolver.compileRules(); Triple<ParameterizedFunction, ValueSpecification, Collection<ValueSpecification>> result = resolver.resolveFunction("Value", target, ValueProperties.none()).next(); assertEquals(result.getFirst(), pfn); result = resolver.resolveFunction( "Value", new ComputationTarget(new ComputationTargetSpecification(ComputationTargetType.PORTFOLIO_NODE, UniqueId.of("Node", "0")).containing(ComputationTargetType.POSITION, target.getUniqueId()), target.getValue()), ValueProperties.none()) .next(); assertEquals(result.getFirst(), pfn); } private static class TestContextPositionFunction extends AbstractFunction.NonCompiled { @Override public ComputationTargetType getTargetType() { return ComputationTargetType.PORTFOLIO_NODE.containing(ComputationTargetType.POSITION); } @Override public boolean canApplyTo(final FunctionCompilationContext context, final ComputationTarget target) { assertEquals(target.getType(), ComputationTargetType.PORTFOLIO_NODE.containing(ComputationTargetType.of(SimplePosition.class))); assertEquals(target.getContextSpecification(), new ComputationTargetSpecification(ComputationTargetType.PORTFOLIO_NODE, UniqueId.of("Node", "0"))); return true; } @Override public Set<ValueSpecification> getResults(final FunctionCompilationContext context, final ComputationTarget target) { return Collections.singleton(new ValueSpecification("Value", target.toSpecification(), createValueProperties().get())); } @Override public Set<ValueRequirement> getRequirements(FunctionCompilationContext context, ComputationTarget target, ValueRequirement desiredValue) { fail(); return null; } @Override public FunctionInvoker getFunctionInvoker() { fail(); return null; } } public void testContextPositionFunction() { final ComputationTarget target = new ComputationTarget(ComputationTargetType.of(SimplePosition.class), mock(SimplePosition.class)); final ParameterizedFunction pfn = function(new TestContextPositionFunction(), "1"); final FunctionCompilationContext context = new FunctionCompilationContext(); final ComputationTargetResolver.AtVersionCorrection targetResolver = Mockito.mock(ComputationTargetResolver.AtVersionCorrection.class); Mockito.when(targetResolver.resolve(target.toSpecification())).thenReturn(target); context.setComputationTargetResolver(targetResolver); final DefaultCompiledFunctionResolver resolver = new DefaultCompiledFunctionResolver(context); resolver.addRule(new ResolutionRule(pfn, ApplyToAllTargets.INSTANCE, 0)); resolver.compileRules(); assertFalse(resolver.resolveFunction("Value", target, ValueProperties.none()).hasNext()); Triple<ParameterizedFunction, ValueSpecification, Collection<ValueSpecification>> result = resolver.resolveFunction( "Value", new ComputationTarget(new ComputationTargetSpecification(ComputationTargetType.PORTFOLIO_NODE, UniqueId.of("Node", "0")).containing(ComputationTargetType.of(SimplePosition.class), target.getUniqueId()), target.getValue()), ValueProperties.none()).next(); assertEquals(result.getFirst(), pfn); } private static class TestTradeFunction extends AbstractFunction.NonCompiled { @Override public ComputationTargetType getTargetType() { return ComputationTargetType.TRADE; } @Override public boolean canApplyTo(final FunctionCompilationContext context, final ComputationTarget target) { assertTrue(getTargetType().isCompatible(target.getType())); return true; } @Override public Set<ValueSpecification> getResults(final FunctionCompilationContext context, final ComputationTarget target) { return Collections.singleton(new ValueSpecification("Value", target.toSpecification(), createValueProperties().get())); } @Override public Set<ValueRequirement> getRequirements(FunctionCompilationContext context, ComputationTarget target, ValueRequirement desiredValue) { fail(); return null; } @Override public FunctionInvoker getFunctionInvoker() { fail(); return null; } } private static class TestPositionOrTradeFunction extends AbstractFunction.NonCompiled { @Override public ComputationTargetType getTargetType() { return ComputationTargetType.POSITION_OR_TRADE; } @Override public boolean canApplyTo(final FunctionCompilationContext context, final ComputationTarget target) { assertTrue(getTargetType().isCompatible(target.getType())); return true; } @Override public Set<ValueSpecification> getResults(final FunctionCompilationContext context, final ComputationTarget target) { return Collections.singleton(new ValueSpecification("Value", target.toSpecification(), createValueProperties().get())); } @Override public Set<ValueRequirement> getRequirements(FunctionCompilationContext context, ComputationTarget target, ValueRequirement desiredValue) { fail(); return null; } @Override public FunctionInvoker getFunctionInvoker() { fail(); return null; } } public void testChainedRuleFolding() { final ComputationTarget target1 = new ComputationTarget(ComputationTargetType.of(SimplePosition.class), mock(SimplePosition.class)); final ComputationTarget target2 = new ComputationTarget(ComputationTargetType.of(SimpleTrade.class), mock(SimpleTrade.class)); final ParameterizedFunction pfn1 = function(new TestPositionFunction(), "1"); final ParameterizedFunction pfn2 = function(new TestTradeFunction(), "2"); final ParameterizedFunction pfn3 = function(new TestPositionOrTradeFunction(), "3"); final FunctionCompilationContext context = new FunctionCompilationContext(); final ComputationTargetResolver.AtVersionCorrection targetResolver = Mockito.mock(ComputationTargetResolver.AtVersionCorrection.class); Mockito.when(targetResolver.resolve(target1.toSpecification())).thenReturn(target1); Mockito.when(targetResolver.resolve(target2.toSpecification())).thenReturn(target2); context.setComputationTargetResolver(targetResolver); final DefaultCompiledFunctionResolver resolver = new DefaultCompiledFunctionResolver(context); resolver.addRule(new ResolutionRule(pfn1, ApplyToAllTargets.INSTANCE, 1)); resolver.addRule(new ResolutionRule(pfn2, ApplyToAllTargets.INSTANCE, 1)); resolver.addRule(new ResolutionRule(pfn3, ApplyToAllTargets.INSTANCE, 2)); resolver.compileRules(); Iterator<Triple<ParameterizedFunction, ValueSpecification, Collection<ValueSpecification>>> itr = resolver.resolveFunction("Value", target1, ValueProperties.none()); assertEquals(itr.next().getFirst(), pfn3); assertEquals(itr.next().getFirst(), pfn1); itr = resolver.resolveFunction("Value", target2, ValueProperties.none()); assertEquals(itr.next().getFirst(), pfn3); assertEquals(itr.next().getFirst(), pfn2); } private interface UserType extends Position, Trade { // This is a dumb case, but easy to test because the types and mock functions exist. In practice the equivalent will happen // when there are functions for two different interfaces that some securities may implement and a security that implements both // is the target } public void testCompiledRuleFolding() { final ComputationTarget target = new ComputationTarget(ComputationTargetType.of(UserType.class), mock(UserType.class)); final ParameterizedFunction pfn1 = function(new TestPositionFunction(), "1"); final ParameterizedFunction pfn2 = function(new TestTradeFunction(), "2"); final FunctionCompilationContext context = new FunctionCompilationContext(); final ComputationTargetResolver.AtVersionCorrection targetResolver = Mockito.mock(ComputationTargetResolver.AtVersionCorrection.class); Mockito.when(targetResolver.resolve(target.toSpecification())).thenReturn(target); context.setComputationTargetResolver(targetResolver); final DefaultCompiledFunctionResolver resolver = new DefaultCompiledFunctionResolver(context); resolver.addRule(new ResolutionRule(pfn1, ApplyToAllTargets.INSTANCE, 1)); resolver.addRule(new ResolutionRule(pfn2, ApplyToAllTargets.INSTANCE, 2)); resolver.compileRules(); Iterator<Triple<ParameterizedFunction, ValueSpecification, Collection<ValueSpecification>>> itr = resolver.resolveFunction("Value", target, ValueProperties.none()); assertEquals(itr.next().getFirst(), pfn2); assertEquals(itr.next().getFirst(), pfn1); } }