Pool has been Shutdown (HikariDataSource) when testing - scala

After migrating an application to Play 2.4 and introducing dependency injection into the controller of the application, I'm getting "Pool has been Shutdown" when running unit tests. The affected tests are something like this:
#RunWith(classOf[JUnitRunner])
class ApplicationSpec extends Specification {
"Application" should {
"doSomething" in running(TestUtil.app) {
val myId = IdGen.newId("someone")
...
}
}
}
Where the IdGen class looks something like:
object IdGen {
def newId(name: String): ClientCredentials = {
DB.withTransaction("myDb") { implicit conn =>
...
}
}
}
The test fails on the DB.withTransaction() call with
[error] Pool has been shutdown (HikariDataSource.java:89)
[error] com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:89)
[error] play.api.db.DefaultDatabase.getConnection(Databases.scala:143)
[error] play.api.db.DefaultDatabase.withConnection(Databases.scala:153)
[error] play.api.db.DefaultDatabase.withTransaction(Databases.scala:162)
[error] play.api.db.DB$.withTransaction(DB.scala:72)
[error] com.example.idGen$.newId...
I'm initializing TestUtil.app with
object TestUtil {
lazy val app = new GuiceApplicationBuilder()
.configure(defaultConfig ++ Helpers.inMemoryDatabase("myDB"))
.bindings(new TestModule) // Mock injections for test
.build
}
Clearly I'm missing something to get the database up and running for tests, but I'm unsure what.

Solved this.
Tried to replace lazy val with def, as answered in this question: Testing: FakeApplication ignoring additionalConfiguration
Which solved the problem.
Would love if someone could explain why?

This problem bit me because I was holding on to Application state in the code. Since tests typically each get their own FakeApplication, squireled-away state from one FakeApplication instance, when used in the context of another FakeApplication instance, will lead to problems. A concrete example is play.api.Play.current - this needs to be re-evaluated for each FakeApplication instance and shouldn't be held (after being evaluated only once) in your code.

Related

Play 2.5 Guice errors when compiling

I am currently in the process of migrating my app from Play 2.4 to Play 2.5 So far, it's been a massive pain.
Right now, I am trying to make my tests to pass.
I have one controller with some injected params
class UserLogin #Inject() (
loginService: UserLoginService,
authConfig: AuthConfig,
oAuthConfig: OAuthConfig,
env: PureEnvironment,
//stringResources: StringResources,
messagesApi: MessagesApi
) extends BaseController(messagesApi: MessagesApi) {
//endpoints
}
From the testing side, I have them defined to be injected with Guice
object IdentityManagerModuleMock extends AbstractModule with ScalaModule {
def configure: Unit = {
bind[PureEnvironment].toInstance(MockEnvironment)
val conf = Configuration.reference
val messagesApi = new DefaultMessagesApi(Environment.simple(), conf, new DefaultLangs(conf))
bind[MessagesApi].toInstance(messagesApi)
bind[AuthConfig].toInstance(
AuthConfig(
"https://localhost",
30,
3600,
86400,
Seq(InetAddress.getByName("127.0.0.1")),
Seq(InetAddress.getByName("127.0.0.1")),
"https://localhost/login"
)
)
bind[OAuthConfig].toInstance(oAuthConfigMock)
bind[UserLoginService].to[UserLoginServiceImpl]
}
val injector = Guice.createInjector(IdentityManagerModuleMock)
When I enable the routes in my routes file,
POST /login com.dummy.im.controllers.UserLogin.login
POST /reset com.dummy.im.controllers.UserLogin.reset
1) No implementation for com.dummy.im.components.UserLoginService was bound.
[info] while locating com.dummy.im.components.UserLoginService
[info] for parameter 0 at com.dummy.im.controllers.UserLogin.<init>(UserLogin.scala:24)
2) No implementation for com.dummy.platform.PureEnvironment was bound.
[info] while locating com.dummy.platform.PureEnvironment
[info] for parameter 3 at com.dummy.im.controllers.UserLogin.<init>(UserLogin.scala:24)
3) No implementation for scala.collection.Seq<java.net.InetAddress> was bound.
[info] while locating scala.collection.Seq<java.net.InetAddress>
[info] for parameter 4 at com.dummy.im.config.AuthConfig.<init>(AuthConfig.scala:13)
5) Could not find a suitable constructor in java.lang.Integer. Classes must have either one
(and only one) constructor annotated with #Inject or a zero-argument constructor that is not private.
[info] at java.lang.Integer.class(Integer.java:52)
[info] while locating java.lang.Integer
[info] for parameter 1 at com.dummy.im.config.AuthConfig.<init>(AuthConfig.scala:13)
The weird thing is that I have a very similar config for actual running the app, without the MessagesAPI (injected by Play, as far as I know) and those config objects which are read from the .conf file.
object IdentityManagerModule extends AbstractModule with ScalaModule {
def configure: Unit = {
bind[PureEnvironment].to[PlayProductionEnvironmentImpl]
bind[OauthRepository].to[OauthRepositoryImpl]
bind[UserLoginService].to[UserLoginServiceImpl]
}
}
And it runs just fine.
The main thing that I changed was to add the dependency to MessagesAPI in the controller.
I don't understand why Guice fails to see the things that are binded in IdentityManagerModuleMock.
Any ideas are more than welcomed. I have read and tried all I could think of for the past several days.
EDIT:
We have a custom app loader
class CustomApplicationLoader extends GuiceApplicationLoader() {
//config validation
override def builder(context: ApplicationLoader.Context): GuiceApplicationBuilder = {
val conf = context.initialConfiguration
initialBuilder
.in(context.environment)
.loadConfig(conf)
.overrides(overrides(context): _*)
.bindings(
MiscModule,
CommonConfigurationModule,
IdentityManagerConfigModule,
IdentityManagerModule,
ApplicationLifecycleModule
)
}
}
In the .conf file, it's used as
play.application.loader = "com.dummy.guice.CustomApplicationLoader"
It doesn't look like you need a custom application loader for what you're doing. If you disable the out of the box MessagesApi and then add your own modules through application.conf, that should mean you don't have to override MessagesApi.
https://www.playframework.com/documentation/2.5.x/ScalaPlayModules#Registration-Overrides
If you're running tests involving Guice, you can use WithApplication.
https://www.playframework.com/documentation/2.5.x/ScalaFunctionalTestingWithSpecs2#WithApplication
You shouldn't ever have to call Guice.createInjector directly, because WithApplication will call out to GuiceApplicationBuilder:
https://www.playframework.com/documentation/2.5.x/ScalaTestingWithGuice#GuiceApplicationBuilder
Check out the example projects: they all have "2.5.x" branches and most have tests integrated into them, and leverage them as a guide:
https://github.com/playframework?utf8=%E2%9C%93&q=examples&type=&language=

