package org.jooby.requery; import static org.easymock.EasyMock.eq; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.isA; import static org.junit.Assert.assertEquals; import java.sql.Statement; import java.util.Set; import java.util.function.Consumer; import javax.inject.Provider; import javax.sql.CommonDataSource; import javax.sql.DataSource; import org.jooby.Env; import org.jooby.Env.ServiceKey; import org.jooby.Registry; import org.jooby.test.MockUnit; import org.jooby.test.MockUnit.Block; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import com.google.common.collect.ImmutableSet; import com.google.inject.Binder; import com.google.inject.Key; import com.google.inject.binder.LinkedBindingBuilder; import com.google.inject.util.Types; import com.typesafe.config.Config; import io.requery.EntityStore; import io.requery.Persistable; import io.requery.TransactionIsolation; import io.requery.TransactionListener; import io.requery.async.CompletableEntityStore; import io.requery.async.CompletionStageEntityStore; import io.requery.meta.EntityModel; import io.requery.meta.Type; import io.requery.reactivex.ReactiveEntityStore; import io.requery.reactivex.ReactiveSupport; import io.requery.reactor.ReactorEntityStore; import io.requery.sql.BoundParameters; import io.requery.sql.Configuration; import io.requery.sql.ConfigurationBuilder; import io.requery.sql.EntityDataStore; import io.requery.sql.EntityStateListener; import io.requery.sql.SchemaModifier; import io.requery.sql.StatementListener; import io.requery.sql.TableCreationMode; import io.requery.util.function.Supplier; import javaslang.control.Try.CheckedConsumer; @RunWith(PowerMockRunner.class) @PrepareForTest({Requery.class, ConfigurationBuilder.class, EntityDataStore.class, SchemaModifier.class, ReactiveSupport.class }) public class RequeryTest { public static class Person implements Persistable { } private Block keys = unit -> { ServiceKey keys = unit.mock(Env.ServiceKey.class); unit.registerMock(Env.ServiceKey.class, keys); Env env = unit.get(Env.class); expect(env.serviceKey()).andReturn(keys); }; private Block zeroModels = unit -> { EntityModel model = unit.get(EntityModel.class); expect(model.getName()).andReturn("DEFAULT"); expect(model.getTypes()).andReturn(ImmutableSet.of()); }; @SuppressWarnings("unchecked") private Block onStart = unit -> { Env env = unit.get(Env.class); expect(env.onStart(unit.capture(CheckedConsumer.class))).andReturn(null); }; private Block configurationBuilder = unit -> { Configuration conf = unit.mock(Configuration.class); unit.registerMock(Configuration.class, conf); ConfigurationBuilder cb = unit.constructor(ConfigurationBuilder.class) .args(CommonDataSource.class, EntityModel.class) .build(unit.get(DataSource.class), unit.get(EntityModel.class)); unit.registerMock(ConfigurationBuilder.class, cb); expect(cb.build()).andReturn(conf); }; private Block eds = unit -> { Configuration conf = unit.get(Configuration.class); @SuppressWarnings("rawtypes") EntityDataStore eds = unit.constructor(EntityDataStore.class) .args(Configuration.class) .build(conf); unit.registerMock(EntityDataStore.class, eds); }; private Block noSchema = unit -> { Config conf = unit.get(Config.class); expect(conf.hasPath("requery.schema")).andReturn(false); }; @Test public void newModule() throws Exception { new MockUnit(Env.class, Config.class, Binder.class, EntityModel.class) .expect(keys) .expect(zeroModels) .expect(store(EntityStore.class, "DEFAULT")) .expect(onStart) .run(unit -> { new Requery(unit.get(EntityModel.class)) .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); }); } @SuppressWarnings("unchecked") @Test public void shouldBindDataSource() throws Exception { new MockUnit(Env.class, Config.class, Binder.class, EntityModel.class, Registry.class, DataSource.class) .expect(keys) .expect(zeroModels).expect(noSchema) .expect(store(EntityStore.class, "DEFAULT")) .expect(onStart) .expect(dataSource(Key.get(DataSource.class))) .expect(configurationBuilder) .expect(eds) .run(unit -> { new Requery(unit.get(EntityModel.class)) .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); }, unit -> { unit.captured(CheckedConsumer.class).iterator().next() .accept(unit.get(Registry.class)); }); } @SuppressWarnings("unchecked") @Test public void shouldBindDataSouxrce() throws Exception { new MockUnit(Env.class, Config.class, Binder.class, EntityModel.class, Registry.class, DataSource.class) .expect(keys) .expect(zeroModels).expect(noSchema) .expect(store(EntityStore.class, "DEFAULT")) .expect(onStart) .expect(dataSource(Key.get(DataSource.class))) .expect(configurationBuilder) .expect(eds) .run(unit -> { new Requery(unit.get(EntityModel.class)) .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); }, unit -> { unit.captured(CheckedConsumer.class).iterator().next() .accept(unit.get(Registry.class)); }); } @SuppressWarnings("unchecked") @Test public void shouldBindCustomDataSouxrce() throws Exception { new MockUnit(Env.class, Config.class, Binder.class, EntityModel.class, Registry.class, DataSource.class) .expect(keys) .expect(zeroModels).expect(noSchema) .expect(store(EntityStore.class, "DEFAULT")) .expect(onStart) .expect(configurationBuilder) .expect(eds) .run(unit -> { new Requery(unit.get(EntityModel.class)) .dataSource(() -> unit.get(DataSource.class)) .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); }, unit -> { unit.captured(CheckedConsumer.class).iterator().next() .accept(unit.get(Registry.class)); }); } @SuppressWarnings("unchecked") @Test public void reactiveStore() throws Exception { new MockUnit(Env.class, Config.class, Binder.class, EntityModel.class, Registry.class, DataSource.class) .expect(keys) .expect(zeroModels).expect(noSchema) .expect(store(ReactiveEntityStore.class, "DEFAULT")) .expect(onStart) .expect(dataSource(Key.get(DataSource.class))) .expect(configurationBuilder) .expect(eds) .expect(unit -> { unit.mockStatic(ReactiveSupport.class); expect(ReactiveSupport.toReactiveStore(unit.get(EntityDataStore.class))) .andReturn(null); }) .run(unit -> { Requery.reactive(unit.get(EntityModel.class)) .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); }, unit -> { unit.captured(CheckedConsumer.class).iterator().next() .accept(unit.get(Registry.class)); }); } @SuppressWarnings("unchecked") @Test public void reactorStore() throws Exception { new MockUnit(Env.class, Config.class, Binder.class, EntityModel.class, Registry.class, DataSource.class) .expect(keys) .expect(zeroModels).expect(noSchema) .expect(store(ReactorEntityStore.class, "DEFAULT")) .expect(onStart) .expect(dataSource(Key.get(DataSource.class))) .expect(configurationBuilder) .expect(eds) .expect(unit -> { unit.constructor(ReactorEntityStore.class) .build(unit.get(EntityDataStore.class)); }) .run(unit -> { Requery.reactor(unit.get(EntityModel.class)) .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); }, unit -> { unit.captured(CheckedConsumer.class).iterator().next() .accept(unit.get(Registry.class)); }); } @SuppressWarnings("unchecked") @Test public void completableEntityStore() throws Exception { new MockUnit(Env.class, Config.class, Binder.class, EntityModel.class, Registry.class, DataSource.class) .expect(keys) .expect(zeroModels).expect(noSchema) .expect(store(CompletionStageEntityStore.class, "DEFAULT")) .expect(onStart) .expect(dataSource(Key.get(DataSource.class))) .expect(configurationBuilder) .expect(eds) .expect(unit -> { unit.constructor(CompletableEntityStore.class) .build(unit.get(EntityDataStore.class)); }) .run(unit -> { Requery.completionStage(unit.get(EntityModel.class)) .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); }, unit -> { unit.captured(CheckedConsumer.class).iterator().next() .accept(unit.get(Registry.class)); }); } @SuppressWarnings("unchecked") @Test public void shouldInvokeConfigurerCallback() throws Exception { new MockUnit(Env.class, Config.class, Binder.class, EntityModel.class, Registry.class, DataSource.class) .expect(keys) .expect(zeroModels).expect(noSchema) .expect(store(EntityStore.class, "DEFAULT")) .expect(onStart) .expect(dataSource(Key.get(DataSource.class))) .expect(configurationBuilder) .expect(eds) .expect(unit -> { ConfigurationBuilder builder = unit.get(ConfigurationBuilder.class); expect(builder.useDefaultLogging()).andReturn(builder); }) .run(unit -> { new Requery(unit.get(EntityModel.class)) .doWith(builder -> { builder.useDefaultLogging(); }) .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); }, unit -> { unit.captured(CheckedConsumer.class).iterator().next() .accept(unit.get(Registry.class)); }); } @SuppressWarnings("unchecked") @Test public void shouldSetupEntityStateListener() throws Exception { class MyListener implements EntityStateListener<Object> { @Override public void postLoad(final Object entity) { } @Override public void postInsert(final Object entity) { } @Override public void postDelete(final Object entity) { } @Override public void postUpdate(final Object entity) { } @Override public void preInsert(final Object entity) { } @Override public void preDelete(final Object entity) { } @Override public void preUpdate(final Object entity) { } } MyListener listener = new MyListener(); new MockUnit(Env.class, Config.class, Binder.class, EntityModel.class, Registry.class, DataSource.class) .expect(keys) .expect(zeroModels).expect(noSchema) .expect(store(EntityStore.class, "DEFAULT")) .expect(onStart) .expect(dataSource(Key.get(DataSource.class))) .expect(configurationBuilder) .expect(eds) .expect(unit -> { ConfigurationBuilder builder = unit.get(ConfigurationBuilder.class); expect(builder.addEntityStateListener(listener)).andReturn(builder); Registry registry = unit.get(Registry.class); expect(registry.require(MyListener.class)).andReturn(listener); }) .run(unit -> { new Requery(unit.get(EntityModel.class)) .entityStateListener(MyListener.class) .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); }, unit -> { unit.captured(CheckedConsumer.class).iterator().next() .accept(unit.get(Registry.class)); }); } @SuppressWarnings("unchecked") @Test public void shouldSetupStatementListener() throws Exception { class MyListener implements StatementListener { @Override public void beforeExecuteUpdate(final Statement statement, final String sql, final BoundParameters parameters) { } @Override public void afterExecuteUpdate(final Statement statement, final int count) { } @Override public void beforeExecuteBatchUpdate(final Statement statement, final String sql) { } @Override public void afterExecuteBatchUpdate(final Statement statement, final int[] count) { } @Override public void beforeExecuteQuery(final Statement statement, final String sql, final BoundParameters parameters) { } @Override public void afterExecuteQuery(final Statement statement) { } } MyListener listener = new MyListener(); new MockUnit(Env.class, Config.class, Binder.class, EntityModel.class, Registry.class, DataSource.class) .expect(keys) .expect(zeroModels).expect(noSchema) .expect(store(EntityStore.class, "DEFAULT")) .expect(onStart) .expect(dataSource(Key.get(DataSource.class))) .expect(configurationBuilder) .expect(eds) .expect(unit -> { ConfigurationBuilder builder = unit.get(ConfigurationBuilder.class); expect(builder.addStatementListener(listener)).andReturn(builder); Registry registry = unit.get(Registry.class); expect(registry.require(MyListener.class)).andReturn(listener); }) .run(unit -> { new Requery(unit.get(EntityModel.class)) .statementListener(MyListener.class) .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); }, unit -> { unit.captured(CheckedConsumer.class).iterator().next() .accept(unit.get(Registry.class)); }); } @SuppressWarnings("unchecked") @Test public void shouldSetupTransactionLister() throws Exception { class MyListener implements TransactionListener { @Override public void beforeBegin(final TransactionIsolation isolation) { } @Override public void afterBegin(final TransactionIsolation isolation) { } @Override public void beforeCommit(final Set<Type<?>> types) { } @Override public void afterCommit(final Set<Type<?>> types) { } @Override public void beforeRollback(final Set<Type<?>> types) { } @Override public void afterRollback(final Set<Type<?>> types) { } } MyListener listener = new MyListener(); new MockUnit(Env.class, Config.class, Binder.class, EntityModel.class, Registry.class, DataSource.class) .expect(keys) .expect(zeroModels).expect(noSchema) .expect(store(EntityStore.class, "DEFAULT")) .expect(onStart) .expect(dataSource(Key.get(DataSource.class))) .expect(configurationBuilder) .expect(eds) .expect(unit -> { ConfigurationBuilder builder = unit.get(ConfigurationBuilder.class); expect(builder.addTransactionListenerFactory(unit.capture(Supplier.class))) .andReturn(builder); Registry registry = unit.get(Registry.class); expect(registry.require(MyListener.class)).andReturn(listener); }) .run(unit -> { new Requery(unit.get(EntityModel.class)) .transactionListener(MyListener.class) .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); }, unit -> { unit.captured(CheckedConsumer.class).iterator().next() .accept(unit.get(Registry.class)); assertEquals(listener, unit.captured(Supplier.class).iterator().next().get()); }); } @SuppressWarnings("unchecked") @Test public void shouldCreateSchema() throws Exception { new MockUnit(Env.class, Config.class, Binder.class, EntityModel.class, Registry.class, DataSource.class) .expect(keys) .expect(zeroModels).expect(noSchema) .expect(store(EntityStore.class, "DEFAULT")) .expect(onStart) .expect(dataSource(Key.get(DataSource.class))) .expect(configurationBuilder) .expect(eds) .expect(unit -> { SchemaModifier schema = unit.constructor(SchemaModifier.class) .args(DataSource.class, EntityModel.class) .build(unit.get(DataSource.class), unit.get(EntityModel.class)); schema.createTables(TableCreationMode.CREATE_NOT_EXISTS); }) .run(unit -> { new Requery(unit.get(EntityModel.class)) .schema(TableCreationMode.CREATE_NOT_EXISTS) .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); }, unit -> { unit.captured(CheckedConsumer.class).iterator().next() .accept(unit.get(Registry.class)); }); } @SuppressWarnings("unchecked") @Test public void shouldCreateSchemaFromProperty() throws Exception { new MockUnit(Env.class, Config.class, Binder.class, EntityModel.class, Registry.class, DataSource.class) .expect(keys) .expect(zeroModels) .expect(store(EntityStore.class, "DEFAULT")) .expect(onStart) .expect(dataSource(Key.get(DataSource.class))) .expect(configurationBuilder) .expect(eds) .expect(unit -> { Config conf = unit.get(Config.class); expect(conf.hasPath("requery.schema")).andReturn(true); expect(conf.getString("requery.schema")).andReturn("DROP_CREATE"); }) .expect(unit -> { SchemaModifier schema = unit.constructor(SchemaModifier.class) .args(DataSource.class, EntityModel.class) .build(unit.get(DataSource.class), unit.get(EntityModel.class)); schema.createTables(TableCreationMode.DROP_CREATE); }) .run(unit -> { new Requery(unit.get(EntityModel.class)) .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); }, unit -> { unit.captured(CheckedConsumer.class).iterator().next() .accept(unit.get(Registry.class)); }); } @Test @SuppressWarnings({"rawtypes", "unchecked" }) public void newModuleWithTypes() throws Exception { new MockUnit(Env.class, Config.class, Binder.class, EntityModel.class) .expect(keys) .expect(unit -> { Type type = unit.mock(Type.class); expect(type.getClassType()).andReturn(Person.class); LinkedBindingBuilder lbb = unit.mock(LinkedBindingBuilder.class); expect(lbb.toProvider(isA(Provider.class))).andReturn(lbb); Binder binder = unit.get(Binder.class); expect(binder.bind(Key .get(Types.newParameterizedType(EntityStore.class, Persistable.class, Person.class)))) .andReturn(lbb); EntityModel model = unit.get(EntityModel.class); expect(model.getName()).andReturn("foo"); expect(model.getTypes()).andReturn(ImmutableSet.of(type)); }) .expect(store(EntityStore.class, "foo")) .expect(onStart) .run(unit -> { new Requery(unit.get(EntityModel.class)) .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); }); } @SuppressWarnings({"rawtypes", "unchecked" }) @Test public void bindEntityStore() throws Exception { Key k = Key.get(Object.class); new MockUnit(Env.class, Config.class, Binder.class, EntityModel.class) .expect(keys) .expect(zeroModels) .expect(store(EntityStore.class, "DEFAULT")) .expect(onStart) .expect(unit -> { LinkedBindingBuilder lbb = unit.mock(LinkedBindingBuilder.class); expect(lbb.toProvider(isA(Provider.class))).andReturn(lbb); Binder binder = unit.get(Binder.class); expect(binder.bind(k)).andReturn(lbb); }) .run(unit -> { new Requery(unit.get(EntityModel.class)) .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); }, unit -> { unit.captured(Consumer.class).iterator().next().accept(k); }); } @SuppressWarnings({"unchecked", "rawtypes" }) private Block store(final Class<? extends EntityStore> storeType, final String db) { return unit -> { Env.ServiceKey keys = unit.get(Env.ServiceKey.class); keys.generate(eq(storeType), eq(db), unit.capture(Consumer.class)); }; } private Block dataSource(final Key<DataSource> dbkey) { return unit -> { DataSource ds = unit.get(DataSource.class); Registry registry = unit.get(Registry.class); expect(registry.require(DataSource.class)).andReturn(ds); }; } }