Error testing DAL in slick scala - 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)
}
}
}

Related

scala akka http type mismatch

I created a project with open api then added a endpoint GET /product which is supposed to return a product( i am testing it so I just want it to return any product).
When I run the project I get the following error.
[error] found : org.openapitools.server.model.Product.type
[error] required: (?, ?, ?) => ?
[error] def toEntityMarshallerProduct: ToEntityMarshaller[Product] = jsonFormat3(Product)
the logs point at Product inside jsonFormat3
I noticed it's caused by the number of properties of the Product Model, if I reduce them to 3, it works ! this is weird! does anyone know how to resolve this?
this is the product model file
package org.openapitools.server.model
final case class Product (
id: Int,
name: String,
isAvailable: Boolean,
description: String,
category: String
)
this is the productAPI file
package org.openapitools.server.api
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.Route
import akka.http.scaladsl.model.StatusCodes
import akka.http.scaladsl.marshalling.ToEntityMarshaller
import akka.http.scaladsl.unmarshalling.FromEntityUnmarshaller
import akka.http.scaladsl.unmarshalling.FromStringUnmarshaller
import org.openapitools.server.AkkaHttpHelper._
import org.openapitools.server.model.Product
class ProductApi(
productService: ProductApiService,
productMarshaller: ProductApiMarshaller
) {
import productMarshaller._
lazy val route: Route =
path("product" / "all") {
get {
productService.productAllGet()
}
}
}
trait ProductApiService {
def productAllGet200(responseProduct: Product)(implicit toEntityMarshallerProduct: ToEntityMarshaller[Product]): Route =
complete((200, responseProduct))
def productAllGet()(implicit toEntityMarshallerProduct: ToEntityMarshaller[Product]): Route
}
trait ProductApiMarshaller {
implicit def toEntityMarshallerProduct: ToEntityMarshaller[Product]
}
and this is the main file
import akka.actor.typed.{ActorSystem, ActorRef}
import akka.actor.typed.scaladsl.Behaviors
import akka.http.scaladsl.Http
import akka.http.scaladsl.server.Route
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.model.StatusCodes
// for JSON serialization/deserialization following dependency is required:
// "com.typesafe.akka" %% "akka-http-spray-json" % AkkaHttpVersion
import akka.http.scaladsl.marshalling.ToEntityMarshaller
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
import spray.json.DefaultJsonProtocol._
import scala.io.StdIn
import akka.util.Timeout
import scala.concurrent.duration._
import scala.concurrent.{ ExecutionContext, Future }
import org.openapitools.server.api._
import org.openapitools.server.model._
object Main extends App {
// needed to run the route
implicit val system = ActorSystem(Behaviors.empty, "product")
// implicit val materializer = ActorMaterializer()
// needed for the future map/flatmap in the end and future in fetchItem and saveOrder
implicit val executionContext = system.executionContext
object DefaultMarshaller extends ProductApiMarshaller {
def toEntityMarshallerProduct: ToEntityMarshaller[Product] = jsonFormat3(Product)
}
object DefaultService extends ProductApiService {
def productAllGet() (implicit toEntityMarshallerProduct: ToEntityMarshaller[Product]) : Route = {
val reponse = Future {
Product(1,"product",false,"desc","pizza")
}
requestcontext => {
(reponse).flatMap {
(product: Product) =>
productAllGet200(product)(toEntityMarshallerProduct)(requestcontext)
}
}
}
}
val api = new ProductApi(DefaultService, DefaultMarshaller)
val host = "localhost"
val port = 3005
val bindingFuture = Http().newServerAt(host, port).bind(pathPrefix("api"){api.route})
println(s"Server online at http://${host}:${port}/\nPress RETURN to stop...")
bindingFuture.failed.foreach { ex =>
println(s"${ex} Failed to bind to ${host}:${port}!")
}
StdIn.readLine() // let it run until user presses return
bindingFuture
.flatMap(_.unbind()) // trigger unbinding from the port
.onComplete(_ => system.terminate()) // and shutdown when done
}
I noticed it's caused by the number of properties of the Product Model, if I reduce them to 3, it works ! this is weird! does anyone know how to resolve this?
try it with using a Data Transfer Object (DTO) which will provide by your api and a domain model object which is handled internally.
so you will use jsonFormat3 for your DTO and have no need to jsonFormat5.
a simple mapper or helper method inner of case classes provide a smooth integration of that.
for example:
final case class Product (
id: Int,
name: String,
isAvailable: Boolean,
description: String,
category: String
) {
def toDto: ProductDTO = ProductDTO(prop0, prop1, prop2)
}
final case class ProductDTO (
prop0: X,
prop1: Y,
prop2: Z
) {
def toDomain(propA: X, propB: Y): Product = Product(id, name, isAvailable, description, category)
}
object ProductSupport extends SprayJsonSupport with DefaultJsonProtocol {
implicit val productFormat = json3Format(ProductDTO)
}