Injecting Play Application for a Slick Database Service

This is regarding a Play 2.3 application that I am trying to introduce Guice into.
I have the following legacy code to Guicify and I reached this point
class DatabaseService {
def db: Database = DB(play.api.Play.current)
//More code below.
}
This class is injected in the class under test, say com.TestA.
When I run the test cases using a modified OneAppPerTest setup, I see ProvisionExceptions of the following kind.
Error injecting constructor, java.lang.RuntimeException: There is no started application
Is it because of the use of play.api.Play.current?
How do I fix this issue?
Additional Info
The overridden OneAppPerTest variant, uses the following logic
override def newAppForTest(testData: TestData): FakeApplication = {
new FakeApplication(
additionalConfiguration = additionalConfiguration,
withGlobal = Some(globalSettings)
)
}
where additionalConfiguration can be overridden by actual tests and globalSettings is where Guice is introduced within the framework
protected def globalSettings = {
new TestGlobalSettings {
val injector = Guice.createInjector(overriddenModules: _*)
override def getControllerInstance[A](controllerClass: Class[A]): A = {
injector.getInstance(controllerClass)
}
override def getInjector = {
injector
}
}
}
There are other test cases with a similar setup that work perfectly fine. I am able to inject mocks, test the classes. However, every test with this DatabaseService class is failing, because I can't inject it cleanly.
The issue is related to how Guice creates the objects and when. DatabaseService here had access to the current application, the current configuration. However, in my Global.scala, I had it injected before 'onStart' was actually called.
This implies that we are trying to access an application before it was properly initialized.
Making DatabaseService injection in the test class lazy helped avoid the error.

Play framework GuiceApplicationBuilder not loading enabled module configs

I'm trying to test some actions. They require my security stuff which I've created using Silhouette.
I have a module to configure the DI for Silhouette in security.Module, and in my conf/application.conf file I have the line:
play.modules.enabled += "security.Module"
When I run my tests I get an error saying:
No implementation for com.mohiva.play.silhouette.api.Silhouette<security.JwtEnv> was bound.
If I set a breakpoint in my security.Module class, it's never triggered. However if I set a breakpoint in my main Module class it is. So I can see that my security.Module is never being loaded despite the docs for GuiceApplicationBuilder saying enabled modules are loaded automatically.
Here's how I'm configuring GuiceApplicationBuilder in my test class (based on scalatest):
class TestUserController extends PlaySpec with OneAppPerTest with Results {
val identity = UserDao(
id = Some(10),
email = Some("testuser#example.com"),
createdAt = DateTime.parse("2016-11-11T11:11:11")
)
val loginInfo = LoginInfo("credentials", identity.email.get)
implicit val env = FakeEnvironment[JwtEnv](Seq(loginInfo -> identity))
implicit override def newAppForTest(td: TestData) = new GuiceApplicationBuilder()
.overrides(bind[UsersBlockedRepo].to[MockUsersBlockedRepo])
.build
//...
}
What am I missing to get GuiceApplicationBuilder to load my security module?
I've fixed this. The problem was that my security.Module took constructor args:
class Module(environment: PlayEnvironment,
configuration: Configuration) extends AbstractModule with ScalaModule {...}
Removing those fixed it.

Intergation testing with play 2.5.4 and DI - play configuration won't load

