package io.dropwizard.hibernate;
import com.codahale.metrics.MetricRegistry;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import io.dropwizard.db.DataSourceFactory;
import io.dropwizard.lifecycle.setup.LifecycleEnvironment;
import io.dropwizard.logging.BootstrapLogging;
import io.dropwizard.setup.Environment;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import java.util.Map;
import java.util.UUID;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class UnitOfWorkAwareProxyFactoryTest {
static {
BootstrapLogging.bootstrap();
}
private SessionFactory sessionFactory;
@Rule
public ExpectedException thrown = ExpectedException.none();
@Before
public void setUp() throws Exception {
final HibernateBundle<?> bundle = mock(HibernateBundle.class);
final Environment environment = mock(Environment.class);
when(environment.lifecycle()).thenReturn(mock(LifecycleEnvironment.class));
when(environment.metrics()).thenReturn(new MetricRegistry());
final DataSourceFactory dataSourceFactory = new DataSourceFactory();
dataSourceFactory.setUrl("jdbc:hsqldb:mem:unit-of-work-" + UUID.randomUUID().toString());
dataSourceFactory.setUser("sa");
dataSourceFactory.setDriverClass("org.hsqldb.jdbcDriver");
dataSourceFactory.setValidationQuery("SELECT 1 FROM INFORMATION_SCHEMA.SYSTEM_USERS");
dataSourceFactory.setProperties(ImmutableMap.of("hibernate.dialect", "org.hibernate.dialect.HSQLDialect"));
dataSourceFactory.setInitialSize(1);
dataSourceFactory.setMinSize(1);
sessionFactory = new SessionFactoryFactory()
.build(bundle, environment, dataSourceFactory, ImmutableList.of());
try (Session session = sessionFactory.openSession()) {
Transaction transaction = session.beginTransaction();
session.createNativeQuery("create table user_sessions (token varchar(64) primary key, username varchar(16))")
.executeUpdate();
session.createNativeQuery("insert into user_sessions values ('67ab89d', 'jeff_28')")
.executeUpdate();
transaction.commit();
}
}
@Test
public void testProxyWorks() throws Exception {
final SessionDao sessionDao = new SessionDao(sessionFactory);
final UnitOfWorkAwareProxyFactory unitOfWorkAwareProxyFactory =
new UnitOfWorkAwareProxyFactory("default", sessionFactory);
final OAuthAuthenticator oAuthAuthenticator = unitOfWorkAwareProxyFactory
.create(OAuthAuthenticator.class, SessionDao.class, sessionDao);
assertThat(oAuthAuthenticator.authenticate("67ab89d")).isTrue();
assertThat(oAuthAuthenticator.authenticate("bd1e23a")).isFalse();
}
@Test
public void testProxyWorksWithoutUnitOfWork() {
assertThat(new UnitOfWorkAwareProxyFactory("default", sessionFactory)
.create(PlainAuthenticator.class)
.authenticate("c82d11e"))
.isTrue();
}
@Test
public void testProxyHandlesErrors() {
thrown.expect(IllegalStateException.class);
thrown.expectMessage("Session cluster is down");
new UnitOfWorkAwareProxyFactory("default", sessionFactory)
.create(BrokenAuthenticator.class)
.authenticate("b812ae4");
}
@Test
public void testNewAspect() {
final UnitOfWorkAwareProxyFactory unitOfWorkAwareProxyFactory =
new UnitOfWorkAwareProxyFactory("default", sessionFactory);
ImmutableMap<String, SessionFactory> sessionFactories = ImmutableMap.of("default", sessionFactory);
UnitOfWorkAspect aspect1 = unitOfWorkAwareProxyFactory.newAspect(sessionFactories);
UnitOfWorkAspect aspect2 = unitOfWorkAwareProxyFactory.newAspect(sessionFactories);
assertThat(aspect1).isNotSameAs(aspect2);
}
@Test
public void testCanBeConfiguredWithACustomAspect() {
final SessionDao sessionDao = new SessionDao(sessionFactory);
final UnitOfWorkAwareProxyFactory unitOfWorkAwareProxyFactory =
new UnitOfWorkAwareProxyFactory("default", sessionFactory) {
@Override
public UnitOfWorkAspect newAspect(ImmutableMap<String, SessionFactory> sessionFactories) {
return new CustomAspect(sessionFactories);
}
};
final OAuthAuthenticator oAuthAuthenticator = unitOfWorkAwareProxyFactory
.create(OAuthAuthenticator.class, SessionDao.class, sessionDao);
assertThat(oAuthAuthenticator.authenticate("gr6f9y0")).isTrue();
}
static class SessionDao {
private SessionFactory sessionFactory;
public SessionDao(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public boolean isExist(String token) {
return sessionFactory.getCurrentSession()
.createNativeQuery("select username from user_sessions where token=:token")
.setParameter("token", token)
.list()
.size() > 0;
}
}
static class OAuthAuthenticator {
private SessionDao sessionDao;
public OAuthAuthenticator(SessionDao sessionDao) {
this.sessionDao = sessionDao;
}
@UnitOfWork
public boolean authenticate(String token) {
return sessionDao.isExist(token);
}
}
static class PlainAuthenticator {
public boolean authenticate(String token) {
return true;
}
}
static class BrokenAuthenticator {
@UnitOfWork
public boolean authenticate(String token) {
throw new IllegalStateException("Session cluster is down");
}
}
static class CustomAspect extends UnitOfWorkAspect {
public CustomAspect(Map<String, SessionFactory> sessionFactories) {
super(sessionFactories);
}
@Override
protected void configureSession() {
super.configureSession();
Transaction transaction = getSession().beginTransaction();
getSession().createNativeQuery("insert into user_sessions values ('gr6f9y0', 'jeff_29')")
.executeUpdate();
transaction.commit();
}
}
}