embedmongo with reactivemongo process does not exit - mongodb

I am trying to do some tests using ScalaTest + embedmongo + reactivemongo but I fail. My first problem is that after a test mongod process does not shut down, I have this message in console:
INFO: stopOrDestroyProcess: process has not exited
and tests are paused till I kill the process manually. That happens even if body of my test is empty. I am running windows 8.1.
The other issue is, that when I try to connect to db inside test using reactive mongo and insert anything to db I get this exception:
reactivemongo.core.errors.ConnectionNotInitialized: MongoError['Connection is missing metadata (like protocol version, etc.) The connection pool is probably being initialized.']
I have literally no idea how to set it up. Here is my test code:
package model
import com.github.simplyscala.MongoEmbedDatabase
import org.scalatest.{OptionValues, Matchers, BeforeAndAfter, FlatSpec}
import reactivemongo.api.MongoDriver
import reactivemongo.api.collections.bson.BSONCollection
import scala.concurrent.duration._
import reactivemongo.bson.BSONDocument
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Await
class MongoBookingRepositoryTest extends FlatSpec
with Matchers
with OptionValues
with MongoEmbedDatabase
with BeforeAndAfter {
"A MongoBookingRepository" should "..." in withEmbedMongoFixture(port = 12345) { mongoProps =>
val driver = new MongoDriver
val connection = driver.connection("localhost:12345" :: Nil)
val db = connection("testDatabase")
val collection = db.collection[BSONCollection]("bookings")
val future = collection.insert(BSONDocument("a" -> 5))
println(Await.result(future, 3.seconds))
driver.close()
connection.close()
}
}

In play2.4 I tried as below and it worked.
dependencies:
"org.reactivemongo" %% "play2-reactivemongo" % "0.11.7.play24",
"org.reactivemongo" %% "reactivemongo-extensions-json" % "0.11.7.play24",
// test
"org.scalatest" %% "scalatest" % "2.2.4" % Test,
"de.flapdoodle.embed" % "de.flapdoodle.embed.mongo" % "1.50.0" % Test,
"org.mockito" % "mockito-core" % "1.10.19" % Test
TestMongoSetup:
import de.flapdoodle.embed.mongo.config.{Net, MongodConfigBuilder}
import de.flapdoodle.embed.mongo.distribution.Version
import de.flapdoodle.embed.mongo.{MongodStarter, MongodProcess, MongodExecutable}
import de.flapdoodle.embed.process.runtime.Network
import org.mockito.Mockito._
import play.modules.reactivemongo.ReactiveMongoApi
import reactivemongo.api.MongoConnection.ParsedURI
import reactivemongo.api.{MongoConnectionOptions, MongoDriver, MongoConnection}
import scala.concurrent.ExecutionContext
trait TestMongoSetup {
private var port : Int = _
private var mongodExe: MongodExecutable = _
private var mongodProcess: MongodProcess = _
def start(intiAtPort: Int): Unit = {
port=intiAtPort
mongodExe = MongodStarter.getDefaultInstance.prepare(
new MongodConfigBuilder()
.version(Version.Main.V3_0)
.net(new Net(port, Network.localhostIsIPv6()))
.build()
)
mongodProcess = mongodExe.start()
}
def stop(): Unit = {
mongodProcess.stop()
mongodExe.stop()
}
def createConnection(): MongoConnection = {
val driver = new MongoDriver
driver.connection(ParsedURI(
hosts = List(("localhost", port)),
options = MongoConnectionOptions(),
ignoredOptions = List.empty[String],
db = None,
authenticate = None
))
}
def createMockedReactiveMongoApi(dbName: String)(implicit ctx: ExecutionContext): ReactiveMongoApi = {
val connection = createConnection()
val db = connection(dbName)
val api = mock(classOf[ReactiveMongoApi])
doReturn(db).when(api).db
doReturn(connection).when(api).connection
api
}
}
TestClass:
import db.TestMongoSetup
import models.dao.UserDAO
import org.scalatest._
import play.modules.reactivemongo.ReactiveMongoApi
import scala.concurrent.Await
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.Duration
class UserServiceTest extends FlatSpec with ShouldMatchers with GivenWhenThen with BeforeAndAfterAll with TestMongoSetup { private var mockedAPI: ReactiveMongoApi = _
var dao: UserDAO = _
val port : Int = 12345
override def beforeAll(): Unit = {
start(port)
mockedAPI = createMockedReactiveMongoApi("testDB")
dao = new UserDAO(mockedAPI)
}
override def afterAll(): Unit = {
mockedAPI.connection.actorSystem.shutdown()
mockedAPI.connection.actorSystem.awaitTermination()
stop()
}
"Check" should "check User object into DB" in {
Given("a user info")
val email = "xyx#abc.com"
val pwd= "abcddd"
When("it fetch from DB")
val fromDBUser = Await.result(dao.fetch(email,pwd), Duration.Inf)
Then("it should be fetched")
fromDBUser.get.email should equal(email)
}
}

