FoodControllerSpec.scala 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. package controllers
  2. import scala.concurrent.{Await,Future}
  3. import scala.language.postfixOps
  4. import scala.concurrent.duration.{Duration,DurationInt}
  5. import org.scalatestplus.play._
  6. import akka.stream.Materializer
  7. import play.api.mvc._
  8. import play.api.test._
  9. import play.api.test.Helpers._
  10. import play.api.http.Status
  11. import play.api.http.HeaderNames
  12. import play.api.libs.json.{JsValue,JsObject,Json,JsString}
  13. import org.scalatest._
  14. import org.scalatestplus.play._
  15. import org.scalatestplus.play.guice._
  16. import com.github.simplyscala.{MongoEmbedDatabase,MongodProps}
  17. import org.mongodb.scala.{MongoClient,MongoDatabase,MongoCollection,Observer,Completed};
  18. import models.Food
  19. import models.{Mass,Volume}
  20. class FoodControllerSpec
  21. extends PlaySpec
  22. with GuiceOneAppPerTest
  23. with Injecting
  24. with MongoEmbedDatabase {
  25. val testDBPort: Int = 12345
  26. implicit lazy val materializer: Materializer = app.materializer
  27. val exampleFood1: Food = Food("1", "Example Food", false, true, false, Map("iron" -> 1.2f, "B" -> 7f),
  28. "Test Script", Seq("Breakfast", "Asian"), Mass(), 3.2f, 2.7f, 1237, Seq("Scrambled Eggs"))
  29. val exampleFood2: Food = Food("2", "Food Example", true, false, false, Map("copper" -> .2f, "D" -> 1f),
  30. "Test Script", Seq("Dinner", "Southern"), Volume(), 1.2f, 2.0f, 73, Seq("Bacon"))
  31. val exampleJson1: JsValue = Json.parse(
  32. """{"name": "Example Food",
  33. |"glutenFree": false,
  34. |"vegitarian": true,
  35. |"vegan": false,
  36. |"nutrients": {"iron": 1.2, "B": 7},
  37. |"source": "Test Script",
  38. |"category": ["Breakfast", "Asian"],
  39. |"primaryMeasure": "mass",
  40. |"density": 3.2,
  41. |"mass_p_u": 2.7,
  42. |"price": 1237,
  43. |"alternatives": ["Scrambled Eggs"]
  44. |} """.stripMargin
  45. )
  46. val strippedExampleJson1: JsValue = Json.parse(
  47. """{"name": "Example Food",
  48. |"vegitarian": true,
  49. |"nutrients": {"iron": 1.2, "B": 7},
  50. |"source": "Test Script",
  51. |"category": ["Breakfast", "Asian"],
  52. |"primaryMeasure": "mass",
  53. |"density": 3.2,
  54. |"mass_p_u": 2.7,
  55. |"price": 1237,
  56. |"alternatives": ["Scrambled Eggs"]
  57. |} """.stripMargin
  58. )
  59. val brokenExampleJson1: JsValue = Json.parse(
  60. """{
  61. |"glutenFree": false,
  62. |"vegitarian": true,
  63. |"vegan": false,
  64. |"nutrients": {"iron": 1.2, "B": 7},
  65. |"source": "Test Script",
  66. |"category": ["Breakfast", "Asian"],
  67. |"primaryMeasure": "mass",
  68. |"density": 3.2,
  69. |"mass_p_u": 2.7,
  70. |"price": 1237,
  71. |"alternatives": ["Scrambled Eggs"]
  72. |} """.stripMargin
  73. )
  74. val exampleJson2: JsValue = Json.parse(
  75. """{"name": "Food Example",
  76. |"glutenFree": true,
  77. |"vegitarian": false,
  78. |"vegan": false,
  79. |"nutrients": {"copper": 0.2, "D": 1},
  80. |"source": "Test Script",
  81. |"category": ["Dinner", "Southern"],
  82. |"primaryMeasure": "volume",
  83. |"density": 1.2,
  84. |"mass_p_u": 2,
  85. |"price": 73,
  86. |"alternatives": ["Bacon"]
  87. |} """.stripMargin
  88. )
  89. def getDBColl(): MongoCollection[Food] = {
  90. val db: MongoDatabase = MongoClient.apply(s"mongodb://localhost:${testDBPort}")
  91. .getDatabase("recipes")
  92. .withCodecRegistry(MongoDB.codecRegistry)
  93. db.createCollection("Food")
  94. db.getCollection[Food]("Food")
  95. }
  96. def initDB(coll: MongoCollection[Food], items: Seq[Food]): MongoCollection[Food] = {
  97. val futures: Seq[Future[Completed]] = items.map(coll.insertOne(_).toFuture)
  98. futures.map(Await.ready(_, 5 minutes))
  99. coll
  100. }
  101. "FoodController PUT /food" should {
  102. "return the resulting food object and insert into the DB" in {
  103. val fakeRequ: FakeRequest[JsValue] = FakeRequest[JsValue](PUT, "/food", FakeHeaders(), exampleJson1)
  104. .withHeaders(HeaderNames.CONTENT_TYPE -> "application/json")
  105. withEmbedMongoFixture() { mongodProps: MongodProps =>
  106. val coll: MongoCollection[Food] = getDBColl
  107. val controller: FoodController = new FoodController(coll)
  108. val result = controller.put().apply(fakeRequ)
  109. status(result) mustBe OK
  110. contentType(result) mustBe Some("application/json")
  111. val resultJs: JsObject = contentAsJson(result).asInstanceOf[JsObject]
  112. resultJs - "_id" mustBe exampleJson1
  113. Await.result(coll.countDocuments().toFuture, 5 minutes) mustBe 1
  114. Await.result(coll.find().first().toFuture, 5 minutes) mustBe resultJs.as[Food]
  115. }
  116. }
  117. "return an error when given an empty request and not " +
  118. "insert into the DB" in {
  119. val fakeRequ = FakeRequest(PUT, "/food", FakeHeaders(), "")
  120. .withHeaders(HeaderNames.CONTENT_TYPE -> "application/json")
  121. withEmbedMongoFixture() { mongodProps: MongodProps =>
  122. val coll: MongoCollection[Food] = getDBColl
  123. val controller: FoodController = new FoodController(coll)
  124. val result = controller.put().apply(fakeRequ)
  125. status(result) mustBe Status.BAD_REQUEST
  126. Await.result(coll.countDocuments().toFuture, 5 minutes) mustBe 0
  127. }
  128. }
  129. "return an error when given an invalid request and not " +
  130. "insert into the DB" in {
  131. val fakeRequ = FakeRequest(PUT, "/food", FakeHeaders(), brokenExampleJson1)
  132. .withHeaders(HeaderNames.CONTENT_TYPE -> "application/json")
  133. withEmbedMongoFixture() { mongodProps: MongodProps =>
  134. val coll: MongoCollection[Food] = getDBColl
  135. val controller: FoodController = new FoodController(coll)
  136. val result = controller.put().apply(fakeRequ)
  137. status(result) mustBe Status.BAD_REQUEST
  138. Await.result(coll.countDocuments().toFuture, 5 minutes) mustBe 0
  139. }
  140. }
  141. "return the resulting object with default values and " +
  142. "insert into the DB" in {
  143. val fakeRequ = FakeRequest(PUT, "/food", FakeHeaders(), strippedExampleJson1)
  144. .withHeaders(HeaderNames.CONTENT_TYPE -> "application/json")
  145. withEmbedMongoFixture() { mongodProps: MongodProps =>
  146. val coll: MongoCollection[Food] = getDBColl
  147. val controller: FoodController = new FoodController(coll)
  148. val result = controller.put().apply(fakeRequ)
  149. status(result) mustBe OK
  150. contentType(result) mustBe Some("application/json")
  151. val resultJs: JsObject = contentAsJson(result).asInstanceOf[JsObject]
  152. resultJs - "_id" mustBe exampleJson1
  153. Await.result(coll.countDocuments().toFuture, 5 minutes) mustBe 1
  154. Await.result(coll.find().first().toFuture, 5 minutes) mustBe resultJs.as[Food]
  155. }
  156. }
  157. }
  158. "FoodController GET /food/:id" should {
  159. "return the correct food object" in {
  160. val fakeRequ: FakeRequest[JsValue] = FakeRequest[JsValue](GET, s"/food/${exampleFood1._id}", FakeHeaders(), JsString(""))
  161. withEmbedMongoFixture() { mongodProps: MongodProps =>
  162. val coll: MongoCollection[Food] = initDB(getDBColl, Seq(exampleFood1, exampleFood2))
  163. val controller: FoodController = new FoodController(coll)
  164. val result = controller.put().apply(fakeRequ)
  165. status(result) mustBe OK
  166. contentType(result) mustBe Some("application/json")
  167. val resultJs: JsObject = contentAsJson(result).asInstanceOf[JsObject]
  168. resultJs.value.get("_id").toString mustBe exampleFood1._id
  169. resultJs - "_id" mustBe exampleJson1
  170. }
  171. }
  172. "return an error when given an empty request and not " +
  173. "insert into the DB" in {
  174. val fakeRequ: FakeRequest[JsValue] = FakeRequest[JsValue](GET, s"/food/0", FakeHeaders(), JsString(""))
  175. withEmbedMongoFixture() { mongodProps: MongodProps =>
  176. val coll: MongoCollection[Food] = getDBColl
  177. val controller: FoodController = new FoodController(coll)
  178. val result = controller.put().apply(fakeRequ)
  179. status(result) mustBe Status.NOT_FOUND
  180. }
  181. }
  182. }
  183. }