I thought I had fixed the problem temporarily, but it turns out I am still having problems.
I am trying to create some specs2 tests for my models layer, I would like to insert some dummy object, and then run some queries to make sure data comes out as expected. Here is what my simple test looks like:
class ModelSpec extends Specification { override def is = args(sequential = true) ^ super.is object FakeApp extends FakeApplication() running(FakeApp){ println("set up database") val newUser = User( email = "wfbarksdale@gmail.com", username = "weezybizzle", password = "nutterbutter") User.save(newUser) } running(FakeApp) { "User Model" should { "be created and retrieved by username" in { println("finding someone") User.findOneByUsername("weezybizzle") must beSome } "not find non existant user" in { println("finding nobody") User.findOneByUsername("nobody") must beNone } } } }
And here is the stack trace I get from the unit tests:
[info] Compiling 1 Scala source to /www/mojulo3/target/scala-2.9.1/test-classes... set up database finding someone finding nobody [info] ModelSpec [info] [info] User Model should [error] ! be created and retrieved by username [error] IllegalStateException: this Mongo has been closed (DBTCPConnector.java:123) [error] com.mongodb.DBTCPConnector._checkClosed(DBTCPConnector.java:123) [error] com.mongodb.DBTCPConnector.call(DBTCPConnector.java:207) [error] com.mongodb.DBApiLayer$MyCollection.__find(DBApiLayer.java:313) [error] com.mongodb.DBApiLayer$MyCollection.__find(DBApiLayer.java:298) [error] com.mongodb.DBCollection.findOne(DBCollection.java:682) [error] com.mongodb.DBCollection.findOne(DBCollection.java:661) [error] com.mongodb.casbah.MongoCollectionBase$class.findOne(MongoCollection.scala:225) [error] com.mongodb.casbah.MongoCollection.findOne(MongoCollection.scala:897) [error] com.novus.salat.dao.SalatDAO.findOne(SalatDAO.scala:311) [error] models.User$.findOneByUsername(User.scala:24) [error] test.ModelSpec$$anonfun$3$$anonfun$apply$1$$anonfun$apply$2$$anonfun$apply$3.apply(ModelSpec.scala:29) [error] test.ModelSpec$$anonfun$3$$anonfun$apply$1$$anonfun$apply$2$$anonfun$apply$3.apply(ModelSpec.scala:29) [error] test.ModelSpec$$anonfun$3$$anonfun$apply$1$$anonfun$apply$2.apply(ModelSpec.scala:29) [error] test.ModelSpec$$anonfun$3$$anonfun$apply$1$$anonfun$apply$2.apply(ModelSpec.scala:27) [error] ! not find non existant user [error] IllegalStateException: this Mongo has been closed (DBTCPConnector.java:123) [error] com.mongodb.DBTCPConnector._checkClosed(DBTCPConnector.java:123) [error] com.mongodb.DBTCPConnector.call(DBTCPConnector.java:207) [error] com.mongodb.DBApiLayer$MyCollection.__find(DBApiLayer.java:313) [error] com.mongodb.DBApiLayer$MyCollection.__find(DBApiLayer.java:298) [error] com.mongodb.DBCollection.findOne(DBCollection.java:682) [error] com.mongodb.DBCollection.findOne(DBCollection.java:661) [error] com.mongodb.casbah.MongoCollectionBase$class.findOne(MongoCollection.scala:225) [error] com.mongodb.casbah.MongoCollection.findOne(MongoCollection.scala:897) [error] com.novus.salat.dao.SalatDAO.findOne(SalatDAO.scala:311) [error] models.User$.findOneByUsername(User.scala:24) [error] test.ModelSpec$$anonfun$3$$anonfun$apply$1$$anonfun$apply$6$$anonfun$apply$7.apply(ModelSpec.scala:35) [error] test.ModelSpec$$anonfun$3$$anonfun$apply$1$$anonfun$apply$6$$anonfun$apply$7.apply(ModelSpec.scala:35) [error] test.ModelSpec$$anonfun$3$$anonfun$apply$1$$anonfun$apply$6.apply(ModelSpec.scala:35) [error] test.ModelSpec$$anonfun$3$$anonfun$apply$1$$anonfun$apply$6.apply(ModelSpec.scala:33) [info] [info] [info] Total for specification ModelSpec [info] Finished in 20 ms [info] 2 examples, 0 failure, 2 errors [info] [error] Error: Total 2, Failed 0, Errors 2, Passed 0, Skipped 0 [error] Error during tests: [error] test.ModelSpec [error] {file:/www/mojulo3/}mojulo3/test:test: Tests unsuccessful [error] Total time: 4 s, completed Aug 28, 2012 10:02:33 PM
It looks like the FakeApp is somehow disconnecting from the database, and not reconnecting. I looked into the Play source, and it seems that the application will be stopped and restarted, regardless of whether or not it is actually the same object. I am thinking that the issue may be stemming from the salat onStop()
method or onStart()
but I am not really sure.
I have been struggling for a while with this, any help, even just on how to reason about the problem, would be greatly appreciated.
There are 2 phases in executing a specs2 Specification: first the specification is created, with all its examples. Then it is executed.
What you should do instead is:
I hope that helps.
I've changed the implementation of how play-salat closes it's connections.
Usually it's a good thing closing down all the connections when the app stops, because the plugin will be re instantiated when the app starts again.
The problem was I was creating the mongodb connection in a lazy val which created the connection once, and when the app stopped it simply calls .close() on it.
What I've done to fix it is that the connection is now closed and if you ask for the connection again it creates a new one and passes it to you.
This is all available in the 1.1-SNAPSHOT version of play-salat which you can use straight away by adding
This release also includes salat 1.9.1 and support for capped collections and gridfs :)
Try it out and give me a shout if anything doesn't work as expected.
If everything looks good, I'll release the final 1.1 soon.
This is because it closes the MongoDB connection in the plugin's onStop method. I've submitted a pull request so that this doesn't happen during testing:
https://github.com/leon/play-salat/pull/27