Skip to content

Commit

Permalink
Testing...
Browse files Browse the repository at this point in the history
  • Loading branch information
RadoBuransky committed Jan 10, 2014
1 parent 9932055 commit 0f10e3f
Show file tree
Hide file tree
Showing 8 changed files with 219 additions and 58 deletions.
11 changes: 6 additions & 5 deletions app/AppLoader.scala
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import controllers.GymController
import controllers.{RouteController, GymController}
import models.data.impl.MongoRouteDaoComponent
import models.domain.services.impl.{AuthServiceComponentImpl, GymServiceComponentImpl}
import models.domain.services.impl.{PhotoServiceComponentImpl, RouteServiceComponentImpl, AuthServiceComponentImpl, GymServiceComponentImpl}
import play.api.Play
import play.api.Play.current

/**
* Created by rado on 04/01/14.
*/
package object AppLoader {
val gymController = new GymController with MongoRouteDaoComponent with GymServiceComponentImpl
with AuthServiceComponentImpl with PlayConfiguration

val routeController = new RouteController with RouteServiceComponentImpl with GymServiceComponentImpl
with MongoRouteDaoComponent with AuthServiceComponentImpl with PlayConfiguration
with PhotoServiceComponentImpl

trait PlayConfiguration {
val configuration = Play.configuration
}
Expand Down
69 changes: 28 additions & 41 deletions app/controllers/RouteController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ import javax.imageio.ImageWriteParam
import models.contract.JsonMapper
import models.domain.model.{Discipline, Tag}
import Discipline.Bouldering
import models.domain.services.GymService
import models.domain.services.PhotoService
import models.domain.services._
import play.api.{Routes, Logger}
import play.api.libs.Files.TemporaryFile
import play.api.libs.json.Json
Expand All @@ -24,7 +23,6 @@ import play.api.mvc.MultipartFormData.FilePart
import play.modules.reactivemongo.MongoController
import play.modules.reactivemongo.json.collection.JSONCollection
import reactivemongo.bson.BSONObjectID
import models.domain.services.AuthService
import models.data.model.{JsonFormats, Route}
import JsonFormats._
import play.modules.reactivemongo.json.BSONFormats._
Expand All @@ -34,44 +32,45 @@ import play.modules.reactivemongo.json.collection.JSONCollection
import play.mvc.Http
import models.data.model.Route
import models.domain.model.Tag
import play.api.mvc.MultipartFormData.FilePart
import models.data.model.Route
import scala.Some
import play.modules.reactivemongo.json.collection.JSONCollection
import scala.util.{Success, Failure}

trait RouteController extends Controller with MongoController {
this: RouteServiceComponent with GymServiceComponent with AuthServiceComponent
with PhotoServiceComponent =>

object RouteController extends Controller with MongoController {
private val jpegMime = "image/jpeg"
private val photoWidth = 800

def flag(gymHandle: String, routeId: String, flagId: String) = Action.async {
incFlag(routeId, flagId) map { lastError => Ok }
routeService.incFlag(routeId, flagId).map { result =>
Ok
}
}

def delete(gymHandle: String, routeId: String) = Action.async { request =>
// Get gym by handle
val gym = GymService.get(gymHandle)

if (!AuthService.isAdmin(request.cookies, gym)) {
future { Unauthorized }
val isAdminTry = gymService.get(gymHandle).flatMap { gym =>
authService.isAdmin(request.cookies, gym)
}
else {
getBoulder(routeId).map { route =>
route match {
case None => NotFound
case Some(route) => {
// Delete file from S3
val removePhotoFuture = logFuture("removePhoto") {
PhotoService.remove(route.fileName)
}
val disableRouteFuture = logFuture("disableRoute") {
disableRoute(routeId)
}

for {
rp <- removePhotoFuture
dr <- disableRouteFuture
} yield true
isAdminTry match {
case Failure(t) => Promise.successful(InternalServerError).future
case Success(isAdmin) if isAdmin => {
routeService.getByRouteId(routeId).map { route =>
for {
rp <- photoService.remove(route.fileName)
dr <- routeService.delete(routeId)
} yield ()

Ok
}
Ok
} recover {
case _ => NotFound
}
}
case _ => Promise.successful(Unauthorized).future
}
}

Expand Down Expand Up @@ -139,18 +138,6 @@ object RouteController extends Controller with MongoController {
}
}

private def incFlag(routeId: String, flagId: String) = {
db.collection[JSONCollection]("route").
update(Json.obj("_id" -> BSONObjectID(routeId)),
Json.obj("$inc" -> Json.obj(("flags." + flagId) -> 1)))
}

private def disableRoute(routeId: String) = {
db.collection[JSONCollection]("route").
update(Json.obj("_id" -> BSONObjectID(routeId)),
Json.obj("$set" -> Json.obj("enabled" -> false)))
}

private def getBoulder(routeId: String): Future[Option[Route]] = {
db.collection[JSONCollection]("route").
find(Json.obj("_id" -> BSONObjectID(routeId))).
Expand Down Expand Up @@ -255,7 +242,7 @@ object RouteController extends Controller with MongoController {
case _ => false
}
}

private def logFuture[T](msg: String)(body: =>T): Future[T] = {
val f = Future[T](body)
f.onFailure {
Expand Down
12 changes: 8 additions & 4 deletions app/models/domain/services/PhotoService.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import fly.play.s3._
import java.net.URL
import play.api.Logger
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future

object PhotoService {
private val BucketName = "jugjane"
Expand All @@ -24,9 +25,12 @@ object PhotoService {
def getUrl(fileName: String): URL = {
new URL(UrlTemplate.format(BucketName, fileName))
}

def remove(fileName: String) = {
val bucket = S3(BucketName)
bucket.remove(fileName)
}

trait PhotoServiceComponent {
def photoService: PhotoService

trait PhotoService {
def remove(fileName: String): Future[Unit]
}
}
19 changes: 19 additions & 0 deletions app/models/domain/services/impl/PhotoServiceImpl.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package models.domain.services.impl

import models.domain.services.PhotoServiceComponent
import scala.concurrent.Future
import common.Utils._
import fly.play.s3.S3

trait PhotoServiceComponentImpl extends PhotoServiceComponent {
val photoService = new PhotoServiceImpl

class PhotoServiceImpl extends PhotoService {
private val bucketName = "jugjane"

def remove(fileName: String): Future[Unit] = {
notEmpty(fileName, "fileName")
S3(bucketName).remove(fileName)
}
}
}
6 changes: 2 additions & 4 deletions app/models/domain/services/impl/RouteServiceImpl.scala
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package models.domain.services.impl

import models.domain.services.{GymServiceComponent, RouteServiceComponent}
import scala.util.{Success, Failure, Try}
import common.Utils._
import scala.util.Try
import models.data.dao.RouteDaoComponent
import models.domain.{ model => dom }
import models.data.{ model => dat }
import scala.concurrent.{ExecutionContext, Promise, Future}
import models.JugjaneException
import scala.concurrent.{ExecutionContext, Future}
import models.domain.model.{Tag, Discipline, HoldsColor}
import ExecutionContext.Implicits.global

Expand Down
8 changes: 4 additions & 4 deletions conf/routes
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ GET /*path/ com.jugjane.controllers.Application.untrail(

GET /climbing/:gymHandle/new AppLoader.gymController.newBoulder(gymHandle)
GET /climbing/:gymHandle AppLoader.gymController.get(gymHandle, s: Option[String])
POST /climbing/:gymHandle/new controllers.RouteController.upload(gymHandle)
GET /climbing/:gymHandle/:routeId controllers.RouteController.get(gymHandle, routeId)
DELETE /climbing/:gymHandle/:routeId controllers.RouteController.delete(gymHandle, routeId)
PUT /climbing/:gymHandle/:routeId/flag/:flagId controllers.RouteController.flag(gymHandle, routeId, flagId)
POST /climbing/:gymHandle/new AppLoader.routeController.upload(gymHandle)
GET /climbing/:gymHandle/:routeId AppLoader.routeController.get(gymHandle, routeId)
DELETE /climbing/:gymHandle/:routeId AppLoader.routeController.delete(gymHandle, routeId)
PUT /climbing/:gymHandle/:routeId/flag/:flagId AppLoader.routeController.flag(gymHandle, routeId, flagId)

GET /robots.txt controllers.Assets.at(path="/public", file="robots.txt")
GET /sitemap.xml controllers.Assets.at(path="/public", file="sitemap.xml")
Expand Down
17 changes: 17 additions & 0 deletions test/TestData.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.jugjane.test

import models.domain.model.{Tag, Discipline, Route}
import models.domain.gym.{DemoGradingSystem, Demo}

object TestData {
val route1: Route = Route("123",
Demo,
"/home/rado/123.jpeg",
DemoGradingSystem.getById("demo3").get,
Demo.holdColors(0),
"blaaa",
Discipline.Bouldering,
Tag.categories(0) :: Tag.categories(3) :: Nil,
Tag.flags(1).setCounter(10) :: Tag.flags(0) :: Tag.flags(4).setCounter(0) :: Nil,
true)
}
135 changes: 135 additions & 0 deletions test/controllers/RouteControllerSpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package controllers

import org.specs2.mutable.Specification
import org.specs2.mock.Mockito
import org.specs2.specification.Scope
import models.domain.services.{PhotoServiceComponent, RouteServiceComponent, AuthServiceComponent, GymServiceComponent}
import scala.concurrent.Promise
import play.api.test.FakeRequest
import play.api.test.Helpers._
import models.JugjaneException
import scala.util.{Success, Failure}
import models.domain.gym.Demo
import play.api.http.Status._
import scala.util.Success
import models.JugjaneException
import scala.util.Failure
import scala.util.Success
import models.JugjaneException
import scala.util.Failure
import com.jugjane.test.TestData

class RouteControllerSpec extends Specification with Mockito {
"flag" should {
"delegate to service" in new RouteControllerScope {
// Setup
routeService.incFlag("123", "aaa") returns Promise.successful().future

// Execute
val result = flag("demo", "123", "aaa")(FakeRequest(PUT, "/climbing/demo/123/flag/aaa"))

// Assert
status(result) must equalTo(OK)

// Verfy
there was one(routeService).incFlag("123", "aaa")
}
}

"delete" should {
"fail for nonexisting gym" in new RouteControllerScope {
// Setup
gymService.get("demo").returns(Failure(new JugjaneException("x")))

// Execute
val result = delete("demo", "123")(FakeRequest(DELETE, "/climbing/demo/123"))

// Assert
status(result) must equalTo(INTERNAL_SERVER_ERROR)

// Verfy
there was one(gymService).get("demo")
}

"fail for failed authorization" in new RouteControllerScope {
// Setup
gymService.get("demo").returns(Success(Demo))
authService.isAdmin(any, any).returns(Failure(new JugjaneException("x")))

// Execute
val result = delete("demo", "123")(FakeRequest(DELETE, "/climbing/demo/123"))

// Assert
status(result) must equalTo(INTERNAL_SERVER_ERROR)

// Verfy
there was one(gymService).get("demo")
there was one(authService).isAdmin(any, any)
}

"fail for unauthorized access" in new RouteControllerScope {
// Setup
gymService.get("demo").returns(Success(Demo))
authService.isAdmin(any, any).returns(Success(false))

// Execute
val result = delete("demo", "123")(FakeRequest(DELETE, "/climbing/demo/123"))

// Assert
status(result) must equalTo(UNAUTHORIZED)

// Verfy
there was one(gymService).get("demo")
there was one(authService).isAdmin(any, any)
}

"fail for nonexisting route" in new RouteControllerScope {
// Setup
gymService.get("demo").returns(Success(Demo))
authService.isAdmin(any, any).returns(Success(true))
routeService.getByRouteId("123").returns(Promise.failed(new JugjaneException("x")).future)

// Execute
val result = delete("demo", "123")(FakeRequest(DELETE, "/climbing/demo/123"))

// Assert
status(result) must equalTo(NOT_FOUND)

// Verfy
there was one(gymService).get("demo")
there was one(authService).isAdmin(any, any)
there was one(routeService).getByRouteId("123")
}

"delete from S3 and DB" in new RouteControllerScope {
// Setup
gymService.get("demo").returns(Success(Demo))
authService.isAdmin(any, any).returns(Success(true))
routeService.getByRouteId("123").returns(Promise.successful(TestData.route1).future)
photoService.remove("/home/rado/123.jpeg").returns(Promise.successful().future)
routeService.delete("123").returns(Promise.successful().future)

// Execute
val result = delete("demo", "123")(FakeRequest(DELETE, "/climbing/demo/123"))

// Assert
status(result) must equalTo(OK)

// Verfy
there was one(gymService).get("demo")
there was one(authService).isAdmin(any, any)
there was one(routeService).getByRouteId("123")
there was one(photoService).remove("/home/rado/123.jpeg")
there was one(routeService).delete("123")
}
}

trait RouteControllerScope extends Scope with RouteController with RouteServiceComponent
with GymServiceComponent with AuthServiceComponent with PhotoServiceComponent {
val routeService: RouteService = mock[RouteService]
val gymService: GymService = mock[GymService]
val authService: AuthService = mock[AuthService]
val photoService: PhotoService = mock[PhotoService]
}

}

0 comments on commit 0f10e3f

Please sign in to comment.