/**
* Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.integration.tool.portfolio;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.mockito.Matchers;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.threeten.bp.LocalDate;
import org.threeten.bp.OffsetTime;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.core.position.impl.SimpleCounterparty;
import com.opengamma.core.position.impl.SimplePortfolio;
import com.opengamma.core.position.impl.SimplePortfolioNode;
import com.opengamma.core.position.impl.SimplePosition;
import com.opengamma.core.position.impl.SimpleTrade;
import com.opengamma.core.security.impl.SimpleSecurityLink;
import com.opengamma.id.ExternalId;
import com.opengamma.id.ExternalIdBundle;
import com.opengamma.id.UniqueId;
import com.opengamma.master.portfolio.ManageablePortfolio;
import com.opengamma.master.portfolio.PortfolioDocument;
import com.opengamma.master.portfolio.PortfolioMaster;
import com.opengamma.master.portfolio.PortfolioSearchRequest;
import com.opengamma.master.portfolio.PortfolioSearchResult;
import com.opengamma.master.position.ManageablePosition;
import com.opengamma.master.position.PositionDocument;
import com.opengamma.master.position.PositionMaster;
import com.opengamma.master.security.ManageableSecurity;
import com.opengamma.master.security.SecurityDocument;
import com.opengamma.master.security.SecurityMaster;
import com.opengamma.master.security.SecuritySearchRequest;
import com.opengamma.master.security.SecuritySearchResult;
import com.opengamma.util.test.TestGroup;
@Test(groups = TestGroup.UNIT)
public class PortfolioWriterTest {
private MasterRecorder _recorder;
@BeforeMethod
public void setUp() {
_recorder = new MasterRecorder();
}
@Test
public void testNewPortfolioInsertsSecurityPositionPortfolio() {
PortfolioWriter persister = new PortfolioWriter(true, mockPortfolioMaster(), mockPositionMaster(),
mockSecurityMaster());
String portfolioName = "TestPortfolio";
SimplePortfolioNode root = new SimplePortfolioNode(portfolioName);
ExternalIdBundle securityKey = ExternalIdBundle.of("TEST", "1234");
ManageableSecurity security = new ManageableSecurity("SEC_TYPE_TEST");
security.setName("TestSec");
security.setExternalIdBundle(securityKey);
Set<ManageableSecurity> securities = ImmutableSet.of(security);
root.addPosition(new SimplePosition(BigDecimal.valueOf(1000), securityKey));
SimplePortfolio pf = new SimplePortfolio(portfolioName, root);
persister.write(pf, securities);
assertThat(_recorder._securities.size(), is(1));
assertThat(_recorder._securities.get(0).getExternalIdBundle(), is(securityKey));
assertThat(_recorder._positions.size(), is(1));
assertThat(_recorder._positions.get(0).getSecurityLink().getExternalId(), is(securityKey));
assertThat(_recorder._positions.get(0).getQuantity(), is(BigDecimal.valueOf(1000)));
assertThat(_recorder.countPortfolioAdditions(), is(1));
assertThat(_recorder._portfolios.get(0).getPortfolio().getName(), is(portfolioName));
}
@Test(expectedExceptions = OpenGammaRuntimeException.class)
public void testCannotInsertSecurityWithoutIdBundle() {
PortfolioWriter persister = new PortfolioWriter(true, mockPortfolioMaster(), mockPositionMaster(),
mockSecurityMaster());
String portfolioName = "TestPortfolio";
SimplePortfolioNode root = new SimplePortfolioNode(portfolioName);
ManageableSecurity security = new ManageableSecurity("SEC_TYPE_TEST");
security.setName("TestSec");
Set<ManageableSecurity> securities = ImmutableSet.of(security);
SimplePosition position = new SimplePosition();
position.setQuantity(BigDecimal.valueOf(1000));
root.addPosition(position);
SimplePortfolio pf = new SimplePortfolio(portfolioName, root);
persister.write(pf, securities);
}
@Test(expectedExceptions = OpenGammaRuntimeException.class)
public void testCannotInsertPositionWithEmptySecurityIdBundle() {
PortfolioWriter persister = new PortfolioWriter(true, mockPortfolioMaster(), mockPositionMaster(),
mockSecurityMaster());
String portfolioName = "TestPortfolio";
SimplePortfolioNode root = new SimplePortfolioNode(portfolioName);
ExternalIdBundle securityKey = ExternalIdBundle.of("TEST", "1234");
ManageableSecurity security = new ManageableSecurity("SEC_TYPE_TEST");
security.setName("TestSec");
security.setExternalIdBundle(securityKey);
Set<ManageableSecurity> securities = ImmutableSet.of(security);
// Create position with empty Id bundle
root.addPosition(new SimplePosition(BigDecimal.valueOf(1000), ExternalIdBundle.EMPTY));
SimplePortfolio pf = new SimplePortfolio(portfolioName, root);
persister.write(pf, securities);
}
@Test(expectedExceptions = OpenGammaRuntimeException.class)
public void testCannotInsertTradeWithEmptySecurityIdBundle() {
PortfolioWriter persister = new PortfolioWriter(true, mockPortfolioMaster(), mockPositionMaster(),
mockSecurityMaster());
String portfolioName = "TestPortfolio";
SimplePortfolioNode root = new SimplePortfolioNode(portfolioName);
ExternalIdBundle securityKey = ExternalIdBundle.of("TEST", "1234");
ManageableSecurity security = new ManageableSecurity("SEC_TYPE_TEST");
security.setName("TestSec");
security.setExternalIdBundle(securityKey);
Set<ManageableSecurity> securities = ImmutableSet.of(security);
// Create position with empty Id bundle
SimplePosition position = new SimplePosition(BigDecimal.valueOf(1000), securityKey);
position.addTrade(new SimpleTrade(new SimpleSecurityLink(ExternalIdBundle.EMPTY), BigDecimal.valueOf(1000),
new SimpleCounterparty(ExternalId.of("CP", "123")), LocalDate.of(2014, 5, 1),
OffsetTime.MAX));
root.addPosition(position);
SimplePortfolio pf = new SimplePortfolio(portfolioName, root);
persister.write(pf, securities);
}
@Test(expectedExceptions = OpenGammaRuntimeException.class)
public void testCannotInsertPositionWithNullSecurityIdBundle() {
PortfolioWriter persister = new PortfolioWriter(true, mockPortfolioMaster(), mockPositionMaster(),
mockSecurityMaster());
String portfolioName = "TestPortfolio";
SimplePortfolioNode root = new SimplePortfolioNode(portfolioName);
ExternalIdBundle securityKey = ExternalIdBundle.of("TEST", "1234");
ManageableSecurity security = new ManageableSecurity("SEC_TYPE_TEST");
security.setName("TestSec");
security.setExternalIdBundle(securityKey);
Set<ManageableSecurity> securities = ImmutableSet.of(security);
// Create position with null Id bundle
SimplePosition position = new SimplePosition();
position.setQuantity(BigDecimal.valueOf(1000));
root.addPosition(position);
SimplePortfolio pf = new SimplePortfolio(portfolioName, root);
persister.write(pf, securities);
}
@Test
public void testNewPortfolioWithExistingSecurity() {
// Setup the security to appear as if we already have it
ExternalIdBundle securityKey = ExternalIdBundle.of("TEST", "1234");
ManageableSecurity security = new ManageableSecurity("SEC_TYPE_TEST");
security.setName("TestSec");
security.setExternalIdBundle(securityKey);
PortfolioWriter persister = new PortfolioWriter(true, mockPortfolioMaster(), mockPositionMaster(),
mockSecurityMaster(security));
String portfolioName = "TestPortfolio";
SimplePortfolioNode root = new SimplePortfolioNode(portfolioName);
Set<ManageableSecurity> securities = ImmutableSet.of(security);
root.addPosition(new SimplePosition(BigDecimal.valueOf(1000), securityKey));
SimplePortfolio pf = new SimplePortfolio(portfolioName, root);
persister.write(pf, securities);
// No security inserted as we already have it
assertThat(_recorder._securities.size(), is(0));
assertThat(_recorder._positions.size(), is(1));
assertThat(_recorder._positions.get(0).getSecurityLink().getExternalId(), is(securityKey));
assertThat(_recorder._positions.get(0).getQuantity(), is(BigDecimal.valueOf(1000)));
assertThat(_recorder.countPortfolioAdditions(), is(1));
assertThat(_recorder._portfolios.get(0).getPortfolio().getName(), is(portfolioName));
}
@Test
public void testReplacementOfExistingPortfolio() {
String portfolioName = "TestPortfolio";
ManageablePortfolio existing = new ManageablePortfolio(portfolioName);
PortfolioWriter persister = new PortfolioWriter(true, mockPortfolioMaster(existing), mockPositionMaster(),
mockSecurityMaster());
SimplePortfolioNode root = new SimplePortfolioNode(portfolioName);
ExternalIdBundle securityKey = ExternalIdBundle.of("TEST", "1234");
ManageableSecurity security = new ManageableSecurity("SEC_TYPE_TEST");
security.setName("TestSec");
security.setExternalIdBundle(securityKey);
Set<ManageableSecurity> securities = ImmutableSet.of(security);
root.addPosition(new SimplePosition(BigDecimal.valueOf(1000), securityKey));
SimplePortfolio pf = new SimplePortfolio(portfolioName, root);
persister.write(pf, securities);
assertThat(_recorder._securities.size(), is(1));
assertThat(_recorder._securities.get(0).getExternalIdBundle(), is(securityKey));
assertThat(_recorder._positions.size(), is(1));
assertThat(_recorder._positions.get(0).getSecurityLink().getExternalId(), is(securityKey));
assertThat(_recorder._positions.get(0).getQuantity(), is(BigDecimal.valueOf(1000)));
assertThat(_recorder.countPortfolioUpdates(), is(1));
assertThat(_recorder._portfolios.get(0).getPortfolio().getName(), is(portfolioName));
}
private PositionMaster mockPositionMaster() {
final PositionMaster mock = mock(PositionMaster.class);
when(mock.add(Matchers.<PositionDocument>any())).thenAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
ManageablePosition position = new ManageablePosition();
position.setUniqueId(UniqueId.of("POSN", "1"));
_recorder.recordPosition(((PositionDocument) invocation.getArguments()[0]).getPosition());
return new PositionDocument(position);
}
});
return mock;
}
private SecurityMaster mockSecurityMaster(final ManageableSecurity... existingSecurities) {
// Create a set of securities that are already stored in the master so
// we respond to queries about them
final Map<ExternalIdBundle, ManageableSecurity> existing = new HashMap<>();
for (ManageableSecurity security : existingSecurities) {
existing.put(security.getExternalIdBundle(), security);
}
SecurityMaster mock = mock(SecurityMaster.class);
when(mock.search(Matchers.<SecuritySearchRequest>any())).thenAnswer(new Answer<SecuritySearchResult>() {
@Override
public SecuritySearchResult answer(InvocationOnMock invocation) throws Throwable {
SecuritySearchRequest request = (SecuritySearchRequest) invocation.getArguments()[0];
final ExternalIdBundle idBundle = ExternalIdBundle.of(request.getExternalIdSearch());
return existing.containsKey(idBundle) ?
new SecuritySearchResult(ImmutableList.of(new SecurityDocument(existing.get(idBundle)))) :
new SecuritySearchResult();
}
});
when(mock.add(Matchers.<SecurityDocument>any())).thenAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
_recorder.recordSecurity(((SecurityDocument) invocation.getArguments()[0]).getSecurity());
return new SecurityDocument(new ManageableSecurity());
}
});
return mock;
}
private PortfolioMaster mockPortfolioMaster(ManageablePortfolio... existingPortfolios) {
final Map<String, ManageablePortfolio> existing = new HashMap<>();
for (ManageablePortfolio pf : existingPortfolios) {
pf.setUniqueId(UniqueId.of("TEST_PORTFOLIO", pf.getName()));
existing.put(pf.getName(), pf);
}
final PortfolioMaster mock = mock(PortfolioMaster.class);
when(mock.search(Matchers.<PortfolioSearchRequest>any())).thenAnswer(new Answer<PortfolioSearchResult>() {
@Override
public PortfolioSearchResult answer(InvocationOnMock invocation) throws Throwable {
PortfolioSearchRequest request = (PortfolioSearchRequest) invocation.getArguments()[0];
return existing.containsKey(request.getName()) ?
new PortfolioSearchResult(ImmutableList.of(new PortfolioDocument(existing.get(request.getName())))) :
new PortfolioSearchResult();
}
});
when(mock.add(Matchers.<PortfolioDocument>any())).thenAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
_recorder.recordPortfolio(((PortfolioDocument) invocation.getArguments()[0]));
return new PortfolioDocument(new ManageablePortfolio());
}
});
return mock;
}
private class MasterRecorder {
private final List<ManageableSecurity> _securities = new ArrayList<>();
private final List<ManageablePosition> _positions = new ArrayList<>();
private final List<PortfolioDocument> _portfolios = new ArrayList<>();
public void recordSecurity(ManageableSecurity security) {
_securities.add(security);
}
public void recordPosition(ManageablePosition position) {
_positions.add(position);
}
public void recordPortfolio(PortfolioDocument portfolio) {
_portfolios.add(portfolio);
}
public int countPortfolioUpdates() {
int count = 0;
for (PortfolioDocument portfolioDocument : _portfolios) {
if (portfolioDocument.getUniqueId() != null) {
count++;
}
}
return count;
}
public int countPortfolioAdditions() {
return _portfolios.size() - countPortfolioUpdates();
}
}
}