I want to integration test an app by spinning up an in memory database. I had thought this might not be too tricky with the dependency injection:
class TreatySpec extends PlaySpec with OneAppPerSuite with Results {
val testConf = Configuration(ConfigFactory.load("test.conf"))
override lazy val app = new GuiceApplicationBuilder().in(Mode.Test).loadConfig(testConf).bindings(new TestModule()).build()
"Routes" should {
"404 on a bad request" in {
route(app, FakeRequest(GET, "/boum")).map(status(_)) mustBe Some(NOT_FOUND)
}
}
}
When executed, I get the following error:
[info] TreatySpec:
[info] Exception encountered when attempting to run a suite with class name: TreatySpec *** ABORTED ***
[info] com.typesafe.config.ConfigException$Missing: No configuration setting found for key 'slick.dbs.h2'
Here is my test.conf:
slick.dbs.h2.driver="slick.driver.H2Driver$"
slick.dbs.h2.db.driver="org.h2.Driver"
slick.dbs.h2.db.url="jdbc:h2:mem:test"
slick.dbs.h2.db.username=""
slick.dbs.h2.db.password=""
slick.dbs.h2 {
driver="slick.driver.H2Driver$"
db.driver="org.h2.Driver"
db.url="jdbc:h2:mem:spotRepo"
db.username=""
db.password=""
}
slick.dbs{
h2.driver="slick.driver.H2Driver$"
h2.driver="org.h2.Driver"
h2.url="jdbc:h2:mem:spotRepo"
h2.username=""
h2.password=""
}
I thought the Guice module was supposed to load the configuration? Whatever I do, there doesn't appear to be the relevant key in the config.
class TestModule extends AbstractModule {
override def configure() = {
// Use the system clock as the default implementation of Clock
bind(classOf[Clock]).toInstance(Clock.systemDefaultZone)
}
val dbConfigString = "slick.dbs.h2"
#Provides
val dbConfig : DatabaseConfig[JdbcProfile] = DatabaseConfig.forConfig[JdbcProfile](dbConfigString)
}
Can anyone point me in the right direction here? What am I doing wrong such that play refuses to load the configuration?

Fast test execution in a playframework fake application

Running tests as described here
"Spec" should {
"example" in new WithApplication {
...
}
}
is unacceptably slow for me. This is because new WithApplication is starting and stoping framework at every example. Don't get me wrong, a framework itself loads very fast, but if database is configured (surprise!), situation becomes terrible.
Here are some measurments:
"The database layer" should {
"test1" in {
1 must be equalTo(1)
}
...
"test20" in {
1 must be equalTo(1)
}
}
Execution time: 2 seconds. Same test with WithApplication at every example consumes 9 seconds
I was able to achive much better results thanks to this answer
import play.api.Play
import play.api.test.FakeApplication
import org.specs2.mutable.Specification
import scalikejdbc._
class MySpec extends Specification {
var fake: FakeApplication = _
step {fake = FakeApplication(...)}
step {Play.start(fake)}
"The database layer" should {
"some db test" in {
DB localTx { implicit session =>
...
}
}
"another db test" in {
DB localTx { implicit session =>
...
}
}
step {Play.stop()}
}
}
Pros: performance boost
Cons:
need to copy-paste setup and tear-down code because don't know how to
reuse it (by reuse I mean something like "class MySpec extends
Specification with NoWasteOfTime"
new WithApplication() calls Helpers.running which looks like this
synchronized {
try {
Play.start(fakeApp)
block
} finally {
Play.stop()
play.api.libs.ws.WS.resetClient()
}
}
so I can't completely emulate Helpers.running behaviour (resetClient is not visible for my code) without reflection.
Please suggest how to break cons or different approach how accomplish my issue.
I don't know if it is the best possible solution but in this thread:
Execute code before and after specification
You can read a solution for reusable code. I implemented it with little modifications. For me the beforeAll step did not run and added the sequential modifier.
import org.specs2.mutable._
import org.specs2.specification._
class PlayAppSpec extends Specification with BeforeAllAfterAll{
sequential
lazy val app : FakeApplication = {
FakeApplication()
}
def beforeAll(){
Play.start(app)
}
def afterAll(){
Play.stop()
}
}
import org.specs2.specification.Step
trait BeforeAllAfterAll extends Specification {
// see specs2 User Guide, linked below
override def map(fragments: =>Fragments) = {
beforeAll()
fragments ^ Step(afterAll)
}
def beforeAll()
def afterAll()
}
I think the map would be better with Step(...) ^ fragments ^ Step(...) but it did not run the beforeAll for me. The user guide at "Global setup/teardown" says to use a lazy val.
Overall it was a pain to set up this. My problem was
Exception in thread "Thread-145" java.net.SocketException: Connection reset
Or
Configuration error[Cannot connect to database [default]] (Configuration.scala:559)
When reusing the same FakeApplication:
SQLException: Attempting to obtain a connection from a pool that has already been shutdown.
I think it is much more logical this way than always creating a new application for every "in" block or adding all tests into one block.