package org.hivedb.hibernate.simplified.session;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Interceptor;
import org.hibernate.Session;
import org.hibernate.TransientObjectException;
import org.hibernate.shards.strategy.access.SequentialShardAccessStrategy;
import org.hivedb.Hive;
import org.hivedb.hibernate.RecordNodeOpenSessionEvent;
import org.hivedb.meta.Assigner;
import org.hivedb.meta.Node;
import org.hivedb.meta.persistence.HiveDataSourceProvider;
import org.hivedb.util.Lists;
import org.hivedb.util.database.Schemas;
import org.hivedb.util.database.test.HiveTest;
import org.hivedb.util.database.test.WeatherReport;
import org.hivedb.util.database.test.WeatherReportImpl;
import org.hivedb.util.database.test.WeatherSchema;
import org.hivedb.util.functional.Atom;
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.jmock.integration.junit4.JMock;
import org.jmock.integration.junit4.JUnit4Mockery;
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.Collection;
@HiveTest.Config("hive_default")
@RunWith(JMock.class)
public class HiveSessionFactoryImplTest extends HiveTest {
private final static Log log = LogFactory.getLog(HiveSessionFactoryImplTest.class);
HiveSessionFactoryImpl factory;
private Mockery context;
public void setup() {
context = new JUnit4Mockery() {
{
//setImposteriser(ClassImposteriser.INSTANCE);
}
};
if (factory == null)
factory =
(HiveSessionFactoryImpl)
new SingletonHiveSessionFactoryBuilder(
getHive(),
Lists.newList(getMappedClasses()),
new SequentialShardAccessStrategy()).getSessionFactory();
for (Node node : getHive().getNodes())
Schemas.install(WeatherSchema.getInstance(), node.getUri());
}
@Test
public void shouldOpenAllShardsSession() throws Exception {
Session session = factory.openSession();
assertNull(session.get(WeatherReport.class, new Integer(7)));
session.close();
}
@Test
public void shouldOpenAnAllShardsSessionWithTheSpecifiedInterceptor() throws Exception {
final Interceptor mockInterceptor = context.mock(Interceptor.class);
final WeatherReportImpl report = new WeatherReportImpl();
context.checking(new Expectations() {
{
one(mockInterceptor).getEntityName(report);
//will(returnValue());
}
});
Session session = factory.openSession(mockInterceptor);
try {
session.getEntityName(report);
fail("No exception throw");
} catch (TransientObjectException e) {
//this is just here because I don't want to mock every method that will be called.
} finally {
session.close();
}
}
@Test
public void shouldOpenASessionByPrimaryKey() throws Exception {
Hive hive = getHive();
String asia = "Asia";
hive.directory().insertPrimaryIndexKey(asia);
final WeatherReportImpl report = new WeatherReportImpl();
report.setContinent(asia);
Session session = factory.openSession(asia);
try {
Node node = getNodeForFirstId(hive, hive.directory().getNodeIdsOfPrimaryIndexKey(asia));
assertCorrectNode(session, node);
} catch (Exception e) {
fail(e.getMessage());
} finally {
session.close();
}
}
@Test
public void shouldOpenASessionByResourceId() throws Exception {
Hive hive = getHive();
String asia = "Asia";
hive.directory().insertPrimaryIndexKey(asia);
int id = 999;
hive.directory().insertResourceId("WeatherReport", id, asia);
final WeatherReportImpl report = new WeatherReportImpl();
report.setContinent(asia);
Session session = factory.openSession("WeatherReport", id);
try {
Node node = getNodeForFirstId(hive, hive.directory().getNodeIdsOfResourceId("WeatherReport", id));
assertCorrectNode(session, node);
} catch (Exception e) {
fail(e.getMessage());
} finally {
session.close();
}
}
@Test
public void shouldOpenASessionBySecondaryIndex() throws Exception {
Hive hive = getHive();
String asia = "Asia";
int id = 999;
hive.directory().insertPrimaryIndexKey(asia);
hive.directory().insertResourceId("WeatherReport", id, asia);
int code = 765;
hive.directory().insertSecondaryIndexKey("WeatherReport", "RegionCode", code, id);
final WeatherReportImpl report = new WeatherReportImpl();
report.setContinent(asia);
Session session = factory.openSession("WeatherReport", "RegionCode", code);
try {
Node node = getNodeForFirstId(hive, hive.directory().getNodeIdsOfSecondaryIndexKey("WeatherReport", "RegionCode", code));
assertCorrectNode(session, node);
} catch (Exception e) {
fail(e.getMessage());
} finally {
session.close();
}
}
@Test
public void shouldAddOpenSessionEvents() throws Exception {
Hive hive = getHive();
String asia = "Asia";
hive.directory().insertPrimaryIndexKey(asia);
final WeatherReportImpl report = new WeatherReportImpl();
report.setContinent(asia);
Session session = factory.openSession(asia);
try {
Node node = getNodeForFirstId(hive, hive.directory().getNodeIdsOfPrimaryIndexKey(asia));
assertTrue("Opened a session to the wrong node", node.getUri().startsWith(RecordNodeOpenSessionEvent.getNode()));
} catch (Exception e) {
e.printStackTrace();
fail("Exception thrown: " + e.getMessage());
} finally {
session.close();
}
}
@Test
public void shouldAddOpenSessionEventsToAllShardsSession() throws Exception {
Hive hive = getHive();
String asia = "Asia";
hive.directory().insertPrimaryIndexKey(asia);
final WeatherReportImpl report = WeatherReportImpl.generate();
report.setContinent(asia);
Session session = factory.openSession();
report.setReportId(88);
try {
session.save(report);
Node node = getNodeForFirstId(hive, hive.directory().getNodeIdsOfPrimaryIndexKey(asia));
assertTrue("Opened a session to the wrong node", node.getUri().startsWith(RecordNodeOpenSessionEvent.getNode()));
} catch (Exception e) {
e.printStackTrace();
fail("Exception thrown: " + e.getMessage());
} finally {
session.close();
}
}
// TODO There is no guarantee that records get assigned to different nodes, causes intermittent failures
@Test
public void shouldThrowAnExceptionIfARecordIsStoredOnMoreThanOneNode() throws Exception {
final Assigner assigner = context.mock(Assigner.class);
final Hive hive = Hive.load(getHive().getUri(), (HiveDataSourceProvider) getHive().getDataSourceProvider(), assigner);
context.checking(new Expectations() {
{
exactly(2).of(assigner).chooseNode(with(any(Collection.class)), with(anything()));
will(onConsecutiveCalls(returnValue(hive.getNode(1)), returnValue(hive.getNode(2))));
}
});
String asia = "Asia";
hive.directory().insertPrimaryIndexKey(asia);
hive.directory().insertPrimaryIndexKey(asia);
context.assertIsSatisfied(); //asserts that this is no longer probabalistic
Session session = null;
try {
session = factory.openSession(asia);
Collection<Integer> nodeIds = hive.directory().getNodeIdsOfPrimaryIndexKey(asia);
assertEquals(2, nodeIds.size());
Node node = getNodeForFirstId(hive, nodeIds);
assertCorrectNode(session, node);
fail("No exception thrown");
} catch (IllegalStateException e) {
} finally {
if (session != null)
session.close();
}
}
private Node getNodeForFirstId(Hive hive, Collection<Integer> nodes) throws Exception {
return hive.getNode(Atom.getFirst(nodes));
}
@SuppressWarnings("deprecation")
public void assertCorrectNode(Session session, Node node) throws Exception {
assertTrue("Opened a session to the wrong node", node.getUri().startsWith(session.connection().getMetaData().getURL()));
}
}