package org.marketcetera.marketdata.core.webservice.impl;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Deque;
import java.util.EnumSet;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.marketcetera.core.LoggerConfiguration;
import org.marketcetera.event.*;
import org.marketcetera.marketdata.*;
import org.marketcetera.marketdata.bogus.BogusFeedModuleFactory;
import org.marketcetera.marketdata.core.webservice.MarketDataServiceClient;
import org.marketcetera.marketdata.core.webservice.MarketDataServiceClientFactory;
import org.marketcetera.module.ModuleManager;
import org.marketcetera.trade.*;
import org.marketcetera.util.log.SLF4JLoggerProxy;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.google.common.collect.Sets;
/* $License$ */
/**
* Tests {@link MarketDataServiceImpl}.
*
* @author <a href="mailto:colin@marketcetera.com">Colin DuPlantis</a>
* @version $Id: MarketDataServiceImplTest.java 16901 2014-05-11 16:14:11Z colin $
* @since 2.4.0
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"file:src/test/sample_data/conf/web.xml"})
public class MarketDataServiceImplTest
implements ApplicationContextAware
{
/**
* Runs once before all tests.
*
* @throws Exception if an unexpected error occurs
*/
@BeforeClass
public static void once()
throws Exception
{
LoggerConfiguration.logSetup();
}
/**
* Runs before each test.
*
* @throws Exception if an unexpected error occurs
*/
@Before
public void setup()
throws Exception
{
MockServer server = context.getBean(MockServer.class);
MarketDataServiceClientFactory clientFactory = context.getBean(MarketDataServiceClientFactory.class);
marketDataClient = clientFactory.create("username",
"password",
server.getHostname(),
server.getPort());
marketDataClient.start();
moduleManager = new ModuleManager();
moduleManager.init();
moduleManager.start(BogusFeedModuleFactory.INSTANCE_URN);
}
/**
* Runs after each test.
*
* @throws Exception if an unexpected error occurs
*/
@After
public void cleanup()
throws Exception
{
if(marketDataClient != null) {
marketDataClient.stop();
marketDataClient = null;
}
if(moduleManager != null) {
moduleManager.stop();
moduleManager = null;
}
}
/* (non-Javadoc)
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
*/
@Override
public void setApplicationContext(ApplicationContext inContext)
throws BeansException
{
context = inContext;
}
/**
* Tests the transmission of all event types via {@link MarketDataService#getEvents(org.marketcetera.util.ws.stateful.ClientContext, long).
*
* @throws Exception if an unexpected error occurs
*/
@Test
public void testSubscribeAllEventTypes()
throws Exception
{
Set<Instrument> instruments = Sets.newLinkedHashSet(Arrays.asList(new Instrument[] { equity,option,future,currency,bond } ));
Set<Content> equityContent = EnumSet.of(Content.TOP_OF_BOOK,Content.MARKET_STAT,Content.LATEST_TICK,Content.DIVIDEND);
Set<Content> nonequityContent = EnumSet.of(Content.LATEST_TICK,Content.MARKET_STAT,Content.TOP_OF_BOOK);
for(Instrument instrument : instruments) {
final AtomicBoolean trade = new AtomicBoolean(false);
final AtomicBoolean bid = new AtomicBoolean(false);
final AtomicBoolean ask = new AtomicBoolean(false);
final AtomicBoolean dividend = new AtomicBoolean(!(instrument instanceof Equity));
final AtomicBoolean stat = new AtomicBoolean(false);
MarketDataRequestBuilder requestBuilder = MarketDataRequestBuilder.newRequest().withAssetClass(AssetClass.getFor(instrument.getSecurityType()));
if(instrument instanceof Equity) {
requestBuilder.withContent(equityContent);
} else {
requestBuilder.withContent(nonequityContent);
}
requestBuilder.withSymbols(instrument.getFullSymbol());
MarketDataRequest request = requestBuilder.create();
SLF4JLoggerProxy.debug(this,
"Testing with request {}",
request);
final long id = marketDataClient.request(request,
true);
MarketDataFeedTestBase.wait(new Callable<Boolean>() {
@Override
public Boolean call()
throws Exception
{
Deque<Event> events = marketDataClient.getEvents(id);
if(events != null) {
for(Event event : events) {
if(event instanceof TradeEvent) {
validateEvent((TradeEvent)event);
trade.set(true);
} else if(event instanceof BidEvent) {
validateEvent((QuoteEvent)event);
bid.set(true);
} else if(event instanceof AskEvent) {
validateEvent((QuoteEvent)event);
ask.set(true);
} else if(event instanceof DividendEvent) {
dividend.set(true);
} else if(event instanceof MarketstatEvent) {
validateEvent((MarketstatEvent)event);
stat.set(true);
} else {
throw new UnsupportedOperationException("Unexpected event type: " + event.getClass().getName());
}
}
}
return trade.get() && bid.get() && ask.get() && stat.get() && dividend.get();
}
});
}
}
/**
* Validates the the given event contains expected, non-null values.
*
* @param inEvent a <code>MarketstatEvent</code> value
* @throws Exception if an unexpected error occurs
*/
private void validateEvent(MarketstatEvent inEvent)
throws Exception
{
SLF4JLoggerProxy.debug(this,
"Validating {}",
inEvent);
assertNotNull(inEvent.getClose());
assertNotNull(inEvent.getCloseDate());
assertNotNull(inEvent.getCloseExchange());
assertNotNull(inEvent.getEventType());
assertNotNull(inEvent.getHigh());
assertNotNull(inEvent.getHighExchange());
assertNotNull(inEvent.getInstrument());
assertNotNull(inEvent.getInstrumentAsString());
assertNotNull(inEvent.getLow());
assertNotNull(inEvent.getLowExchange());
assertTrue(inEvent.getMessageId() >= 0);
assertNotNull(inEvent.getOpen());
assertNotNull(inEvent.getOpenExchange());
assertNotNull(inEvent.getPreviousClose());
assertNotNull(inEvent.getPreviousCloseDate());
assertNotNull(inEvent.getProvider());
assertTrue(inEvent.getTimeMillis() >= 0);
assertNotNull(inEvent.getTimestamp());
assertNotNull(inEvent.getTradeHighTime());
assertNotNull(inEvent.getTradeLowTime());
assertNotNull(inEvent.getValue());
assertNotNull(inEvent.getVolume());
}
/**
* Validates the the given event contains expected, non-null values.
*
* @param inEvent a <code>TradeEvent</code> value
* @throws Exception if an unexpected error occurs
*/
private void validateEvent(TradeEvent inEvent)
throws Exception
{
SLF4JLoggerProxy.debug(this,
"Validating {}",
inEvent);
assertNotNull(inEvent.getEventType());
assertNotNull(inEvent.getExchange());
assertNotNull(inEvent.getExchangeTimestamp());
assertNotNull(inEvent.getInstrument());
assertNotNull(inEvent.getInstrumentAsString());
assertTrue(inEvent.getMessageId() >= 0);
assertNotNull(inEvent.getPrice());
assertTrue(!inEvent.getPrice().equals(BigDecimal.ZERO));
assertNotNull(inEvent.getProvider());
assertNotNull(inEvent.getSize());
assertTrue(!inEvent.getSize().equals(BigDecimal.ZERO));
assertTrue(inEvent.getTimeMillis() >= 0);
assertNotNull(inEvent.getTimestamp());
assertNotNull(inEvent.getTradeDate());
}
/**
* Validates the the given event contains expected, non-null values.
*
* @param inEvent a <code>QuoteEvent</code> value
* @throws Exception if an unexpected error occurs
*/
private void validateEvent(QuoteEvent inEvent)
throws Exception
{
SLF4JLoggerProxy.debug(this,
"Validating {}",
inEvent);
assertNotNull(inEvent.getAction());
assertNotNull(inEvent.getEventType());
assertNotNull(inEvent.getExchange());
assertNotNull(inEvent.getExchangeTimestamp());
assertNotNull(inEvent.getInstrument());
assertNotNull(inEvent.toString(),
inEvent.getInstrumentAsString());
assertTrue(inEvent.getMessageId() >= 0);
assertNotNull(inEvent.getPrice());
assertTrue(!inEvent.getPrice().equals(BigDecimal.ZERO));
assertNotNull(inEvent.getProvider());
assertNotNull(inEvent.getQuoteDate());
assertNotNull(inEvent.getSize());
assertTrue(!inEvent.getSize().equals(BigDecimal.ZERO));
assertTrue(inEvent.getTimeMillis() >= 0);
assertNotNull(inEvent.getTimestamp());
}
/**
* test module manager used to activate market data providers
*/
private ModuleManager moduleManager;
/**
* client used to connect to test market data nexus service
*/
private MarketDataServiceClient marketDataClient;
/**
* test application context
*/
private ApplicationContext context;
/**
* test option
*/
private Option option = new Option("METC",
"20150115",
BigDecimal.TEN,
OptionType.Put);
/**
* test future value
*/
private Future future = new Future("METC",
FutureExpirationMonth.DECEMBER,
2014);
/**
* test currency value
*/
private Currency currency = new Currency("USD/BTC");
/**
* test equity value
*/
private Equity equity = new Equity("METC");
/**
* test convertible bond value
*/
private ConvertibleBond bond = new ConvertibleBond("FR0011453463");
}