withEmbedMongoFixture doesn't work very well.
Prefer use the "classic" way : https://github.com/SimplyScala/scalatest-embedmongo#basic-usage-mutable-way
For Mongo 3 use 2.3_SNAPSHOT version of the library.

Related

How to read from embedded-kafka with fs2-kafka

I am using fs2-kafka to read from embedded-kafka.
I create the embedded kafka using withRunningKafkaOnFoundPort, create topic and publish a few messages. However when I try to read it back with fs2-kafka I get a NullPointerException. I have isolated a test case and the code is below.
Here is my code:
import cats.effect._
import cats.implicits._
import cats.effect.implicits._
import fs2.Stream
import fs2.kafka.{AutoOffsetReset, ConsumerSettings, KafkaConsumer, consumerStream}
import net.manub.embeddedkafka.{EmbeddedKafka, EmbeddedKafkaConfig}
import org.scalatest.{BeforeAndAfterAll, FunSuite}
import scala.concurrent.ExecutionContext
class KafkaSuite extends FunSuite with EmbeddedKafka {
val singleThreadExecutor = ExecutionContext.fromExecutor((task: Runnable) => task.run())
implicit val contextShift = IO.contextShift(singleThreadExecutor)
implicit val timer = IO.timer(singleThreadExecutor)
val topic = "example"
val partition = 0
val clientId = "client"
test("works") {
val userDefinedConfig = EmbeddedKafkaConfig(kafkaPort = 0, zooKeeperPort = 0)
withRunningKafkaOnFoundPort(userDefinedConfig) { implicit actualConfig =>
createCustomTopic(topic)
publishStringMessageToKafka(topic, "example-message1")
publishStringMessageToKafka(topic, "example-message2")
publishStringMessageToKafka(topic, "example-message3")
publishStringMessageToKafka(topic, "example-message4")
val broker = s"localhost:${actualConfig.kafkaPort}"
val consumerSettings = ConsumerSettings[IO, String, String]
.withAutoOffsetReset(AutoOffsetReset.Earliest)
.withBootstrapServers(broker)
.withGroupId("group")
.withClientId(clientId)
val r = consumerStream[IO].using(consumerSettings)
.evalTap(_.subscribeTo(topic))
.evalTap(_.seekToBeginning)
.flatMap { consumer =>
consumer.stream.take(1)
}
.compile
.toList
val res = r.unsafeRunSync()
Console.println(res)
assert(res.size == 1)
}
}
}
build.sbt:
name := "test"
version := "0.1"
scalaVersion := "2.12.6"
libraryDependencies ++= Seq(
"org.scalatest" % "scalatest_2.12" % "3.1.2" % "test",
"org.slf4j" % "slf4j-simple" % "1.7.25",
"com.github.fd4s" %% "fs2-kafka" % "1.0.0",
"io.github.embeddedkafka" %% "embedded-kafka" % "2.4.1.1" % Test
)
An here is the stacktrace:
java.lang.NullPointerException was thrown.
java.lang.NullPointerException
at java.lang.String.<init>(String.java:515)
at fs2.kafka.Deserializer$.$anonfun$string$1(Deserializer.scala:208)
at fs2.kafka.Deserializer$.$anonfun$lift$1(Deserializer.scala:184)
at fs2.kafka.Deserializer$$anon$1.deserialize(Deserializer.scala:133)
at fs2.kafka.ConsumerRecord$.deserializeFromBytes(ConsumerRecord.scala:166)
at fs2.kafka.ConsumerRecord$.fromJava(ConsumerRecord.scala:177)
at fs2.kafka.internal.KafkaConsumerActor.$anonfun$records$2(KafkaConsumerActor.scala:378)
at cats.data.NonEmptyVectorInstances$$anon$1.traverse(NonEmptyVector.scala:300)
at cats.data.NonEmptyVectorInstances$$anon$1.traverse(NonEmptyVector.scala:245)
at cats.Traverse$Ops.traverse(Traverse.scala:19)
at cats.Traverse$Ops.traverse$(Traverse.scala:19)
at cats.Traverse$ToTraverseOps$$anon$2.traverse(Traverse.scala:19)
at fs2.kafka.internal.KafkaConsumerActor.$anonfun$records$1(KafkaConsumerActor.scala:376)
at cats.instances.VectorInstances$$anon$1.$anonfun$traverse$2(vector.scala:80)
at cats.instances.VectorInstances$$anon$1.loop$2(vector.scala:43)
at cats.instances.VectorInstances$$anon$1.$anonfun$foldRight$2(vector.scala:44)
at cats.Eval$.advance(Eval.scala:271)
at cats.Eval$.loop$1(Eval.scala:350)
at cats.Eval$.cats$Eval$$evaluate(Eval.scala:368)
at cats.Eval$Defer.value(Eval.scala:257)
at cats.instances.VectorInstances$$anon$1.traverse(vector.scala:79)
at cats.instances.VectorInstances$$anon$1.traverse(vector.scala:15)
at cats.Traverse$Ops.traverse(Traverse.scala:19)
at cats.Traverse$Ops.traverse$(Traverse.scala:19)
at cats.Traverse$ToTraverseOps$$anon$2.traverse(Traverse.scala:19)
at fs2.kafka.internal.KafkaConsumerActor.records(KafkaConsumerActor.scala:373)
at fs2.kafka.internal.KafkaConsumerActor.$anonfun$poll$2(KafkaConsumerActor.scala:405)
at cats.effect.internals.IORunLoop$.liftedTree1$1(IORunLoop.scala:95)
at cats.effect.internals.IORunLoop$.cats$effect$internals$IORunLoop$$loop(IORunLoop.scala:95)
at cats.effect.internals.IORunLoop$.startCancelable(IORunLoop.scala:41)
at cats.effect.internals.IOBracket$BracketStart.run(IOBracket.scala:86)
at cats.effect.internals.Trampoline.cats$effect$internals$Trampoline$$immediateLoop(Trampoline.scala:70)
at cats.effect.internals.Trampoline.startLoop(Trampoline.scala:36)
at cats.effect.internals.TrampolineEC$JVMTrampoline.super$startLoop(TrampolineEC.scala:93)
at cats.effect.internals.TrampolineEC$JVMTrampoline.$anonfun$startLoop$1(TrampolineEC.scala:93)
at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
at scala.concurrent.BlockContext$.withBlockContext(BlockContext.scala:81)
at cats.effect.internals.TrampolineEC$JVMTrampoline.startLoop(TrampolineEC.scala:93)
at cats.effect.internals.Trampoline.execute(Trampoline.scala:43)
at cats.effect.internals.TrampolineEC.execute(TrampolineEC.scala:44)
at cats.effect.internals.IOBracket$BracketStart.apply(IOBracket.scala:72)
at cats.effect.internals.IOBracket$BracketStart.apply(IOBracket.scala:52)
at cats.effect.internals.IORunLoop$.cats$effect$internals$IORunLoop$$loop(IORunLoop.scala:136)
at cats.effect.internals.IORunLoop$RestartCallback.signal(IORunLoop.scala:355)
at cats.effect.internals.IORunLoop$RestartCallback.apply(IORunLoop.scala:376)
at cats.effect.internals.IORunLoop$RestartCallback.apply(IORunLoop.scala:316)
at cats.effect.internals.IOShift$Tick.run(IOShift.scala:36)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Turns out the problem is that the key type in ConsumerSettings[IO, String, String] is String but embedded-kafka writes Null as a key, so on deserializing the key it fails with NullPointerException. Setting key type to Unit solves the problem with exception.
Another problem is that withRunningKafkaOnFoundPort finished before the evaluation of the IO starts. To have it running it is needed to make a Resource from embedded-kafka and wrap the IO into that.
val embeddedKafka = Resource.make(IO(EmbeddedKafka.start()))((kafka) => IO(kafka.stop(true)))
Next problem is that fs2-kafka cannot work with a single thread executor so you have to provide it with an executor pool (for example ExecutionContext.global).
Here is a full working example:
import cats.effect._
import fs2.Stream
import fs2.kafka.{AutoOffsetReset, ConsumerSettings, consumerStream}
import net.manub.embeddedkafka.{EmbeddedKafka, EmbeddedKafkaConfig}
import org.scalatest.FunSuite
import scala.concurrent.ExecutionContext
class KafkaSuite extends FunSuite with EmbeddedKafka {
implicit val ec = ExecutionContext.global
implicit val contextShift = IO.contextShift(ec)
implicit val timer = IO.timer(ec)
val topic = "example"
val partition = 0
val clientId = "client"
val userDefinedConfig = EmbeddedKafkaConfig(kafkaPort = 0, zooKeeperPort = 0)
def broker(port: Long) = s"localhost:${port}"
val consumerSettings = ConsumerSettings[IO, Unit, String]
.withAutoOffsetReset(AutoOffsetReset.Earliest)
.withEnableAutoCommit(true)
.withGroupId("group")
.withClientId(clientId)
val embeddedKafka = Resource.make(IO(EmbeddedKafka.start()))((kafka) => IO(kafka.stop(true)))
test("works") {
val r = Stream.resource(embeddedKafka).flatMap { kafka =>
implicit val actualConfig: EmbeddedKafkaConfig = kafka.config
createCustomTopic(topic)
publishStringMessageToKafka(topic, "example-message1")
publishStringMessageToKafka(topic, "example-message2")
publishStringMessageToKafka(topic, "example-message3")
publishStringMessageToKafka(topic, "example-message4")
consumerStream(consumerSettings.withBootstrapServers(broker(actualConfig.kafkaPort)))
.evalTap(_.subscribeTo(topic))
.evalTap(_.seekToBeginning)
.flatMap(_.stream)
.map(_.record.value)
.take(1)
}
val res = r.compile.toList.unsafeRunSync()
assert(res.contains("example-message1"))
}
}

