package com.redhat.lightblue.migrator.facade;
import java.util.Arrays;
import java.util.Properties;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import com.redhat.lightblue.migrator.facade.ServiceFacade.ExceptionSwallowedListener;
import com.redhat.lightblue.migrator.facade.methodcallstringifier.MethodCallStringifier;
import com.redhat.lightblue.migrator.facade.model.Country;
import com.redhat.lightblue.migrator.facade.proxy.FacadeProxyFactory;
import com.redhat.lightblue.migrator.facade.sharedstore.SharedStoreSetter;
import com.redhat.lightblue.migrator.test.LightblueMigrationPhase;
/**
* Dual read phase tests. Dual read means that both legacy and Lightblue are being read from and written to.
*
* @author mpatercz
*
*/
@RunWith(MockitoJUnitRunner.class)
public class ServiceFacadePhaseDualReadTest extends ServiceFacadeTestBase {
@Before
public void setup() throws InstantiationException, IllegalAccessException {
super.setup();
LightblueMigrationPhase.dualReadPhase(togglzRule);
}
@Test
public void testGetCountryFromLegacy_DualRead_Implicit() throws CountryException {
countryDAOProxy.getCountryFromLegacy(1l);
Mockito.verify(legacyDAO).getCountryFromLegacy(1l);
// even though this is a dual read phase, never call lightblue. It's not a facade operation.
Mockito.verifyZeroInteractions(lightblueDAO);
}
public interface CountryDAOSubinterface extends CountryDAOFacadable {
public abstract Country getCountryFromLegacy(long id) throws CountryException;
}
/**
* Calls to non annotated facade methods are proxied directly to legacy
* service. This test ensures this invocation works when facade is created
* using an interface which extends the interface used by the service.
*
*/
@Test
public void testGetCountryFromLegacy_UsingSubinterfaceToCreateProxy() throws Exception {
// countryDAO is daoFacade using CountryDAO interface to invoke methods
countryDAOProxy = FacadeProxyFactory.createFacadeProxy(daoFacade, CountryDAOSubinterface.class);
Mockito.verify((SharedStoreSetter) legacyDAO).setSharedStore((daoFacade).getSharedStore());
Mockito.verify((SharedStoreSetter) lightblueDAO).setSharedStore((daoFacade).getSharedStore());
countryDAOProxy.getCountryFromLegacy(1l);
Mockito.verify(legacyDAO).getCountryFromLegacy(1l);
// even though this is a proxy phase, never call lightblue. It's not a facade operation.
Mockito.verifyZeroInteractions(lightblueDAO);
}
@Test
public void dualReadPhaseReadConsistentTest() throws CountryException {
final boolean[] exceptionEventFired = new boolean[1];
exceptionEventFired[0] = false;
daoFacade.registerExceptionSwallowedListener(new ExceptionSwallowedListener() {
@Override
public void onLightblueSvcExceptionSwallowed(Throwable t, String implementationName) {
exceptionEventFired[0] = true;
}
});
Country country = new Country();
Mockito.when(legacyDAO.getCountry("PL")).thenReturn(country);
Mockito.when(lightblueDAO.getCountry("PL")).thenReturn(country);
countryDAOProxy.getCountry("PL");
Mockito.verify(consistencyChecker).checkConsistency(Mockito.any(), Mockito.any(), Mockito.anyString(), Mockito.any(MethodCallStringifier.class));
Mockito.verify(legacyDAO).getCountry("PL");
Mockito.verify(lightblueDAO).getCountry("PL");
Assert.assertFalse(exceptionEventFired[0]);
}
@Test
public void dualReadPhaseReadInconsistentTest() throws CountryException {
Country pl = new Country("PL");
Country ca = new Country("CA");
Mockito.when(legacyDAO.getCountry("PL")).thenReturn(ca);
Mockito.when(lightblueDAO.getCountry("PL")).thenReturn(pl);
Country returnedCountry = countryDAOProxy.getCountry("PL");
Mockito.verify(consistencyChecker).checkConsistency(Mockito.any(), Mockito.any(), Mockito.anyString(), Mockito.any(MethodCallStringifier.class));
Mockito.verify(legacyDAO).getCountry("PL");
Mockito.verify(lightblueDAO).getCountry("PL");
// when there is a conflict, facade will return what legacy dao returned
Assert.assertEquals(ca, returnedCountry);
}
@Test
public void dualReadPhaseReadInconsistentPrimitiveArrayTest() throws CountryException {
Country pl = new Country(1l, "PL");
Country ca = new Country(2l, "CA");
long[] ids = new long[]{1l, 2l, 3l};
Mockito.when(legacyDAO.getCountries(ids)).thenReturn(Arrays.asList(new Country[]{ca}));
Mockito.when(lightblueDAO.getCountries(ids)).thenReturn(Arrays.asList(new Country[]{pl}));
Country returnedCountry = countryDAOProxy.getCountries(ids).get(0);
Mockito.verify(consistencyChecker).checkConsistency(Mockito.any(), Mockito.any(), Mockito.anyString(), Mockito.any(MethodCallStringifier.class));
Mockito.verify(legacyDAO).getCountries(ids);
Mockito.verify(lightblueDAO).getCountries(ids);
// when there is a conflict, facade will return what legacy dao returned
Assert.assertEquals(ca, returnedCountry);
}
@Test
public void dualReadPhaseCreateWithReadTest() throws CountryException {
Country pl = new Country("PL");
Country createdByLegacy = new Country(101l, "PL"); // has id set
Mockito.when(legacyDAO.createCountryIfNotExists(pl)).thenReturn(createdByLegacy);
Country createdCountry = countryDAOProxy.createCountryIfNotExists(pl);
Assert.assertEquals(new Long(101), createdCountry.getId());
Mockito.verify(legacyDAO).createCountryIfNotExists(pl);
Mockito.verify(lightblueDAO).createCountryIfNotExists(pl);
Mockito.verify(consistencyChecker).checkConsistency(Mockito.any(), Mockito.any(), Mockito.anyString(), Mockito.any(MethodCallStringifier.class));
}
@Test
public void ligtblueFailureDuringReadTest() throws CountryException {
Country pl = new Country("PL");
Mockito.when(legacyDAO.getCountry("PL")).thenReturn(pl);
Mockito.when(lightblueDAO.getCountry(Mockito.anyString())).thenThrow(new RuntimeException("Lightblue failure!"));
Country returnedCountry = countryDAOProxy.getCountry("PL");
Mockito.verify(lightblueDAO).getCountry("PL");
Mockito.verify(legacyDAO).getCountry("PL");
Assert.assertEquals(pl, returnedCountry);
}
@Test
public void lightblueFailureDuringUpdateTest() throws CountryException {
Country pl = new Country("PL");
Country ca = new Country("CA");
Mockito.when(legacyDAO.updateCountry(pl)).thenReturn(ca);
Mockito.when(lightblueDAO.updateCountry(Mockito.any(Country.class))).thenThrow(new RuntimeException("Lightblue failure!"));
Country returnedCountry = countryDAOProxy.updateCountry(pl);
Mockito.verify(lightblueDAO).updateCountry(pl);
Mockito.verify(legacyDAO).updateCountry(pl);
Assert.assertEquals(ca, returnedCountry);
}
@Test
public void lightblueFailureDuringCreateTest() throws CountryException {
final boolean[] exceptionEventFired = new boolean[1];
exceptionEventFired[0] = false;
daoFacade.registerExceptionSwallowedListener(new ExceptionSwallowedListener() {
@Override
public void onLightblueSvcExceptionSwallowed(Throwable t, String implementationName) {
exceptionEventFired[0] = true;
}
});
Country pl = new Country(101l, "PL");
Mockito.when(legacyDAO.createCountry(pl)).thenReturn(pl);
Mockito.when(lightblueDAO.createCountry(Mockito.any(Country.class))).thenThrow(new RuntimeException("Lightblue failure!"));
Country returnedCountry = countryDAOProxy.createCountry(pl);
Mockito.verify(lightblueDAO).createCountry(pl);
Mockito.verify(legacyDAO).createCountry(pl);
Assert.assertEquals(pl, returnedCountry);
Assert.assertTrue(exceptionEventFired[0]);
}
@Test
public void lightblueNullReturnedAfterCreateTest() throws CountryException {
Country pl = new Country(101l, "PL");
Mockito.when(legacyDAO.createCountry(pl)).thenReturn(null);
Mockito.when(lightblueDAO.createCountry(Mockito.any(Country.class))).thenReturn(null);
Country returnedCountry = countryDAOProxy.createCountry(pl);
Mockito.verify(lightblueDAO).createCountry(pl);
Mockito.verify(legacyDAO).createCountry(pl);
Assert.assertEquals(null, returnedCountry);
}
@Test
public void lightblueTakesLongToRespondOnCreate_TimoutDisabled() throws CountryException {
TimeoutConfiguration t = new TimeoutConfiguration(0, CountryDAO.class.getSimpleName(), null);
daoFacade.setTimeoutConfiguration(t);
final Country pl = new Country(101l, "PL");
Mockito.when(legacyDAO.createCountry(pl)).thenReturn(pl);
Mockito.when(lightblueDAO.createCountry(Mockito.any(Country.class))).thenAnswer(new Answer<Country>() {
@Override
public Country answer(InvocationOnMock invocation) throws Throwable {
Thread.sleep(500);
return pl;
}
});
Country returnedCountry = countryDAOProxy.createCountry(pl);
Mockito.verify(lightblueDAO).createCountry(pl);
Mockito.verify(legacyDAO).createCountry(pl);
Mockito.verify(consistencyChecker).checkConsistency(Mockito.any(), Mockito.any(), Mockito.anyString(), Mockito.any(MethodCallStringifier.class));
Assert.assertEquals(pl, returnedCountry);
}
@Test
public void lightblueTakesLongToRespondOnCreate_Success() throws CountryException {
TimeoutConfiguration t = new TimeoutConfiguration(1000, CountryDAO.class.getSimpleName(), null);
daoFacade.setTimeoutConfiguration(t);
final Country pl = new Country(101l, "PL");
Mockito.when(legacyDAO.createCountry(pl)).thenReturn(pl);
Mockito.when(lightblueDAO.createCountry(Mockito.any(Country.class))).thenAnswer(new Answer<Country>() {
@Override
public Country answer(InvocationOnMock invocation) throws Throwable {
Thread.sleep(500);
return pl;
}
});
Country returnedCountry = countryDAOProxy.createCountry(pl);
Mockito.verify(lightblueDAO).createCountry(pl);
Mockito.verify(legacyDAO).createCountry(pl);
Mockito.verify(consistencyChecker).checkConsistency(Mockito.any(), Mockito.any(), Mockito.anyString(), Mockito.any(MethodCallStringifier.class));
Assert.assertEquals(pl, returnedCountry);
}
@Test
public void lightblueTakesLongToRespondOnRead_Timeout_NoInterrupt() throws CountryException {
TimeoutConfiguration t = new TimeoutConfiguration(200, CountryDAO.class.getSimpleName(), null);
t.setInterruptOnTimeout(false);
daoFacade.setTimeoutConfiguration(t);
final Country pl = new Country(101l, "PL");
Mockito.when(legacyDAO.getCountry("PL")).thenReturn(pl);
// an array trick to change value of a final boolean
final boolean[] wasInterrupted = {false};
Mockito.when(lightblueDAO.getCountry(Mockito.anyString())).thenAnswer(new Answer<Country>() {
@Override
public Country answer(InvocationOnMock invocation) throws Throwable {
try {
Thread.sleep(90000);
Assert.fail("Call did not timeout");
return pl;
} catch (InterruptedException e) {
wasInterrupted[0] = true;
throw e;
}
}
});
Country returnedCountry = countryDAOProxy.getCountry("PL");
Mockito.verify(lightblueDAO).getCountry("PL");
Mockito.verify(legacyDAO).getCountry("PL");
Mockito.verify(consistencyChecker, Mockito.never()).checkConsistency(Mockito.any(), Mockito.any(), Mockito.anyString(), Mockito.any(MethodCallStringifier.class));
Assert.assertEquals(pl, returnedCountry);
Assert.assertFalse("Lightblue call was interrupted on timeout", waitOnInterrupt(wasInterrupted, 3000));
}
@Test
public void lightblueTakesLongToRespondOnRead_Timeout_Interrupt() throws CountryException {
TimeoutConfiguration t = new TimeoutConfiguration(200, CountryDAO.class.getSimpleName(), null);
t.setInterruptOnTimeout(true);
daoFacade.setTimeoutConfiguration(t);
final Country pl = new Country(101l, "PL");
Mockito.when(legacyDAO.getCountry("PL")).thenReturn(pl);
// an array trick to change value of a final boolean
final boolean[] wasInterrupted = {false};
Mockito.when(lightblueDAO.getCountry(Mockito.anyString())).thenAnswer(new Answer<Country>() {
@Override
public Country answer(InvocationOnMock invocation) throws Throwable {
try {
Thread.sleep(90000);
Assert.fail("Call did not timeout");
return pl;
} catch (InterruptedException e) {
wasInterrupted[0] = true;
throw e;
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
});
Country returnedCountry = countryDAOProxy.getCountry("PL");
Mockito.verify(lightblueDAO).getCountry("PL");
Mockito.verify(legacyDAO).getCountry("PL");
Mockito.verify(consistencyChecker, Mockito.never()).checkConsistency(Mockito.any(), Mockito.any(), Mockito.anyString(), Mockito.any(MethodCallStringifier.class));
Assert.assertEquals(pl, returnedCountry);
Assert.assertTrue("Lightblue call was not interrupted on timeout", waitOnInterrupt(wasInterrupted, 10000));
}
private boolean waitOnInterrupt(boolean wasInterrupted[], int timeout) {
try {
int i=0;
while (!wasInterrupted[0]) {
Thread.sleep(100);
if (++i * 100 >= timeout) {
return false;
}
}
return true;
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
@Test
public void lightblueTakesLongToRespondOnCreate_Timeout_Interrupt() throws CountryException {
TimeoutConfiguration t = new TimeoutConfiguration(200, CountryDAO.class.getSimpleName(), null);
t.setInterruptOnTimeout(true);
daoFacade.setTimeoutConfiguration(t);
final Country pl = new Country(101l, "PL");
Mockito.when(legacyDAO.createCountry(pl)).thenReturn(pl);
// an array trick to change value of a final boolean
final boolean[] wasInterrupted = {false};
Mockito.when(lightblueDAO.createCountry(Mockito.any(Country.class))).thenAnswer(new Answer<Country>() {
@Override
public Country answer(InvocationOnMock invocation) throws Throwable {
try {
Thread.sleep(90000);
Assert.fail("Call did not timeout");
return pl;
} catch (InterruptedException e) {
wasInterrupted[0] = true;
throw e;
}
}
});
Country returnedCountry = countryDAOProxy.createCountry(pl);
Mockito.verify(lightblueDAO).createCountry(pl);
Mockito.verify(legacyDAO).createCountry(pl);
Mockito.verify(consistencyChecker, Mockito.never()).checkConsistency(Mockito.any(), Mockito.any(), Mockito.anyString(), Mockito.any(MethodCallStringifier.class));
Assert.assertEquals(pl, returnedCountry);
Assert.assertFalse("Lightblue call was interrupted on timeout, even though this is a write operation", waitOnInterrupt(wasInterrupted, 3000));
}
@Test
public void lightblueTakesLongToRespondOnRead_Timeout() throws CountryException {
TimeoutConfiguration t = new TimeoutConfiguration(1000, CountryDAO.class.getSimpleName(), null);
daoFacade.setTimeoutConfiguration(t);
final Country pl = new Country(101l, "PL");
Mockito.when(legacyDAO.getCountry("PL")).thenReturn(pl);
Mockito.when(lightblueDAO.getCountry("PL")).thenAnswer(new Answer<Country>() {
@Override
public Country answer(InvocationOnMock invocation) throws Throwable {
Thread.sleep(1500);
return pl;
}
});
Country returnedCountry = countryDAOProxy.getCountry("PL");
Mockito.verify(lightblueDAO).getCountry("PL");
Mockito.verify(legacyDAO).getCountry("PL");
Mockito.verify(consistencyChecker, Mockito.never()).checkConsistency(Mockito.any(), Mockito.any(), Mockito.anyString(), Mockito.any(MethodCallStringifier.class));
Assert.assertEquals(pl, returnedCountry);
}
@Test
public void lightblueTakesLongToRespondOnUpdate_Timeout() throws CountryException {
TimeoutConfiguration t = new TimeoutConfiguration(1000, CountryDAO.class.getSimpleName(), null);
daoFacade.setTimeoutConfiguration(t);
final Country pl = new Country(101l, "PL");
Mockito.when(legacyDAO.updateCountry(pl)).thenReturn(pl);
Mockito.when(lightblueDAO.updateCountry(pl)).thenAnswer(new Answer<Country>() {
@Override
public Country answer(InvocationOnMock invocation) throws Throwable {
Thread.sleep(1500);
return pl;
}
});
Country returnedCountry = countryDAOProxy.updateCountry(pl);
Mockito.verify(lightblueDAO).updateCountry(pl);
Mockito.verify(legacyDAO).updateCountry(pl);
Mockito.verify(consistencyChecker, Mockito.never()).checkConsistency(Mockito.any(), Mockito.any(), Mockito.anyString(), Mockito.any(MethodCallStringifier.class));
Assert.assertEquals(pl, returnedCountry);
}
@Test
public void lightblueTakesLongToRespondOnParallelRead_NoTimoutBecauseSourceEvenSlower() throws CountryException {
TimeoutConfiguration t = new TimeoutConfiguration(200, CountryDAO.class.getSimpleName(), null);
daoFacade.setTimeoutConfiguration(t);
final Country pl = new Country(101l, "PL");
Mockito.when(legacyDAO.getCountry("PL")).thenAnswer(new Answer<Country>() {
@Override
public Country answer(InvocationOnMock invocation) throws Throwable {
Thread.sleep(400);
return pl;
}
});
Mockito.when(lightblueDAO.getCountry("PL")).thenAnswer(new Answer<Country>() {
@Override
public Country answer(InvocationOnMock invocation) throws Throwable {
Thread.sleep(300);
return pl;
}
});
Country returnedCountry = countryDAOProxy.getCountry("PL");
Mockito.verify(lightblueDAO).getCountry("PL");
Mockito.verify(legacyDAO).getCountry("PL");
// consistency check is there because both services returned
Mockito.verify(consistencyChecker, Mockito.times(1)).checkConsistency(Mockito.any(), Mockito.any(), Mockito.anyString(), Mockito.any(MethodCallStringifier.class));
Assert.assertEquals(pl, returnedCountry);
}
@Test
public void lightblueTakesLongToRespondOnSerialWrite_NoTimoutBecauseSourceEvenSlower() throws CountryException {
TimeoutConfiguration t = new TimeoutConfiguration(200, CountryDAO.class.getSimpleName(), null);
daoFacade.setTimeoutConfiguration(t);
final Country pl = new Country(101l, "PL");
Mockito.when(legacyDAO.createCountry(pl)).thenAnswer(new Answer<Country>() {
@Override
public Country answer(InvocationOnMock invocation) throws Throwable {
Thread.sleep(400);
return pl;
}
});
Mockito.when(lightblueDAO.createCountry(pl)).thenAnswer(new Answer<Country>() {
@Override
public Country answer(InvocationOnMock invocation) throws Throwable {
Thread.sleep(300);
return pl;
}
});
Country returnedCountry = countryDAOProxy.createCountry(pl);
Mockito.verify(lightblueDAO).createCountry(pl);
Mockito.verify(legacyDAO).createCountry(pl);
// consistency check is there because both services returned
Mockito.verify(consistencyChecker, Mockito.times(1)).checkConsistency(Mockito.any(), Mockito.any(), Mockito.anyString(), Mockito.any(MethodCallStringifier.class));
Assert.assertEquals(pl, returnedCountry);
}
@Test
public void lightblueTakesLongToRespondOnRead_Success_FromProperties_Method() throws CountryException {
Properties p = new Properties();
p.setProperty(TimeoutConfiguration.CONFIG_PREFIX+"timeout.CountryDAO", "1000");
p.setProperty(TimeoutConfiguration.CONFIG_PREFIX+"timeout.CountryDAO.getCountry", "2000");
TimeoutConfiguration t = new TimeoutConfiguration(500, CountryDAO.class.getSimpleName(), p);
daoFacade.setTimeoutConfiguration(t);
final Country pl = new Country(101l, "PL");
Mockito.when(legacyDAO.getCountry("PL")).thenReturn(pl);
Mockito.when(lightblueDAO.getCountry("PL")).thenAnswer(new Answer<Country>() {
@Override
public Country answer(InvocationOnMock invocation) throws Throwable {
Thread.sleep(1500);
return pl;
}
});
Country returnedCountry = countryDAOProxy.getCountry("PL");
Mockito.verify(lightblueDAO).getCountry("PL");
Mockito.verify(legacyDAO).getCountry("PL");
Mockito.verify(consistencyChecker).checkConsistency(Mockito.any(), Mockito.any(), Mockito.anyString(), Mockito.any(MethodCallStringifier.class));
Assert.assertEquals(pl, returnedCountry);
}
@Test
public void lightblueTakesLongToRespondOnRead_Timeout_FromProperties_Bean() throws CountryException {
Properties p = new Properties();
p.setProperty(TimeoutConfiguration.CONFIG_PREFIX+"timeout.CountryDAO", "1000");
p.setProperty(TimeoutConfiguration.CONFIG_PREFIX+"timeout.CountryDAO.getCountry", "2000");
TimeoutConfiguration t = new TimeoutConfiguration(500, CountryDAO.class.getSimpleName(), p);
daoFacade.setTimeoutConfiguration(t);
final Country pl = new Country(101l, "PL");
Mockito.when(legacyDAO.createCountry(pl)).thenReturn(pl);
Mockito.when(lightblueDAO.createCountry(Mockito.any(Country.class))).thenAnswer(new Answer<Country>() {
@Override
public Country answer(InvocationOnMock invocation) throws Throwable {
Thread.sleep(1500);
return pl;
}
});
Country returnedCountry = countryDAOProxy.createCountry(pl);
Mockito.verify(lightblueDAO).createCountry(pl);
Mockito.verify(legacyDAO).createCountry(pl);
Mockito.verify(consistencyChecker, Mockito.never()).checkConsistency(Mockito.any(), Mockito.any(), Mockito.anyString(), Mockito.any(MethodCallStringifier.class));
Assert.assertEquals(pl, returnedCountry);
}
@Test
public void legacyFailureDuringParallelReadTest() throws CountryException {
Mockito.when(legacyDAO.getCountry("PL")).then(new Answer<Country>() {
@Override
public Country answer(InvocationOnMock invocation) throws Throwable {
Thread.sleep(300);
throw new CountryException();
}
});
try {
countryDAOProxy.getCountry("PL");
Assert.fail();
} catch (CountryException ce) {
} catch (Exception e) {
Assert.fail();
}
Mockito.verify(lightblueDAO).getCountry("PL");
Mockito.verify(legacyDAO).getCountry("PL");
}
@Test
public void legacyFailureDuringUpdateTest() throws CountryException, InterruptedException {
LightblueMigrationPhase.dualReadPhase(togglzRule);
final Country pl = new Country("PL");
Mockito.when(legacyDAO.updateCountry(Mockito.any(Country.class))).thenAnswer(new Answer<Country>() {
@Override
public Country answer(InvocationOnMock invocation) throws Throwable {
Thread.sleep(300);
throw new CountryException();
}
});
try {
countryDAOProxy.updateCountry(pl);
Assert.fail();
} catch (CountryException ce) {
} catch (Exception e) {
Assert.fail();
}
Mockito.verify(lightblueDAO).updateCountry(pl);
Mockito.verify(legacyDAO).updateCountry(pl);
}
@Test
public void legacyFailureDuringCreateTest() throws CountryException {
Country pl = new Country("PL");
Mockito.when(legacyDAO.createCountry(Mockito.any(Country.class))).thenAnswer(new Answer<Country>() {
@Override
public Country answer(InvocationOnMock invocation) throws Throwable {
Thread.sleep(300);
throw new CountryException();
}
});
try {
countryDAOProxy.createCountry(pl);
Assert.fail();
} catch (CountryException ce) {
} catch (Exception e) {
Assert.fail();
}
Mockito.verify(legacyDAO).createCountry(pl);
}
/**
* This test ensures that shared data is cleared for current thread at the
* beginning of execution.
*
* Thread Ids are unique, but can be reused. That means shared data created
* by previous thread can be accessed by the current thread with the same
* id, assuming the data does not expire and it is not consumed by the
* originating thread (there is an error before shared data is consumed).
*
* @throws CountryException
*/
@Test
public void clearSharedStoreAfterFailure() throws CountryException {
final Country pl = new Country("PL");
final Country ca = new Country("CA");
// legacyDAO creates CA Country with id=12
// legacyDAO creates PL Country with id=13
Mockito.when(legacyDAO.createCountry(Mockito.any(Country.class))).thenAnswer(new Answer<Country>() {
@Override
public Country answer(InvocationOnMock invocation) throws Throwable {
Country country = (Country) invocation.getArguments()[0];
if (country.getIso2Code().equals("CA")) {
// oracle service pushes id of a created object into shared store
daoFacade.getSharedStore().push(12l);
return new Country(12l, "CA");
} else {
// oracle service pushes id of a created object into shared store
daoFacade.getSharedStore().push(13l);
return new Country(13l, "PL");
}
}
});
// lightblueDAO fails when creating CA Country
// lightblueDAO creates PL Country with id=13
Mockito.when(lightblueDAO.createCountry(Mockito.any(Country.class))).thenAnswer(new Answer<Country>() {
@Override
public Country answer(InvocationOnMock invocation) throws Throwable {
Country country = (Country) invocation.getArguments()[0];
if (country.getIso2Code().equals("CA")) {
throw new CountryException();
} else {
return new Country((Long) daoFacade.getSharedStore().pop(), "PL");
}
}
});
// lightblue service operation fails and the id is not retrieved
countryDAOProxy.createCountry(ca);
// lightblue service operation succeeds, id is retrieved from shared store
// reusing same thread id as the previous call
Country returned = countryDAOProxy.createCountry(pl);
Assert.assertEquals((Long) 13l, returned.getId());
// the id pushed into shared store during first, failed call, is cleared, expecting no inconsistency
Mockito.verify(consistencyChecker).checkConsistency(Mockito.eq(new Country(13l, "PL")), Mockito.eq(new Country(13l, "PL")), Mockito.anyString(), Mockito.any(MethodCallStringifier.class));
Mockito.verify(legacyDAO).createCountry(pl);
Mockito.verify(legacyDAO).createCountry(ca);
Mockito.verify(lightblueDAO).createCountry(pl);
Mockito.verify(lightblueDAO).createCountry(ca);
}
@Test
public void dualReadPhaseRead_CircularDependencyTest() throws CountryException {
Country pl = new Country("PL");
Country de = new Country("DE");
// create circular dependency
pl.setNeighbour(de);
de.setNeighbour(pl);
Mockito.when(legacyDAO.getCountry("PL")).thenReturn(pl);
Mockito.when(lightblueDAO.getCountry("PL")).thenReturn(de);
Assert.assertEquals(pl, countryDAOProxy.getCountry("PL"));
Mockito.verify(consistencyChecker).checkConsistency(Mockito.any(), Mockito.any(), Mockito.anyString(), Mockito.any(MethodCallStringifier.class));
Mockito.verify(legacyDAO).getCountry("PL");
Mockito.verify(lightblueDAO).getCountry("PL");
}
}