package org.jooby.jooq;
import static com.typesafe.config.ConfigValueFactory.fromAnyRef;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.isA;
import static org.junit.Assert.assertEquals;
import java.util.Properties;
import javax.inject.Provider;
import javax.sql.DataSource;
import org.jooby.Env;
import org.jooby.test.MockUnit;
import org.jooby.test.MockUnit.Block;
import org.jooq.Configuration;
import org.jooq.ConnectionProvider;
import org.jooq.DSLContext;
import org.jooq.SQLDialect;
import org.jooq.impl.DSL;
import org.jooq.impl.DataSourceConnectionProvider;
import org.jooq.impl.DefaultConfiguration;
import org.jooq.impl.DefaultTransactionProvider;
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.inject.Binder;
import com.google.inject.Key;
import com.google.inject.binder.AnnotatedBindingBuilder;
import com.google.inject.name.Names;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigValueFactory;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import javaslang.control.Try.CheckedRunnable;
@RunWith(PowerMockRunner.class)
@PrepareForTest({jOOQ.class, DefaultConfiguration.class, DSL.class,
DataSourceConnectionProvider.class, DefaultTransactionProvider.class })
public class jOOQTest {
@SuppressWarnings("unchecked")
private MockUnit.Block configuration = unit -> {
DataSourceConnectionProvider dscp = unit.constructor(DataSourceConnectionProvider.class)
.build(unit.get(HikariDataSource.class));
DefaultTransactionProvider trx = unit.constructor(DefaultTransactionProvider.class)
.args(ConnectionProvider.class)
.build(dscp);
DefaultConfiguration conf = unit.constructor(DefaultConfiguration.class)
.build();
expect(conf.set(dscp)).andReturn(conf);
expect(conf.set(trx)).andReturn(conf);
expect(conf.set(SQLDialect.H2)).andReturn(conf);
unit.registerMock(Configuration.class, conf);
AnnotatedBindingBuilder<Configuration> abbC = unit.mock(AnnotatedBindingBuilder.class);
abbC.toInstance(conf);
abbC.toInstance(conf);
Binder binder = unit.get(Binder.class);
expect(binder.bind(Key.get(Configuration.class))).andReturn(abbC);
expect(binder.bind(Key.get(Configuration.class, Names.named("jdbctest")))).andReturn(abbC);
};
@SuppressWarnings("unchecked")
private MockUnit.Block ctx = unit -> {
DSLContext dslcontext = unit.mock(DSLContext.class);
Configuration conf = unit.get(Configuration.class);
unit.mockStatic(DSL.class);
expect(DSL.using(conf)).andReturn(dslcontext);
AnnotatedBindingBuilder<DSLContext> abbC = unit.mock(AnnotatedBindingBuilder.class);
expect(abbC.toProvider(isA(Provider.class))).andReturn(abbC);
expect(abbC.toProvider(unit.capture(Provider.class))).andReturn(abbC);
Binder binder = unit.get(Binder.class);
expect(binder.bind(Key.get(DSLContext.class))).andReturn(abbC);
expect(binder.bind(Key.get(DSLContext.class, Names.named("jdbctest")))).andReturn(abbC);
};
private MockUnit.Block onStop = unit -> {
Env env = unit.get(Env.class);
expect(env.onStop(isA(CheckedRunnable.class))).andReturn(env);
};
@Test
public void defaults() throws Exception {
String url = "jdbc:h2:target/jdbctest";
new MockUnit(Env.class, Config.class, Binder.class)
.expect(props("org.h2.jdbcx.JdbcDataSource", url, "h2.jdbctest",
"sa", "", false))
.expect(hikariConfig())
.expect(hikariDataSource(url))
.expect(serviceKey("jdbctest"))
.expect(configuration)
.expect(ctx)
.expect(onStop)
.run(unit -> {
new jOOQ()
.configure(unit.get(Env.class), config(), unit.get(Binder.class));
}, unit -> {
unit.captured(Provider.class).iterator().next().get();
});
}
@Test
public void withDbProp() throws Exception {
String url = "jdbc:h2:target/jdbctest";
new MockUnit(Env.class, Config.class, Binder.class)
.expect(props("org.h2.jdbcx.JdbcDataSource", url, "h2.jdbctest",
"sa", "", false))
.expect(hikariConfig())
.expect(hikariDataSource(url))
.expect(serviceKey("jdbctest"))
.expect(configuration)
.expect(ctx)
.expect(onStop)
.run(unit -> {
new jOOQ("db")
.configure(unit.get(Env.class), config(), unit.get(Binder.class));
}, unit -> {
unit.captured(Provider.class).iterator().next().get();
});
}
@Test
public void doWith() throws Exception {
String url = "jdbc:h2:target/jdbctest";
new MockUnit(Env.class, Config.class, Binder.class)
.expect(props("org.h2.jdbcx.JdbcDataSource", url, "h2.jdbctest",
"sa", "", false))
.expect(hikariConfig())
.expect(hikariDataSource(url))
.expect(serviceKey("jdbctest"))
.expect(configuration)
.expect(ctx)
.expect(onStop)
.run(unit -> {
new jOOQ()
.doWith((final Configuration c) -> assertEquals(unit.get(Configuration.class), c))
.configure(unit.get(Env.class), config(), unit.get(Binder.class));
}, unit -> {
unit.captured(Provider.class).iterator().next().get();
});
}
private Config config() {
return new jOOQ().config()
.withValue("db", ConfigValueFactory.fromAnyRef("fs"))
.withValue("application.ns", ConfigValueFactory.fromAnyRef("my.model"))
.withValue("application.tmpdir", ConfigValueFactory.fromAnyRef("target"))
.withValue("application.name", ConfigValueFactory.fromAnyRef("jdbctest"))
.withValue("application.charset", ConfigValueFactory.fromAnyRef("UTF-8"))
.withValue("runtime.processors-x2", fromAnyRef("4"))
.resolve();
}
@SuppressWarnings("unchecked")
private Block serviceKey(final String db) {
return unit -> {
Env env = unit.get(Env.class);
expect(env.serviceKey()).andReturn(new Env.ServiceKey()).times(2);
AnnotatedBindingBuilder<DataSource> binding = unit.mock(AnnotatedBindingBuilder.class);
binding.toInstance(unit.get(HikariDataSource.class));
binding.toInstance(unit.get(HikariDataSource.class));
Binder binder = unit.get(Binder.class);
expect(binder.bind(Key.get(DataSource.class))).andReturn(binding);
expect(binder.bind(Key.get(DataSource.class, Names.named(db)))).andReturn(binding);
};
}
private Block hikariConfig() {
return unit -> {
Properties properties = unit.get(Properties.class);
HikariConfig hikari = unit.constructor(HikariConfig.class)
.build(properties);
unit.registerMock(HikariConfig.class, hikari);
};
}
private Block hikariDataSource(final String url) {
return unit -> {
HikariConfig properties = unit.get(HikariConfig.class);
HikariDataSource hikari = unit.constructor(HikariDataSource.class)
.build(properties);
Properties props = unit.mock(Properties.class);
expect(props.getProperty("url")).andReturn(url);
expect(hikari.getDataSourceProperties()).andReturn(props);
unit.registerMock(HikariDataSource.class, hikari);
};
}
private Block props(final String dataSourceClassName, final String url, final String name,
final String username, final String password, final boolean hasDataSourceClassName) {
return unit -> {
Properties properties = unit.constructor(Properties.class)
.build();
expect(properties
.setProperty("dataSource.dataSourceClassName", dataSourceClassName))
.andReturn(null);
if (username != null) {
expect(properties
.setProperty("dataSource.user", username))
.andReturn(null);
expect(properties
.setProperty("dataSource.password", password))
.andReturn(null);
}
expect(properties
.setProperty("dataSource.url", url))
.andReturn(null);
if (hasDataSourceClassName) {
expect(properties.getProperty("dataSourceClassName")).andReturn(dataSourceClassName);
} else {
expect(properties.getProperty("dataSourceClassName")).andReturn(null);
expect(properties.getProperty("dataSource.dataSourceClassName"))
.andReturn(dataSourceClassName);
expect(properties.setProperty("dataSourceClassName", dataSourceClassName)).andReturn(null);
}
expect(properties.remove("dataSource.dataSourceClassName")).andReturn(dataSourceClassName);
expect(properties.setProperty("poolName", name)).andReturn(null);
expect(properties.setProperty("maximumPoolSize", "4")).andReturn(null);
unit.registerMock(Properties.class, properties);
};
}
}