|
|
@@ -0,0 +1,179 @@
|
|
|
+package controllers
|
|
|
+
|
|
|
+import scala.concurrent.Await
|
|
|
+import scala.concurrent.duration.Duration
|
|
|
+import org.scalatestplus.play._
|
|
|
+import akka.stream.Materializer
|
|
|
+
|
|
|
+import play.api.mvc._
|
|
|
+import play.api.test._
|
|
|
+import play.api.test.Helpers._
|
|
|
+import play.api.http.Status
|
|
|
+import play.api.http.HeaderNames
|
|
|
+import play.api.libs.json.{JsValue,JsObject,Json}
|
|
|
+
|
|
|
+import org.scalatest._
|
|
|
+import org.scalatestplus.play._
|
|
|
+import org.scalatestplus.play.guice._
|
|
|
+
|
|
|
+import com.github.simplyscala.{MongoEmbedDatabase,MongodProps}
|
|
|
+import org.mongodb.scala.{MongoClient,MongoDatabase,MongoCollection,Observer};
|
|
|
+
|
|
|
+import models.Food
|
|
|
+
|
|
|
+class FoodControllerSpec
|
|
|
+ extends PlaySpec
|
|
|
+ with GuiceOneAppPerTest
|
|
|
+ with Injecting
|
|
|
+ with MongoEmbedDatabase {
|
|
|
+
|
|
|
+ val testDBPort: Int = 12345
|
|
|
+ implicit lazy val materializer: Materializer = app.materializer
|
|
|
+
|
|
|
+ def getDBColl(): MongoCollection[Food] = {
|
|
|
+ val db: MongoDatabase = MongoClient.apply(s"mongodb://localhost:${testDBPort}")
|
|
|
+ .getDatabase("recipes")
|
|
|
+ .withCodecRegistry(MongoDB.codecRegistry)
|
|
|
+ db.createCollection("Food")
|
|
|
+ db.getCollection[Food]("Food")
|
|
|
+ }
|
|
|
+
|
|
|
+ // def blockingObserver[T](sem: Semaphore, processor: T => Unit) = new Observer[T] {
|
|
|
+ // override def onNext(result: T) = {println("next");processor(result)}
|
|
|
+ // override def onError(e: Throwable) = {
|
|
|
+ // println("error")
|
|
|
+ // sem.release()
|
|
|
+ // throw e
|
|
|
+ // }
|
|
|
+ // override def onComplete() = {println("complete");sem.release()}
|
|
|
+ // }
|
|
|
+
|
|
|
+ "FoodController PUT /food" should {
|
|
|
+ "return the resulting food object and insert into the DB" in {
|
|
|
+ val body: JsValue = Json.parse(
|
|
|
+ """{"name": "Example Food",
|
|
|
+ |"glutenFree": false,
|
|
|
+ |"vegitarian": true,
|
|
|
+ |"vegan": false,
|
|
|
+ |"nutrients": {"iron": 1.2, "B": 7},
|
|
|
+ |"source": "Test Script",
|
|
|
+ |"category": ["Breakfast", "Asian"],
|
|
|
+ |"primaryMeasure": "mass",
|
|
|
+ |"density": 3.2,
|
|
|
+ |"mass_p_u": 2.7,
|
|
|
+ |"price": 1237,
|
|
|
+ |"alternatives": ["Scrambled Eggs"]
|
|
|
+ |} """.stripMargin
|
|
|
+ )
|
|
|
+ val fakeRequ: FakeRequest[JsValue] = FakeRequest[JsValue](PUT, "/food", FakeHeaders(), body)
|
|
|
+ .withHeaders(HeaderNames.CONTENT_TYPE -> "application/json")
|
|
|
+ withEmbedMongoFixture() { mongodProps: MongodProps =>
|
|
|
+ val coll: MongoCollection[Food] = getDBColl
|
|
|
+ val controller: FoodController = new FoodController(coll)
|
|
|
+ val result = controller.put().apply(fakeRequ)
|
|
|
+ status(result) mustBe OK
|
|
|
+ contentType(result) mustBe Some("application/json")
|
|
|
+ val resultJs: JsObject = contentAsJson(result).asInstanceOf[JsObject]
|
|
|
+ resultJs - "_id" mustBe body
|
|
|
+ Await.result(coll.countDocuments().toFuture, Duration.Inf) mustBe 1
|
|
|
+ Await.result(coll.find().first().toFuture, Duration.Inf) mustBe resultJs.as[Food]
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Removed: not presenting id's to front-end
|
|
|
+ // "return the resulting food object with a distinct id" in {
|
|
|
+ // val controller = inject[HomeController]
|
|
|
+ // val home = controller.index().apply(FakeRequest(GET, "/"))
|
|
|
+
|
|
|
+ // status(home) mustBe OK
|
|
|
+ // contentType(home) mustBe Some("text/html")
|
|
|
+ // contentAsString(home) must include ("Welcome to Play")
|
|
|
+ // }
|
|
|
+
|
|
|
+ "return an error when given an empty request and not " +
|
|
|
+ "insert into the DB" in {
|
|
|
+ val fakeRequ = FakeRequest(PUT, "/food", FakeHeaders(), "")
|
|
|
+ .withHeaders(HeaderNames.CONTENT_TYPE -> "application/json")
|
|
|
+ withEmbedMongoFixture() { mongodProps: MongodProps =>
|
|
|
+ val coll: MongoCollection[Food] = getDBColl
|
|
|
+ val controller: FoodController = new FoodController(coll)
|
|
|
+ val result = controller.put().apply(fakeRequ)
|
|
|
+ status(result) mustBe Status.BAD_REQUEST
|
|
|
+ Await.result(coll.countDocuments().toFuture, Duration.Inf) mustBe 0
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ "return an error when given an invalid request and not " +
|
|
|
+ "insert into the DB" in {
|
|
|
+ val body: JsValue = Json.parse(// Name intentionally moved
|
|
|
+ """{
|
|
|
+ |"glutenFree": false,
|
|
|
+ |"vegitarian": true,
|
|
|
+ |"vegan": false,
|
|
|
+ |"nutrients": {"iron": 1.2, "B": 7},
|
|
|
+ |"source": "Test Script",
|
|
|
+ |"category": ["Breakfast", "Asian"],
|
|
|
+ |"primaryMeasure": "mass",
|
|
|
+ |"density": 3.2,
|
|
|
+ |"mass_p_u": 2.7,
|
|
|
+ |"price": 1237,
|
|
|
+ |"alternatives": ["Scrambled Eggs"]
|
|
|
+ |} """.stripMargin
|
|
|
+ )
|
|
|
+ val fakeRequ = FakeRequest(PUT, "/food", FakeHeaders(), body)
|
|
|
+ .withHeaders(HeaderNames.CONTENT_TYPE -> "application/json")
|
|
|
+ withEmbedMongoFixture() { mongodProps: MongodProps =>
|
|
|
+ val coll: MongoCollection[Food] = getDBColl
|
|
|
+ val controller: FoodController = new FoodController(coll)
|
|
|
+ val result = controller.put().apply(fakeRequ)
|
|
|
+ status(result) mustBe Status.BAD_REQUEST
|
|
|
+ Await.result(coll.countDocuments().toFuture, Duration.Inf) mustBe 0
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ "return the resulting object with default values and " +
|
|
|
+ "insert into the DB" in {
|
|
|
+ val body: JsValue = Json.parse(
|
|
|
+ """{"name": "Example Food",
|
|
|
+ |"vegitarian": true,
|
|
|
+ |"nutrients": {"iron": 1.2, "B": 7},
|
|
|
+ |"source": "Test Script",
|
|
|
+ |"category": ["Breakfast", "Asian"],
|
|
|
+ |"primaryMeasure": "mass",
|
|
|
+ |"density": 3.2,
|
|
|
+ |"mass_p_u": 2.7,
|
|
|
+ |"price": 1237,
|
|
|
+ |"alternatives": ["Scrambled Eggs"]
|
|
|
+ |} """.stripMargin
|
|
|
+ )
|
|
|
+ val expected: JsValue = Json.parse(
|
|
|
+ """{"name": "Example Food",
|
|
|
+ |"glutenFree": false,
|
|
|
+ |"vegitarian": true,
|
|
|
+ |"vegan": false,
|
|
|
+ |"nutrients": {"iron": 1.2, "B": 7},
|
|
|
+ |"source": "Test Script",
|
|
|
+ |"category": ["Breakfast", "Asian"],
|
|
|
+ |"primaryMeasure": "mass",
|
|
|
+ |"density": 3.2,
|
|
|
+ |"mass_p_u": 2.7,
|
|
|
+ |"price": 1237,
|
|
|
+ |"alternatives": ["Scrambled Eggs"]
|
|
|
+ |} """.stripMargin
|
|
|
+ )
|
|
|
+ val fakeRequ = FakeRequest(PUT, "/food", FakeHeaders(), body)
|
|
|
+ .withHeaders(HeaderNames.CONTENT_TYPE -> "application/json")
|
|
|
+ withEmbedMongoFixture() { mongodProps: MongodProps =>
|
|
|
+ val coll: MongoCollection[Food] = getDBColl
|
|
|
+ val controller: FoodController = new FoodController(coll)
|
|
|
+ val result = controller.put().apply(fakeRequ)
|
|
|
+ status(result) mustBe OK
|
|
|
+ contentType(result) mustBe Some("application/json")
|
|
|
+ val resultJs: JsObject = contentAsJson(result).asInstanceOf[JsObject]
|
|
|
+ resultJs - "_id" mustBe expected
|
|
|
+ Await.result(coll.countDocuments().toFuture, Duration.Inf) mustBe 1
|
|
|
+ Await.result(coll.find().first().toFuture, Duration.Inf) mustBe resultJs.as[Food]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|