/**
* Revenue Settlement and Sharing System GE
* Copyright (C) 2011-2014, Javier Lucio - lucio@tid.es
* Telefonica Investigacion y Desarrollo, S.A.
*
* Copyright (C) 2015, CoNWeT Lab., Universidad Politécnica de Madrid
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.upm.fiware.rss.expenditureLimit.processing.test;
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import javax.sql.DataSource;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.database.IDatabaseConnection;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import es.upm.fiware.rss.common.Constants;
import es.upm.fiware.rss.common.test.DatabaseLoader;
import es.upm.fiware.rss.exception.RSSException;
import es.upm.fiware.rss.exception.UNICAExceptionType;
import es.upm.fiware.rss.expenditureLimit.dao.DbeExpendControlDao;
import es.upm.fiware.rss.expenditureLimit.model.DbeExpendControl;
import es.upm.fiware.rss.expenditureLimit.processing.ProcessingLimitService;
import es.upm.fiware.rss.model.BmCurrency;
import es.upm.fiware.rss.model.DbeAggregator;
import es.upm.fiware.rss.model.DbeAppProvider;
import es.upm.fiware.rss.model.DbeAppProviderId;
import es.upm.fiware.rss.model.DbeTransaction;
import java.net.URL;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.xml.FlatXmlDataSetBuilder;
import org.dbunit.operation.DatabaseOperation;
import org.springframework.beans.factory.annotation.Value;
/**
*
*
*/
@ContextConfiguration({"classpath:database.xml"})
public class ProcessingLimitServiceTest {
/**
* Logging system.
*/
private static Logger logger = LoggerFactory.getLogger(ProcessingLimitServiceTest.class);
private @Value("${database.test.schema}") String schema;
@Autowired
private DataSource dataSource;
@Autowired
private ProcessingLimitService limitService;
@Autowired
private DbeExpendControlDao controlService;
@Autowired
private DatabaseLoader databaseLoader;
@Autowired
@Qualifier("transactionManager")
private HibernateTransactionManager transactionManager;
/**
* Method to insert data before test.
*
* @throws Exception
* from db
*/
@Before
public void setUp() throws Exception {
databaseLoader.cleanInsert("dbunit/CREATE_DATATEST_EXPLIMIT.xml", true);
}
/**
* @throws Exception
*/
@After
public void tearDown() throws Exception {
FlatXmlDataSetBuilder loader = new FlatXmlDataSetBuilder();
IDatabaseConnection dbConn = new DatabaseConnection(DataSourceUtils.getConnection(dataSource), this.schema);
URL url = this.getClass().getClassLoader().getResource("dbunit/CREATE_DATATEST_EXPLIMIT.xml");
IDataSet ds = loader.build(url);
DatabaseOperation.DELETE_ALL.execute(dbConn, ds);
dbConn.getConnection().commit();
}
/**
* Generate Transaction test.
*
* @return transaction
*/
public static DbeTransaction generateTransaction() {
DbeTransaction tx = new DbeTransaction();
tx.setTcTransactionType(Constants.CHARGE_TYPE);
BmCurrency currency = new BmCurrency();
currency.setNuCurrencyId(1);
tx.setBmCurrency(currency);
DbeAggregator ag = new DbeAggregator();
ag.setTxEmail("test@email.com");
ag.setTxName("test");
DbeAppProviderId pid = new DbeAppProviderId();
pid.setAggregator(ag);
pid.setTxAppProviderId("app123456");
DbeAppProvider provider = new DbeAppProvider();
provider.setId(pid);
tx.setTxEndUserId("txEndUserId");
tx.setAppProvider(provider);
tx.setFtChargedAmount(new BigDecimal(20));
return tx;
}
/**
*
* @param tx
* @return
*/
private List<DbeExpendControl> getExpenditureControls(DbeTransaction tx) {
return controlService.getExpendDataForUserAppProvCurrency(
tx.getTxEndUserId(),
tx.getAppProvider().getId().getAggregator().getTxEmail(),
tx.getAppProvider().getId().getTxAppProviderId(),
tx.getBmCurrency());
}
/**
* Check that the limits are updated.
*/
@Transactional
public void updateControls() {
try {
ProcessingLimitServiceTest.logger.debug("==== Update Controls ====");
DbeTransaction tx = ProcessingLimitServiceTest.generateTransaction();
// Set user for testing
tx.setTxEndUserId("userIdUpdate");
tx.setFtChargedAmount(new BigDecimal(2));
List<DbeExpendControl> controls = this.getExpenditureControls(tx);
// Save expexted expenditure limits
Map<String, BigDecimal> expectedLimits = new HashMap<>();
for (DbeExpendControl control: controls) {
expectedLimits.put(control.getId().getTxElType(), control.getFtExpensedAmount().add(tx.getFtChargedAmount()));
}
// Reset dates to current date--> in other case the test fails
updateDate(controls);
limitService.updateLimit(tx);
List<DbeExpendControl> controls2 = this.getExpenditureControls(tx);
for (DbeExpendControl control : controls2) {
BigDecimal amount = control.getFtExpensedAmount();
Assert.assertTrue(expectedLimits.get(control.getId().getTxElType()).compareTo(amount) == 0);
}
} catch (RSSException e) {
Assert.fail("Exception not expected" + e.getMessage());
}
}
/**
* Update control dates
*
* @param controls
*/
private void updateDate(List<DbeExpendControl> controls) {
GregorianCalendar cal = (GregorianCalendar) Calendar.getInstance();
cal.setTime(new Date());
cal.add(Calendar.DAY_OF_MONTH, 1);
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
TransactionStatus status = transactionManager.getTransaction(def);
for (DbeExpendControl control : controls) {
control.setDtNextPeriodStart(cal.getTime());
controlService.createOrUpdate(control);
}
transactionManager.commit(status);
}
/**
* Check that the acummulated is set to 0 and added a negative value (refund)
*/
@Transactional
public void updateResetControls() {
try {
DbeTransaction tx = ProcessingLimitServiceTest.generateTransaction();
// Set user for testing
tx.setTxEndUserId("userIdUpdate");
tx.setTcTransactionType(Constants.REFUND_TYPE);
tx.setFtChargedAmount(new BigDecimal(2));
List<DbeExpendControl> controls = this.getExpenditureControls(tx);
DbeExpendControl control = controls.get(0);
// Reset period
Date date = new Date();
date.setTime((new Date()).getTime() - 100000000);
control.setDtNextPeriodStart(date);
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
TransactionStatus status = transactionManager.getTransaction(def);
controlService.createOrUpdate(control);
transactionManager.commit(status);
limitService.updateLimit(tx);
List<DbeExpendControl> controls2 = this.getExpenditureControls(tx);
for (DbeExpendControl controlAux : controls2) {
if (control.getId().getTxElType().
equalsIgnoreCase(controlAux.getId().getTxElType())) {
Assert.assertTrue("Expensed amount: " + controlAux.getFtExpensedAmount(), controlAux.getFtExpensedAmount().compareTo(new BigDecimal(-2)) == 0);
}
}
} catch (RSSException e) {
Assert.fail("Exception not expected" + e.getMessage());
}
}
/**
*
* Check that not existing control are created.
*/
@Transactional(propagation = Propagation.SUPPORTS)
public void creationControls() {
try {
DbeTransaction tx = ProcessingLimitServiceTest.generateTransaction();
// Set user for testing
tx.setTxEndUserId("userForCreation");
List<DbeExpendControl> controls = controlService.getExpendDataForUserAppProvCurrency(
tx.getTxEndUserId(),
tx.getAppProvider().getId().getAggregator().getTxEmail(),
tx.getAppProvider().getId().getTxAppProviderId(),
tx.getBmCurrency());
Assert.assertTrue(controls.isEmpty());
// Update limits.
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
TransactionStatus status = transactionManager.getTransaction(def);
limitService.proccesLimit(tx);
transactionManager.commit(status);
controls = controlService.getExpendDataForUserAppProvCurrency(
tx.getTxEndUserId(),
tx.getAppProvider().getId().getAggregator().getTxEmail(),
tx.getAppProvider().getId().getTxAppProviderId(),
tx.getBmCurrency());
Assert.assertNotNull(controls);
Assert.assertTrue(controls.size() == 3);
// All the new control have to be set to 0
for (DbeExpendControl control : controls) {
Assert.assertTrue(control.getFtExpensedAmount().compareTo(new BigDecimal(0)) == 0);
}
ProcessingLimitServiceTest.logger.debug("Controls:" + controls.size());
} catch (RSSException e) {
ProcessingLimitServiceTest.logger.debug("Error: " + e.getMessage());
}
}
/**
* Update periods and check amounts.
*/
@Transactional(propagation = Propagation.SUPPORTS)
public void checkControls() {
DbeTransaction tx = ProcessingLimitServiceTest.generateTransaction();
tx.setTxEndUserId("userIdUpdate");
try {
List<DbeExpendControl> controlsBefore = controlService.getExpendDataForUserAppProvCurrency(
tx.getTxEndUserId(),
tx.getAppProvider().getId().getAggregator().getTxEmail(),
tx.getAppProvider().getId().getTxAppProviderId(),
tx.getBmCurrency());
Assert.assertNotNull(controlsBefore);
// Reset dates to current date--> if not test fail
GregorianCalendar cal = (GregorianCalendar) Calendar.getInstance();
cal.setTime(new Date());
cal.add(Calendar.DAY_OF_MONTH, 1);
for (DbeExpendControl control : controlsBefore) {
control.setDtNextPeriodStart(cal.getTime());
controlService.createOrUpdate(control);
}
limitService.proccesLimit(tx);
List<DbeExpendControl> controlsAfter = controlService.getExpendDataForUserAppProvCurrency(
tx.getTxEndUserId(),
tx.getAppProvider().getId().getAggregator().getTxEmail(),
tx.getAppProvider().getId().getTxAppProviderId(),
tx.getBmCurrency());
ProcessingLimitServiceTest.logger.debug("Controls:" + controlsAfter.size());
for (DbeExpendControl controlInit : controlsBefore) {
for (DbeExpendControl controlEnd : controlsAfter) {
if (controlInit.getId().getTxElType().equalsIgnoreCase(controlEnd.getId().getTxElType())) {
// All the values without modification
Assert
.assertTrue(controlInit.getFtExpensedAmount().compareTo(controlEnd.getFtExpensedAmount()) == 0);
break;
}
}
}
} catch (RSSException e) {
ProcessingLimitServiceTest.logger.debug("Error: " + e.getMessage());
Assert.fail("Exception not expected");
}
// check error
try {
tx.setFtChargedAmount(new BigDecimal(1000));
limitService.proccesLimit(tx);
Assert.fail("Exception expected");
} catch (RSSException e) {
ProcessingLimitServiceTest.logger.debug("Exception received: " + e.getMessage());
// "SVC3705",
Assert.assertTrue(e.getMessage().contains("Insufficient payment method balance"));
}
// check that
try {
tx.setFtChargedAmount(new BigDecimal(30));
List<DbeExpendControl> controlsBefore = controlService.getExpendDataForUserAppProvCurrency(
tx.getTxEndUserId(),
tx.getAppProvider().getId().getAggregator().getTxEmail(),
tx.getAppProvider().getId().getTxAppProviderId(),
tx.getBmCurrency());
// Reset period
DbeExpendControl control = controlsBefore.get(0);
GregorianCalendar cal = (GregorianCalendar) Calendar.getInstance();
cal.setTime(new Date());
cal.add(Calendar.MONTH, -1);
control.setDtNextPeriodStart(cal.getTime());
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
TransactionStatus status = transactionManager.getTransaction(def);
controlService.update(control);
transactionManager.commit(status);
limitService.proccesLimit(tx);
List<DbeExpendControl> controlsAfter = controlService.getExpendDataForUserAppProvCurrency(
tx.getTxEndUserId(),
tx.getAppProvider().getId().getAggregator().getTxEmail(),
tx.getAppProvider().getId().getTxAppProviderId(),
tx.getBmCurrency());
boolean found = false;
for (DbeExpendControl checkControl : controlsAfter) {
if (checkControl.getFtExpensedAmount().compareTo(new BigDecimal(0)) == 0) {
found = true;
break;
}
}
// reset control found
Assert.assertTrue(found);
} catch (RSSException e) {
ProcessingLimitServiceTest.logger.debug("Exception received: " + e.getMessage());
Assert.fail("Exception expected");
}
}
/**
* Verifies that the limit perTransaction is applied correctly
*/
@Transactional(propagation = Propagation.SUPPORTS)
public void perTransactionLimit() {
DbeTransaction tx = ProcessingLimitServiceTest.generateTransaction();
tx.setTxEndUserId("userId01");
DbeAggregator ag = new DbeAggregator();
ag.setTxEmail("test@email.com");
ag.setTxName("test");
DbeAppProviderId pid = new DbeAppProviderId();
pid.setAggregator(ag);
pid.setTxAppProviderId("123456");
DbeAppProvider provider = new DbeAppProvider();
provider.setId(pid);
tx.setAppProvider(provider);
tx.setFtChargedAmount(new BigDecimal("60"));
try {
limitService.proccesLimit(tx);
Assert.fail("Limit surpassed");
} catch (RSSException e) {
if (e.getExceptionType().getExceptionId().
equals(UNICAExceptionType.INSUFFICIENT_MOP_BALANCE.getExceptionId())) {
Assert.assertTrue("Limit Exceeded", true);
} else {
Assert.fail("Exception unexpected");
}
}
tx = ProcessingLimitServiceTest.generateTransaction();
tx.setTxEndUserId("userId01");
tx.setAppProvider(provider);
try {
limitService.proccesLimit(tx);
Assert.assertTrue("Limit passed", true);
} catch (Exception e) {
Assert.fail("Exception not expected " + e.getMessage());
}
}
}