could not find implicit value for parameter env: com.mohiva.play.silhouette.api.Environment[utils.auth.DefaultEnv]

I'm using a Silhouette v4.0 library with play framework 2.5.
And have been trying to write test code using play specs2.
But, I get the following error with my test class as below.
Error Message
[error] could not find implicit value for parameter env: com.mohiva.play.silhouette.api.Environment[utils.auth.DefaultEnv]
.withAuthenticator[DefaultEnv](identity.loginInfo)
^
Here's the test class
package controllers
import com.google.inject.AbstractModule
import org.joda.time.DateTime
import org.specs2.specification.Scope
import org.specs2.matcher._
import org.specs2.mock._
import play.api.test._
import play.api.libs.json._
import play.api.libs.json.Json
import play.api.libs.json.Reads._
import play.api.libs.functional.syntax._
import play.api.libs.concurrent.Execution.Implicits._
import play.api.libs.mailer.{ MailerClient, Email }
import play.api.inject.guice.GuiceApplicationBuilder
import play.api.inject.bind
import com.mohiva.play.silhouette.test._
import com.mohiva.play.silhouette.api._
import com.mohiva.play.silhouette.api.repositories.AuthInfoRepository
import com.mohiva.play.silhouette.api.util._
import com.mohiva.play.silhouette.impl.providers._
import net.codingwell.scalaguice.ScalaModule
import utils.auth.DefaultEnv
class TestControllerSpec extends PlaySpecification with Mockito {
"case" in new Context {
new WithApplication(application) {
val request = FakeRequest(POST, "/api/test")
.withAuthenticator[DefaultEnv](identity.loginInfo) // <-
val result = route(app, request).get
status(result) must be equalTo OK
}
}
trait Context extends Scope {
val identity = User(
loginInfo = LoginInfo(..)
..
)
implicit val env = FakeEnvironment[DefaultEnv](Seq(identity.loginInfo -> identity))
class FakeModule extends AbstractModule with ScalaModule {
def configure() = {
bind[Environment[DefaultEnv]].toInstance(env)
}
}
lazy val application = new GuiceApplicationBuilder()
.overrides(new FakeModule)
.build
}
}
There are some other test classes similar to this class are properly able to compile and execute.
It's kind of implicit problem with scope..
Therefore, I tried to import all the same as another test class which's able to compile properly. But, still unable to compile.
Missing some import?
As the compiler states, you're missing an implicit value. Use the following, which is modeled after one of Silhouette's specs:
class TestControllerSpec extends PlaySpecification with Mockito {
"the POST request" should {
"return an OK response" in new Context {
new WithApplication(application) {
val identity = User(LoginInfo(...))
implicit val env = FakeEnvironment[DefaultEnv](Seq(identity.loginInfo -> identity))
val request = FakeRequest(POST, "/api/test")
.withAuthenticator(identity.loginInfo)
val result = route(app, request).get
status(result) must be equalTo OK
}
}
}
trait Context extends Scope {
...
}
}

Getting error while trying to insert data into MongoDB