Connection refused when running multiple NettyServer with play 2.5

I'm currently migrating from play 2.4 to 2.5.
I'm trying to run many NettyServer in a test but I can only access the last created
import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import org.scalatest.{FlatSpec, Matchers}
import org.scalatest.concurrent.ScalaFutures
import org.scalatest.time.{Seconds, Span}
import play.api.libs.ws.ahc.AhcWSClient
import play.api.mvc.{Action, Results}
import play.core.server.{NettyServer, ServerConfig}
import play.api.routing.sird._
class NettyServerTest extends FlatSpec with Matchers with ScalaFutures {
override implicit val patienceConfig = PatienceConfig(Span(5, Seconds))
implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
private val wsClient = AhcWSClient()
it should "print 'Hello I am the secondServer' then 'Hello I am the firstServer'" in {
val firstServer = createServer("firstServer")
val secondServer = createServer("secondServer")
try {
println(wsClient.url(s"http://localhost:${secondServer.httpPort.get}/hello").get().futureValue.body)
println(wsClient.url(s"http://localhost:${firstServer.httpPort.get}/hello").get().futureValue.body)
} finally {
firstServer.stop()
secondServer.stop()
}
}
def createServer(server: String): NettyServer = {
NettyServer.fromRouter(ServerConfig(port = Some(0))) {
case GET(p"/hello") => Action {
Results.Ok(s"Hello I am the $server")
}
}
}
}
When I run the test it only prints 'Hello I am the secondServer' then I get the error:
The future returned an exception of type: java.net.ConnectException, with message: Connection refused: no further information: localhost/0:0:0:0:0:0:0:1:58096.
ScalaTestFailureLocation: NettyServerTest$$anonfun$1 at (NettyServerTest.scala:28)
org.scalatest.exceptions.TestFailedException: The future returned an exception of type: java.net.ConnectException, with message: Connection refused: no further information: localhost/0:0:0:0:0:0:0:1:58096.
at org.scalatest.concurrent.Futures$FutureConcept$class.tryTryAgain$1(Futures.scala:531)
at org.scalatest.concurrent.Futures$FutureConcept$class.futureValue(Futures.scala:558)
at org.scalatest.concurrent.ScalaFutures$$anon$1.futureValue(ScalaFutures.scala:74)
at NettyServerTest$$anonfun$1.apply$mcV$sp(NettyServerTest.scala:28)
at NettyServerTest$$anonfun$1.apply(NettyServerTest.scala:22)
...
I have the following dependencies:
"com.typesafe.play" %% "play-netty-server" % "2.5.4"
"com.typesafe.play" %% "play-ws" % "2.5.4"
This test was working with play 2.4
Finally I succeed to make it work by overriding the actorSystem used by the netty server:
import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import org.scalatest.concurrent.ScalaFutures
import org.scalatest.time.{Seconds, Span}
import org.scalatest.{FlatSpec, Matchers}
import play.api.BuiltInComponents
import play.api.libs.ws.ahc.AhcWSClient
import play.api.mvc.{Action, Results}
import play.api.routing.Router
import play.api.routing.sird._
import play.core.server.{NettyServer, NettyServerComponents, ServerConfig}
class NettyServerTest extends FlatSpec with Matchers with ScalaFutures {
override implicit val patienceConfig = PatienceConfig(Span(5, Seconds))
implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
private val wsClient = AhcWSClient()
it should "print 'Hello I am the secondServer' then 'Hello I am the firstServer'" in {
val firstServer = createServer("firstServer")
val secondServer = createServer("secondServer")
try {
wsClient.url(s"http://localhost:${firstServer.httpPort.get}/hello").get().futureValue.body shouldBe "Hello I am the firstServer"
wsClient.url(s"http://localhost:${secondServer.httpPort.get}/hello").get().futureValue.body shouldBe "Hello I am the secondServer"
} finally {
firstServer.stop()
secondServer.stop()
}
}
def createServer(serverName: String): NettyServer = {
new NettyServerComponents with BuiltInComponents {
lazy val router = Router.from {
case GET(p"/hello") => Action {
Results.Ok(s"Hello I am the $serverName")
}
}
override lazy val serverConfig = ServerConfig(port = Some(0))
override lazy val actorSystem: ActorSystem = ActorSystem()
}.server
}
}

