Last active
February 9, 2017 12:47
-
-
Save emrecelikten/58ae4a4cb572cfaeb525 to your computer and use it in GitHub Desktop.
Sample upload testing in Play Framework 2.3.1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package controllers | |
import play.api.mvc._ | |
object Application extends Controller { | |
def upload = Action(parse.multipartFormData) { | |
request => | |
if (request.body.files.isEmpty) BadRequest("Invalid file!") | |
else if (request.body.asFormUrlEncoded.isEmpty) BadRequest("Invalid data!") | |
else Ok("Everything is okay!") | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Routes | |
# This file defines all application routes (Higher priority routes first) | |
# ~~~~ | |
# Home page | |
POST /upload controllers.Application.upload | |
# Map static resources from the /public folder to the /assets URL path | |
GET /assets/*file controllers.Assets.at(path="/public", file) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package controllers | |
import java.io.{ByteArrayOutputStream, File} | |
import java.nio.charset.Charset | |
import java.nio.file.{Files, StandardCopyOption, StandardOpenOption} | |
import org.apache.http.entity.ContentType | |
import org.apache.http.entity.mime.MultipartEntityBuilder | |
import org.specs2.mutable.Specification | |
import play.api.http.{ContentTypeOf, Writeable} | |
import play.api.libs.Files.TemporaryFile | |
import play.api.mvc.MultipartFormData.FilePart | |
import play.api.mvc.{MultipartFormData, Result} | |
import play.api.test.Helpers._ | |
import play.api.test.{FakeHeaders, FakeRequest, WithApplication} | |
import scala.concurrent.Future | |
class UploadTest extends Specification { | |
// Uses ideas from | |
// https://stackoverflow.com/questions/13352618/how-to-test-actions-that-expect-an-uploaded-file-in-play-framework-version-2-0 | |
// https://stackoverflow.com/questions/15133794/writing-a-test-case-for-file-uploads-in-play-2-1-and-scala | |
/** | |
* An ugly way to create multipartFormData using Apache HTTP MultipartEntityBuilder. | |
* | |
* The reason for def instead of a implicit Writeable instance is because we need multipart boundary to pass into | |
* ContentTypeOf constructor and creating a Writeable requires a ContentTypeOf instance. | |
* | |
* @param request fake request on which the Writeable instance will be created | |
*/ | |
def writeableOf_multipartFormData(request: FakeRequest[MultipartFormData[TemporaryFile]]) = { | |
val builder = MultipartEntityBuilder.create() | |
request.body.dataParts.foreach { case (k, vs) => builder.addTextBody(k, vs.mkString)} | |
// ContentType part is necessary here because it gets parsed as a DataPart otherwise. | |
request.body.files.foreach { case f => builder.addBinaryBody(f.filename, f.ref.file, ContentType.create(f.contentType.get, null: Charset), f.filename)} | |
val entity = builder.build() | |
implicit val contentTypeOf_MultipartFormData: ContentTypeOf[MultipartFormData[TemporaryFile]] = ContentTypeOf[MultipartFormData[TemporaryFile]](Some(entity.getContentType.getValue)) | |
Writeable[MultipartFormData[TemporaryFile]] { | |
(mfd: MultipartFormData[TemporaryFile]) => | |
val outputStream = new ByteArrayOutputStream() | |
entity.writeTo(outputStream) | |
outputStream.toByteArray | |
} | |
} | |
/** | |
* Creates a fake request to given URL and sends it. | |
* | |
* @param url url of the controller to send the request | |
* @param parameters some parameters that you would like to pass as a data part | |
*/ | |
def sendUploadRequest(url: String, file: File, mimeType: String, parameters: Map[String, String]): Future[Result] = { | |
// Your original file will be deleted after the controller executes if you don't do the copy part below | |
val tempFile = TemporaryFile("TEST_REMOVE_") | |
Files.copy(file.toPath, tempFile.file.toPath, StandardCopyOption.REPLACE_EXISTING) | |
val part = FilePart[TemporaryFile](key = tempFile.file.getName, filename = tempFile.file.getName, contentType = Some(mimeType), ref = tempFile) | |
val formData = MultipartFormData(dataParts = parameters.map { case (k, v) => k -> Seq(v)}, files = Seq(part), badParts = Nil, missingFileParts = Nil) | |
val request = FakeRequest("POST", url, FakeHeaders(), formData) | |
implicit val writeable = writeableOf_multipartFormData(request) | |
route(request)(writeable).get | |
} | |
"Upload" should { | |
"pass" in new WithApplication { | |
val tempFile = TemporaryFile("TEST_") | |
val fileRef = tempFile.file | |
Files.write(fileRef.toPath, """{"hello":"world"}""".getBytes, StandardOpenOption.WRITE) | |
val parameters = Map("foo" -> "bar") | |
val future = sendUploadRequest(controllers.routes.Application.upload().url, fileRef, "application/json", parameters) | |
status(future) ==== OK | |
contentAsString(future) ==== "Everything is okay!" | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi @emrecelikten, I've got a question. Why you should pass writable implicit value as explicitly?