package com.opengamma.sesame.web.functionconfig;
import static com.opengamma.sesame.config.ConfigBuilder.argument;
import static com.opengamma.sesame.config.ConfigBuilder.arguments;
import static com.opengamma.sesame.config.ConfigBuilder.config;
import static com.opengamma.sesame.config.ConfigBuilder.function;
import static com.opengamma.sesame.config.ConfigBuilder.implementations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.testng.AssertJUnit.assertEquals;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.IOUtils;
import org.json.JSONException;
import org.mockito.internal.stubbing.answers.Returns;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.opengamma.core.config.Config;
import com.opengamma.core.config.impl.ConfigItem;
import com.opengamma.core.link.ConfigLink;
import com.opengamma.core.position.Trade;
import com.opengamma.financial.security.equity.EquitySecurity;
import com.opengamma.financial.security.irs.InterestRateSwapSecurity;
import com.opengamma.master.config.ConfigDocument;
import com.opengamma.master.config.ConfigMaster;
import com.opengamma.master.config.ConfigSearchRequest;
import com.opengamma.master.config.ConfigSearchResult;
import com.opengamma.sesame.EngineTestUtils;
import com.opengamma.sesame.OutputName;
import com.opengamma.sesame.config.EngineUtils;
import com.opengamma.sesame.config.FunctionArguments;
import com.opengamma.sesame.config.FunctionModelConfig;
import com.opengamma.sesame.function.AvailableImplementations;
import com.opengamma.sesame.function.AvailableImplementationsImpl;
import com.opengamma.sesame.function.AvailableOutputs;
import com.opengamma.sesame.function.AvailableOutputsImpl;
import com.opengamma.sesame.function.FunctionMetadata;
import com.opengamma.sesame.function.Output;
import com.opengamma.sesame.graph.FunctionModel;
import com.opengamma.sesame.graph.convert.DefaultArgumentConverter;
import com.opengamma.util.test.TestGroup;
@Test(groups = TestGroup.UNIT)
public class ConfigJsonBuilderTest {
private static final String COLUMN_NAME = "Column Name";
private static final FunctionMetadata FOO_META = EngineUtils.createMetadata(Fn.class, "foo");
private final JsonElement _expected;
public ConfigJsonBuilderTest() throws IOException, JSONException {
String jsonString = IOUtils.toString(getClass().getResourceAsStream("ConfigJsonBuilderTest.json"));
_expected = new JsonParser().parse(jsonString);
}
private void checkJson(Map<?, ?> json, String expectedJsonName) {
Gson gson = new Gson();
JsonElement element = _expected.getAsJsonObject().get(expectedJsonName);
Map expectedJson = gson.fromJson(element, Map.class);
EngineTestUtils.assertJsonEquals(expectedJson, json);
}
@Test
public void fnWithMultipleImplsNoImplSelected() throws JSONException {
AvailableImplementations availableImplementations = new AvailableImplementationsImpl();
availableImplementations.register(ImplNoArgs.class, ImplWithArgs.class);
FunctionModel model = FunctionModel.forFunction(FOO_META);
ConfigJsonBuilder builder = new ConfigJsonBuilder(mock(AvailableOutputs.class),
availableImplementations,
mock(ConfigMaster.class),
new DefaultArgumentConverter());
Map<String, Object> json = builder.getConfigPageModel(COLUMN_NAME, FunctionModelConfig.EMPTY, null, null, model);
checkJson(json, "fnWithMultipleImplsNoImplSelected");
}
@Test
public void fnWithMultipleImplsSelectedImplHasArgs() {
AvailableImplementations availableImplementations = new AvailableImplementationsImpl();
availableImplementations.register(ImplNoArgs.class, ImplWithArgs.class);
FunctionModelConfig config =
config(
implementations(Fn.class, ImplWithArgs.class),
arguments(
function(
ImplWithArgs.class,
argument("arg1", "value1"),
argument("arg2", ImmutableList.of(1, 2, 3)))));
FunctionModel model = FunctionModel.forFunction(FOO_META, config);
ConfigJsonBuilder builder = new ConfigJsonBuilder(mock(AvailableOutputs.class),
availableImplementations,
mock(ConfigMaster.class),
new DefaultArgumentConverter());
Map<String, Object> json = builder.getConfigPageModel(COLUMN_NAME, config, null, null, model);
checkJson(json, "fnWithMultipleImplsSelectedImplHasArgs");
}
@Test
public void fnWithMultipleImplsSelectedImplHasNoArgs() {
AvailableImplementations availableImplementations = new AvailableImplementationsImpl();
availableImplementations.register(ImplNoArgs.class, ImplWithArgs.class);
FunctionModelConfig config = config(implementations(Fn.class, ImplNoArgs.class));
FunctionModel model = FunctionModel.forFunction(FOO_META, config);
ConfigJsonBuilder builder = new ConfigJsonBuilder(mock(AvailableOutputs.class),
availableImplementations,
mock(ConfigMaster.class),
new DefaultArgumentConverter());
Map<String, Object> json = builder.getConfigPageModel(COLUMN_NAME, config, null, null, model);
checkJson(json, "fnWithMultipleImplsSelectedImplHasNoArgs");
}
@Test
public void concreteFunctionNoArgs() {
FunctionMetadata metadata = EngineUtils.createMetadata(ConcreteNoArgs.class, "bar");
FunctionModel model = FunctionModel.forFunction(metadata);
ConfigJsonBuilder builder = new ConfigJsonBuilder(mock(AvailableOutputs.class),
new AvailableImplementationsImpl(),
mock(ConfigMaster.class),
new DefaultArgumentConverter());
Map<String, Object> json = builder.getConfigPageModel(COLUMN_NAME, FunctionModelConfig.EMPTY, null, null, model);
checkJson(json, "concreteFunctionNoArgs");
}
@Test
public void concreteFunctionWithArgs() {
FunctionMetadata metadata = EngineUtils.createMetadata(ConcreteWithArgs.class, "baz");
FunctionModelConfig config =
config(
arguments(
function(
ConcreteWithArgs.class,
argument("arg1", "value1"),
argument("arg2", ImmutableList.of(1, 2, 3)))));
FunctionModel model = FunctionModel.forFunction(metadata, config);
ConfigJsonBuilder builder = new ConfigJsonBuilder(mock(AvailableOutputs.class),
new AvailableImplementationsImpl(),
mock(ConfigMaster.class),
new DefaultArgumentConverter());
Map<String, Object> json = builder.getConfigPageModel(COLUMN_NAME, config, null, null, model);
checkJson(json, "concreteFunctionWithArgs");
}
@Test
public void missingArgument() {
AvailableImplementations availableImplementations = new AvailableImplementationsImpl();
availableImplementations.register(ImplNoArgs.class, ImplWithArgs.class);
FunctionModelConfig config = config(implementations(Fn.class, ImplWithArgs.class),
arguments(function(ImplWithArgs.class,
argument("arg2", ImmutableList.of(1, 2, 3)))));
FunctionModel model = FunctionModel.forFunction(FOO_META, config);
ConfigJsonBuilder builder = new ConfigJsonBuilder(mock(AvailableOutputs.class),
availableImplementations,
mock(ConfigMaster.class),
new DefaultArgumentConverter());
Map<String, Object> json = builder.getConfigPageModel(COLUMN_NAME, config, null, null, model);
checkJson(json, "missingArgument");
}
@SuppressWarnings("unchecked")
@Test
public void createConfig() {
Gson gson = new Gson();
JsonElement element = _expected.getAsJsonObject().get("createConfig");
Map<String, Object> map = gson.fromJson(element, Map.class);
ConfigJsonBuilder builder = new ConfigJsonBuilder(new AvailableOutputsImpl(),
new AvailableImplementationsImpl(),
mock(ConfigMaster.class),
new DefaultArgumentConverter());
FunctionModelConfig config = builder.getConfigFromJson(map);
Map<String, Object> argsMap = ImmutableMap.<String, Object>of("arg1", "value1", "arg2", ImmutableList.of(1, 2, 3));
FunctionArguments simpleFunctionArguments = new FunctionArguments(argsMap);
Map<Class<?>, FunctionArguments> fnArgsMap =
ImmutableMap.<Class<?>, FunctionArguments>of(ImplWithArgs.class, simpleFunctionArguments);
FunctionModelConfig expected =
new FunctionModelConfig(ImmutableMap.<Class<?>, Class<?>>of(Fn.class, ImplWithArgs.class), fnArgsMap);
assertEquals(expected, config);
}
@SuppressWarnings("unchecked")
@Test
public void createConfigWithConfigArg() {
Gson gson = new Gson();
JsonElement element = _expected.getAsJsonObject().get("createConfigWithConfigArg");
Map<String, Object> map = gson.fromJson(element, Map.class);
ConfigJsonBuilder builder = new ConfigJsonBuilder(new AvailableOutputsImpl(),
new AvailableImplementationsImpl(),
mock(ConfigMaster.class),
new DefaultArgumentConverter());
FunctionModelConfig config = builder.getConfigFromJson(map);
ConfigLink<ConfigObject> configLink = ConfigLink.resolvable("configName", ConfigObject.class);
Map<String, Object> argsMap = ImmutableMap.<String, Object>of("configArg", configLink);
FunctionArguments simpleFunctionArguments = new FunctionArguments(argsMap);
Map<Class<?>, FunctionArguments> fnArgsMap =
ImmutableMap.<Class<?>, FunctionArguments>of(UsesConfig.class, simpleFunctionArguments);
FunctionModelConfig expected =
new FunctionModelConfig(ImmutableMap.<Class<?>, Class<?>>of(Fn.class, UsesConfig.class), fnArgsMap);
assertEquals(expected, config);
}
@Test
public void columnJsonNoInputOrOutput() {
AvailableOutputs availableOutputs = new AvailableOutputsImpl();
AvailableImplementations availableImplementations = new AvailableImplementationsImpl();
availableOutputs.register(Fn.class, Fn2.class, ConcreteNoArgs.class, ConcreteWithArgs.class);
availableImplementations.register(ImplNoArgs.class, ImplWithArgs.class);
ConfigJsonBuilder builder = new ConfigJsonBuilder(availableOutputs,
availableImplementations,
mock(ConfigMaster.class),
new DefaultArgumentConverter());
Map<String, Object> json = builder.getConfigPageModel(COLUMN_NAME, FunctionModelConfig.EMPTY, null, null, null);
checkJson(json, "columnJsonNoInputOrOutput");
}
@Test
public void columnJsonInputNoOutput() {
AvailableOutputs availableOutputs = new AvailableOutputsImpl();
AvailableImplementations availableImplementations = new AvailableImplementationsImpl();
availableOutputs.register(Fn.class, Fn2.class, ConcreteNoArgs.class, ConcreteWithArgs.class);
availableImplementations.register(ImplNoArgs.class, ImplWithArgs.class);
ConfigJsonBuilder builder = new ConfigJsonBuilder(availableOutputs,
availableImplementations,
mock(ConfigMaster.class),
new DefaultArgumentConverter());
Map<String, Object> json = builder.getConfigPageModel(COLUMN_NAME, FunctionModelConfig.EMPTY, Trade.class, null, null);
checkJson(json, "columnJsonInputNoOutput");
}
@Test
public void columnJsonInputAndOutput() {
AvailableOutputs availableOutputs = new AvailableOutputsImpl();
AvailableImplementations availableImplementations = new AvailableImplementationsImpl();
availableOutputs.register(Fn.class, Fn2.class, ConcreteNoArgs.class, ConcreteWithArgs.class);
availableImplementations.register(ImplNoArgs.class, ImplWithArgs.class);
ConfigJsonBuilder builder = new ConfigJsonBuilder(availableOutputs,
availableImplementations,
mock(ConfigMaster.class),
new DefaultArgumentConverter());
Map<String, Object> json = builder.getConfigPageModel(COLUMN_NAME,
FunctionModelConfig.EMPTY,
Trade.class,
OutputName.of("Foo2"),
null);
checkJson(json, "columnJsonInputAndOutput");
}
/**
* Tests that an array of values is included if the argument type is annotated with @Config and there
* are values of that type in the config master. if there is no value selected there the selected item
* isn't included (empty or null?)
*/
@Test
public void configArgNoSelection() {
AvailableImplementations availableImplementations = new AvailableImplementationsImpl();
availableImplementations.register(UsesConfig.class);
FunctionModelConfig config = new FunctionModelConfig(availableImplementations.getDefaultImplementations());
FunctionModel model = FunctionModel.forFunction(FOO_META, config);
ConfigMaster configMaster = mock(ConfigMaster.class);
ConfigSearchRequest<?> searchRequest = new ConfigSearchRequest<>();
searchRequest.setType(ConfigObject.class);
List<ConfigDocument> configs = Lists.newArrayList(configDocument("foo"), configDocument("bar"), configDocument("baz"));
when(configMaster.search(searchRequest)).thenAnswer(new Returns(new ConfigSearchResult<>(configs)));
ConfigJsonBuilder builder = new ConfigJsonBuilder(mock(AvailableOutputs.class),
availableImplementations,
configMaster,
new DefaultArgumentConverter());
Map<String, Object> functionJson = builder.getConfigPageModel(COLUMN_NAME, config, null, null, model);
checkJson(functionJson, "configArgNoSelection");
}
/**
* Tests that an array of values is included if the argument type is annotated with @Config and there
* are values of that type in the config master. If there is a value selected it is included
* TODO enable this test once the config link API has been changed to include the link target's name
*/
@Test(enabled = false)
public void configArgValueSelected() {
AvailableImplementations availableImplementations = new AvailableImplementationsImpl();
availableImplementations.register(UsesConfig.class);
ConfigLink<ConfigObject> configLink = ConfigLink.resolvable("bar", ConfigObject.class);
FunctionModelConfig config = config(implementations(Fn.class, UsesConfig.class),
arguments(function(UsesConfig.class, argument("configArg", configLink))));
FunctionModel model = FunctionModel.forFunction(FOO_META, config);
ConfigMaster configMaster = mock(ConfigMaster.class);
ConfigSearchRequest<?> searchRequest = new ConfigSearchRequest<>();
searchRequest.setType(ConfigObject.class);
List<ConfigDocument> configs = Lists.newArrayList(configDocument("foo"), configDocument("bar"), configDocument("baz"));
when(configMaster.search(searchRequest)).thenAnswer(new Returns(new ConfigSearchResult<>(configs)));
ConfigJsonBuilder builder = new ConfigJsonBuilder(mock(AvailableOutputs.class),
availableImplementations,
configMaster,
new DefaultArgumentConverter());
Map<String, Object> json = builder.getConfigPageModel(COLUMN_NAME, config, null, null, model);
checkJson(json, "configArgNoSelection");
}
@Test
public void convertBetweenJsonAndConfig() {
FunctionModelConfig config =
config(
implementations(
Fn.class, ImplWithArgs.class,
Fn2.class, Impl2.class),
arguments(
function(
ImplWithArgs.class,
argument("arg1", "argValue1"),
argument("arg2", ImmutableList.of(1, 2, 3))),
function(
ConcreteWithArgs.class,
argument("arg1", "argValue3"),
argument("arg2", ImmutableList.of(1, 2, 3)))));
ConfigJsonBuilder builder = new ConfigJsonBuilder(mock(AvailableOutputs.class),
mock(AvailableImplementations.class),
mock(ConfigMaster.class),
new DefaultArgumentConverter());
Map<String, Object> json = builder.getJsonFromConfig(config);
checkJson(json, "convertBetweenJsonAndConfig");
assertEquals(config, builder.getConfigFromJson(json));
}
private ConfigDocument configDocument(String name) {
return new ConfigDocument(ConfigItem.of(new ConfigObject(), name));
}
public interface Fn {
@Output("Foo")
String foo(Trade trade);
}
public static class ImplNoArgs implements Fn {
@Override
public String foo(Trade trade) {
return null;
}
}
public static class ImplWithArgs implements Fn {
public ImplWithArgs(String arg1, List<Integer> arg2) {
}
@Override
public String foo(Trade trade) {
return null;
}
}
public static class ConcreteNoArgs {
@Output("Bar")
public String bar(EquitySecurity equitySecurity) {
return null;
}
}
public static class ConcreteWithArgs {
public ConcreteWithArgs(String arg1, List<Integer> arg2) {
}
@Output("Baz")
public String baz(InterestRateSwapSecurity swapSecurity) {
return null;
}
}
public interface Fn2 {
@Output("Foo2")
String foo(Trade trade);
}
public static class Impl2 implements Fn2 {
@Override
public String foo(Trade trade) {
return null;
}
}
@Config
public static final class ConfigObject {
}
public static final class UsesConfig implements Fn {
public UsesConfig(ConfigObject configArg) {
}
@Override
public String foo(Trade trade) {
return null;
}
}
}