Error testing DAL in slick scala

Pretty new to scala and play and I have been assigned a task to test someone else app,which is running fine btw.Please check if my tests are right and what is the error.
This is employeeEntry.scala file in models
package models
import models.database.Employee
import play.api.db.slick.Config.driver.simple._
import play.api.db.slick._
import play.api.Play.current
case class EmployeeEntry(eid :Int, ename: String, eadd: String, emob: String)
object Employee {
val DBemp = TableQuery[Employee]
def savedat(value: EmployeeEntry):Long = {
DB.withSession { implicit session =>
DBemp+=EmployeeEntry(eid=value.eid,ename=value.ename,eadd=value.eadd,emob=value.emob)
}}
/*val query = for (c <- Employee) yield c.ename
val result = DB.withSession {
implicit session =>
query.list // <- takes session implicitly
}*/
//val query = for (c <- Employee) yield c.ename
def getPersonList: List[EmployeeEntry] = DB.withSession { implicit session => DBemp.list }
def Update: Int = DB.withSession { implicit session =>
(DBemp filter (_.eid === 1) map (s => (s.ename,s.eadd))) update ("test","khair")}
def delet :Int =DB.withSession {
implicit session => (DBemp filter (_.eid === 1)).delete
}
}
And this is file Employee.scala in models/database
package models.database
import models._
import models.EmployeeEntry
import play.api.db.slick.Config.driver.simple._
import scala.slick.lifted._
class Employee(tag:Tag) extends Table[EmployeeEntry](tag,"employee")
{
//val a = "hello"
def eid = column[Int]("eid", O.PrimaryKey)
def ename = column[String]("name", O.DBType("VARCHAR(50)"))
def emob = column[String]("emob",O.DBType("VARCHAR(10)"))
def eadd =column[String]("eadd",O.DBType("VARCHAR(100)"))
def * = (eid, ename, emob, eadd) <> (EmployeeEntry.tupled, EmployeeEntry.unapply)
}
Finally this is my test I am running,which is failing :
import play.api.db.slick.Config.driver.simple._
import play.api.db.slick._
import play.api.Play.current
import org.scalatest.FunSpec
import org.scalatest.matchers.ShouldMatchers
import models.database.Employee
import scala.slick.lifted._
import models._
import models.EmployeeEntry
//import scala.slick.driver.H2Driver.simple._
class databasetest extends FunSpec with ShouldMatchers{
describe("this is to check database layer"){
it("can save a row"){
val a = EmployeeEntry(1006,"udit","schd","90909090")
Employee.savedat(a) should be (1)
}
it("getpersonlist"){
Employee.getPersonList.size should be (1)
}
}
}
The test is failing and error is
java.lang.RuntimeException: There is no started application
at scala.sys.package$.error(package.scala:27)
at play.api.Play$$anonfun$current$1.apply(Play.scala:71)
at play.api.Play$$anonfun$current$1.apply(Play.scala:71)
at scala.Option.getOrElse(Option.scala:120)
at play.api.Play$.current(Play.scala:71)
at models.Employee$.getPersonList(EmployeeEntry.scala:27)
at databasetest$$anonfun$1$$anonfun$apply$mcV$sp$2.apply$mcV$sp(databasetest.scala:39)
at databasetest$$anonfun$1$$anonfun$apply$mcV$sp$2.apply(databasetest.scala:39)
at databasetest$$anonfun$1$$anonfun$apply$mcV$sp$2.apply(databasetest.scala:39)
at org.scalatest.Transformer$$anonfun$apply$1.apply$mcV$sp(Transformer.scala:22)
By default play provides spec2 testing framework.so no need to add scalatest framework for unit testing.For database access layer testing required a connection with database so start a fake application.(this is not running code, just an idea to write unit test)
for more detail take a look play doc : https://www.playframework.com/documentation/2.3.x/ScalaFunctionalTestingWithSpecs2
import org.specs2.mutable.Specification
import models.database.Employee
import models._
import models.EmployeeEntry
import play.api.test.FakeApplication
import play.api.test.Helpers.running
import play.api.Play.current
class databasetest extends Specification {
"database layer" should {
"save a row" in {
running(FakeApplication()) {
val a = EmployeeEntry(1006,"udit","schd","90909090")
Employee.savedat(a) must be equalTo (1)
}
}
"get list" in {
running(FakeApplication()) {
Employee.getPersonList.size must be equalTo (1)
}
}
}

How to have a Scala standalone application that uses the playframework libraries

I have this simple test Scala application, which a blocking http request:
build.sbt
name := "hello"
version := "1.0"
scalaVersion := "2.11.2"
libraryDependencies += "com.typesafe.play" %% "play-ws" % "2.4.0-M1"
Test.scala
import play.api.libs.json._
import play.api.libs.ws._
import scala.concurrent.duration.Duration
import scala.concurrent.{Await, Future}
object Test {
def main(args: Array[String]) = {
val wsClient = WS.client
val body = getBody(wsClient.url("http://example.com/").get())
println(s"body: $body")
}
def getBody(future: Future[WSResponse]) = {
val response = Await.result(future, Duration.Inf);
if (response.status != 200)
throw new Exception(response.statusText);
response.body
}
}
This application fails with:
Exception in thread "main" java.lang.RuntimeException: There is no started application
How to solve this issue?
EDIT for Play 2.5:
import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import play.api.libs.ws._
import play.api.libs.ws.ahc.AhcWSClient
import scala.concurrent.Future
object Main {
import scala.concurrent.ExecutionContext.Implicits._
def main(args: Array[String]): Unit = {
implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
val wsClient = AhcWSClient()
call(wsClient)
.andThen { case _ => wsClient.close() }
.andThen { case _ => system.terminate() }
}
def call(wsClient: WSClient): Future[Unit] = {
wsClient.url("http://www.google.com").get().map { response =>
val statusText: String = response.statusText
println(s"Got a response $statusText")
}
}
}
Please see:
https://www.playframework.com/documentation/2.5.x/ScalaWS#using-wsclient
https://www.playframework.com/documentation/2.5.x/ScalaTestingWebServiceClients
for more detailed examples of standalone WSClient usage. If you are migrating from earlier versions, see https://www.playframework.com/documentation/2.5.x/Migration25#Play-WS-upgrades-to-AsyncHttpClient-2
For Play 2.4:
Do not use raw AsyncHttpClientConfig.Builder for HTTPS -- it does not configure a secure SSLContext with hostname validation.
You can create a new WSClient instance using the following code:
import play.api.libs.ws.ning._
import play.api.libs.ws._
val config = new NingAsyncHttpClientConfigBuilder(DefaultWSClientConfig()).build()
val builder = new AsyncHttpClientConfig.Builder(config)
val wsClient:WSClient = new NingWSClient(builder.build())
Please note that this will start up threads which will not be closed until you close the client:
wsClient.underlying[NingWSClient].close()
and you may run into memory leaks if you don't close it.
Play 2.4 makes it very easy to utilize WS in a standalone app.
The following gist provides a nice working example and the following blog post provides a nice explanation.
Here are the highlights.
Configure build.sbt
libraryDependencies ++= Seq(
"com.typesafe.play" %% "play-ws" % "2.4.0-M2"
)
Initialize the WS client
val config = new NingAsyncHttpClientConfigBuilder(DefaultWSClientConfig()).build
val builder = new AsyncHttpClientConfig.Builder(config)
val client = new NingWSClient(builder.build)
Use WS
client.url("http://www.example.com").get
Release WS resources
client.close()
A started PlayApplication contains a client instance, which WS.client simply points to it. Since you won't start a Play application, You have to create your own client, like this:
val client = {
val builder = new com.ning.http.client.AsyncHttpClientConfig.Builder()
new play.api.libs.ws.ning.NingWSClient(builder.build())
}
client.url("http://example.com/").get()
Have a look on my project for a similar usecase, I am using play-ws and play-json, without Play itself.

Scala Play Framework Slick session doesn't work

I'm trying a simple test application with Slick and the Play2 Framework, but the compiler keeps complaining the implicit session cannot be inferred.
Here is my Build.scala:
import sbt._
import Keys._
import play.Project._
object ApplicationBuild extends Build {
val appName = "dummy"
val appVersion = "1.0"
val appDependencies = Seq(
jdbc,
"mysql" % "mysql-connector-java" % "5.1.26",
"com.typesafe.slick" %% "slick" % "1.0.1"
)
val main = play.Project(appName, appVersion, appDependencies).settings(
// Add your own project settings here
)
}
And this is my Global singleton that holds my database connections:
package models
import play.api.Play.current
import play.api.db.DB
import slick.session.Session
import slick.driver.MySQLDriver.simple._
import scala.slick.session.Database.threadLocalSession
object Global {
lazy val database = Database.forDataSource(DB.getDataSource())
lazy val session = database.createSession()
}
And my controller:
package controllers
import scala.language.implicitConversions
import play.api._
import play.api.mvc._
import models.Global.session
import slick.driver.MySQLDriver.simple._
object Application extends Controller {
def index = Action {
/*slick.driver.MySQLDriver.simple.*/Query(Foo).foreach( _ => () ) // Do nothing for now
Ok(views.html.index("hola"))
}
object Foo extends Table[(Long, String, String)]("Foo") {
def * = column[Long]("id") ~ column[String]("bar1") ~ column[String]("bar2")
}
}
As you can see my Global.session val is imported, but it keeps saying no implicit session was found.
To make queries you need two things: connection to the database and a session, so your problem is how you define and use them.
With Database.threadLocalSession in scope, you can make your queries like this :
Database.forURL("jdbc:h2:mem:play", driver = "org.h2.Driver") withSession {
//create table
Foo.ddl.create
//insert data
Foo.insert((1.toLong,"foo","bar"))
//get data
val data : (Long,String,String) = (for{f<-Foo}yield(f)).first
}
or you can do it like this:
val database = Database.forDataSource(DB.getDataSource())
database.withSession{ implicit session : Session =>
Foo.ddl.create
Foo.insert((1.toLong,"foo","bar"))
val data : (Long,String,String) = (for{f<-Foo}yield(f)).first
}
I have create a test and it works fine, you can play with it:
"Foo should be creatable " in {
running(FakeApplication(additionalConfiguration = inMemoryDatabase())) {
val database = Database.forDataSource(DB.getDataSource())
database.withSession{ implicit session : Session =>
Foo.ddl.create
Foo.insert((1.toLong,"foo","bar"))
val data : (Long,String,String) = (for{f<-Foo}yield(f)).first
data._1 must equalTo(1)
}
}
}
Also you may look at here