I am trying to insert data into MongoDB using Play-scala and ReactiveMongo.
Here is my DbimpService.scala:
package services
import models.Post
import reactivemongo.bson.BSONDocument
import reactivemongo.api.MongoDriver
import reactivemongo.api.collections.bson.BSONCollection
import scala.concurrent.ExecutionContext
import javax.inject.Inject
import play.api.libs.json.Json
import reactivemongo.play.json.collection.JSONCollection
import reactivemongo.api.commands.WriteResult
import scala.concurrent.Future
import org.apache.xerces.util.DatatypeMessageFormatter
class Dbimpservice #Inject() (implicit ec:ExecutionContext) extends Dbservice {
def create(p:Post):String={
var status = "Not Saved"
val driver = new MongoDriver
val connection = driver.connection(List("localhost"))
val db = connection("application")
val collection = db[BSONCollection]("post")
val futureList = collection.insert[Post](p)
futureList.onComplete { case sucess => println(sucess) }
return status
}
}
Here is my HomeController.scala:
package controllers
import javax.inject._
import play.api._
import play.api.mvc._
import models._
import scala.util.{ Failure, Success }
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import reactivemongo.api.{ MongoDriver, MongoConnection }
import reactivemongo.play.json.collection.JSONCollection
import reactivemongo.bson.BSONDocument
import reactivemongo.api.commands.WriteResult
import reactivemongo.api.collections.bson.BSONCollection
import play.api.libs.json.Json
import services.Dbservice
import services.Dbimpservice
import services.Dbservice
import scala.concurrent.ExecutionContext
import scala.concurrent.Await
import scala.concurrent.duration.Duration
/**
* This controller creates an `Action` to handle HTTP requests to the
* application's home page.
*/
#Singleton
class HomeController #Inject() (implicit ec:ExecutionContext,val Dbservice : Dbimpservice)extends Controller {
/**
* Create an Action to render an HTML page with a welcome message.
* The configuration in the `routes` file means that this method
* will be called when the application receives a `GET` request with
* a path of `/`.
*/
def index = Action{
Ok("Hai")
}
def read = Action.async {
val query = BSONDocument()
val driver = new MongoDriver
val connection = driver.connection(List("localhost:27017"))
val db = connection("application")
val collection = db[BSONCollection]("post")
val futureList = collection.find(query).cursor[Post]().collect[List]()
futureList.map { list =>
Ok(list.toString())
}
}
def create = Action(BodyParsers.parse.json) { request =>
val personResult = request.body.validate[Post]
personResult.fold(
errors => {
BadRequest(Json.obj("status " ->"ERROR"))
},
valid = fun
)
}
def fun:Post => Result= { post =>
var ans = Dbservice.create(post)
Ok(ans)
}
}
I am trying to insert the data but not getting inserted and the error which i am getting is
Failure(reactivemongo.core.errors.ConnectionNotInitialized: MongoError['Connection is missing metadata (like protocol version, etc.) The connection pool is probably being initialized.'])
Some one please help me, I even referred the link
http://stackoverflow.com/questions/31456517/embedmongo-with-reactivemongo-process-does-not-exit
but did not get
Guessing that you are using a recent version of ReactiveMongo (0.11.7+), you are using a deprecated DB resolution code (connection(dbName) aka connection.apply(dbName).
See also
You need to use the asynchronous resolution, which benefit from the failover (to handle possible network latency/incident). The following code must so be refactored.
val db = connection("application")
val collection = db[BSONCollection]("post")
val futureList = collection.insert[Post](p)
Using the new DB resolution:
for {
db <- connection.database("application")
collection = db("post")
res <- collection.insert(p)
} yield res

Scala compile error: value is not member of

Sorry for my bad english!
I'm newbie in scala language, I'm compiling a project with some modifications and getting the error
"scala value is not member of"... some body can help me? follow my code:
Command.scala
package com.bla.cms.domain
import scala.collection.Map
import redis.clients.jedis.Jedis
sealed trait CommandResult
object Success extends CommandResult
object Failure extends CommandResult
object Unauthorized extends CommandResult
trait Command {
def captchaValidator:Validator
def logger:Logging
val properties = PropertiesHandler.readProperties(System.getProperty(PropertiesHandler.configFileNameKey))
}
RedisIcrementCommand.scala
package com.bla.cms
package domain
import scala.collection.Map
import redis.clients.jedis.JedisPool
import dispatch._
import org.apache.log4j.Logger
import redis.clients.jedis.Jedis
class RedisIncrementCommand(database: Jedis, val captchaValidator:Validator, val logger:Logging) extends Command {
def execute(parameters: Map[String,String]):CommandResult = {
captchaValidator.validate(parameters) match {
case Right(params) =>
executeInDatabase(params)
case Left(status) =>
logger.info("Falha ao tentar executar comando. Captcha inválido. Status: " + status)
Failure
}
}
def executeInDatabase(parameters: Map[String,String]):CommandResult = {
parameters.get("selectedAnswer") match {
case Some(selectedAnswer) =>
database.incr(selectedAnswer)
database.sadd(Answers.key, selectedAnswer)
logger.info("Incremento recebido com sucesso. Opção: " + selectedAnswer)
Success
case None =>
logger.info("Falha ao tentar computar incremento. Alternativa não informada.")
Failure
}
}
}
PollServle.scala
package com.bla.cms
import javax.servlet.http._
import redis.clients.jedis.JedisPool
import scala.collection.JavaConverters._
import scala.collection.JavaConversions._
import com.bla.cms.domain.Logging
import org.apache.log4j.Logger
import scala.util.matching.Regex
class PollServlet extends HttpServlet with RequiresConnection {
import com.bla.cms.domain._
import URLHandler._
override def doPost(request:HttpServletRequest, response:HttpServletResponse):Unit = {
val parametersMap = new ServletApiAdapter(request,response).parameters
val outcome = newIncrementCommand(request).execute(parametersMap)
redirect(request, response, outcome)
}
}
And when I compile, I've got:
[error]PollServlet.scala:19: value execute is nota member of com.bla.cms.domain.Command
val outcome = newIncrementCommand(request).execute(parametersMap)
Somebody can help me please?
You can:
Add def execute(parameters: Map[String,String]):CommandResult to Command trait.
Change newIncrementCommand(request) to return RedisIncrementCommand instead of Command.
Cast result of newIncrementCommand(request) to RedisIncrementCommand using asInstanceOf.
I prefer 1 which would be:
trait Command {
val captchaValidator: Validator
val logger: Logging
val properties = PropertiesHandler.readProperties(System.getProperty(PropertiesHandler.configFileNameKey))
def execute(parameters: Map[String,String]): CommandResult
def executeInDatabase(parameters: Map[String,String]): CommandResult
}

slick 'n scala : a TableQuery object without .ddl field

using scala, slick 2.0 & eclipse I have an error I can't explain : "value ddl is not a member of scala.slick.lifted.TableQuery[SqliteSpec.this.Personnes]"
here is the code:
I declare a trait like this :
trait sqlite {
val db = Database.forURL("jdbc:sqlite:rdvs.txt", driver = "org.sqlite.JDBC")
class Personnes(tag: Tag) extends Table[Rdv](tag, "RDV") {
def id = column[Int]("ID", O.PrimaryKey, O.AutoInc)
def nom = column[String]("NOM", O.NotNull)
def prénom = column[String]("PRENOM")
def sexe = column[Int]("SEXE")
def télPortable = column[String]("TELPOR")
def télBureau = column[String]("TELBUR")
def télPrivé = column[String]("TELPRI")
def siteRDV = column[String]("SITE")
def typeRDV = column[String]("TYPE")
def libelléRDV = column[String]("LIBELLE")
def numRDV = column[String]("NUMRDV")
def étape = column[String]("ETAPE")
def dateRDV = column[Date]("DATE")
def heureRDVString = column[String]("HEURE")
def statut = column[String]("STATUT")
def orderId = column[String]("ORDERID")
def * = (id.?, nom, prénom, sexe, télPortable, télBureau, télPrivé,
siteRDV, typeRDV, libelléRDV, numRDV, étape, dateRDV, heureRDVString,
statut, orderId) <> (Rdv.tupled, Rdv.unapply _)
}
}
and here is the wrong code :
db.withDynSession{
val personnes=TableQuery[Personnes]
personnes.ddl.create
}
althought I followed this official tutorial : http://slick.typesafe.com/doc/2.0.0/schemas.html (section DDL)
Do you know what's wrong?
thanks.
Maybe this is useful for somebody: I had the same problem, but my mistake was importing different driver simple implicits. In my main model class had Postgres', but in my tests had H2's (in order to make in-memory integration testing). Switching to the same drivers solved the issue.
I would like to add the entire code, but the "edit" button is no more present under my question; here is the code:
package tests {
#RunWith(classOf[JUnitRunner])
class SqliteSpec extends Specification with sqlite {
"la base sqlite" should {
"create a new database file" in new Sqlite_avant_chaque_test {
todo
}
}
class Sqlite_avant_chaque_test extends Scope {
println("avant test")
def abc = {
db.withDynSession {
val personnes = TableQuery[Personnes]
personnes.ddl.create
}
}
}
}
}
ok, I only needed to log on; here is the working code :
import org.specs2.execute.AsResult
import org.specs2.runner.JUnitRunner
import scala.collection.GenTraversableOnce
import org.specs2.time.TimeConversions$longAsTime
import org.specs2.collection.BiMap
import org.specs2.control.Debug$Debuggable
import scala.collection.mutable.ListBuffer
import org.specs2.internal.scalaz.TreeLoc
import org.specs2.mutable.Specification
import scala.xml.NodeSeq
import scala.collection.immutable.List
import org.specs2.text.LinesContent
import org.specs2.specification.Fragments
import scala.math.Numeric
import java.net.URL
import org.specs2.matcher.MatchSuccess
import scala.runtime.Nothing$
import scala.reflect.ClassTag
import org.specs2.main.Arguments
import java.io.InputStream
import org.specs2.data.Sized
import org.junit.runner.RunWith
import org.specs2.specification.Scope
import java.sql.SQLInvalidAuthorizationSpecException
import models.sqlite
import scala.slick.lifted.TableQuery
//import scala.slick.driver.JdbcDriver.simple._
import scala.slick.driver.SQLiteDriver.simple._
import play.api.test.Helpers
import play.test.Helpers
package tests {
#RunWith(classOf[JUnitRunner])
class SqliteSpec extends Specification with sqlite {
sequential
"la base sqlite" should {
"create a new database file" in new Sqlite_avant_chaque_test {
todo
}
}
class Sqlite_avant_chaque_test extends Scope {
println("avant test")
//db.withDynSession {
db.withSession { implicit session: Session =>
val personnes = TableQuery[Personnes]
personnes.ddl.create
println("avant tests, après création base")
}
}
}
}