Skip to content

Instantly share code, notes, and snippets.

@mnylen
Created April 6, 2012 19:11
Show Gist options
  • Save mnylen/2322134 to your computer and use it in GitHub Desktop.
Save mnylen/2322134 to your computer and use it in GitHub Desktop.
postMulti() helper for scalatra-test for making multipart/form-data requests. Useful when testing file uploads with scalatra-fileupload
class FileUploadSpec extends MutableScalatraSpec with ScalatraFileUploadTests {
"POST /upload" should {
"return 200" in {
val files = Map("file" -> new File("test/resources/hasselhoff.jpg"))
val params = Map("image" -> "true")
postMulti("/upload", files, params) {
status must_== 200
}
}
}
}
import org.apache.commons.io.IOUtils
import org.eclipse.jetty.http.HttpHeaders
import org.eclipse.jetty.testing.HttpTester
import org.eclipse.jetty.io.ByteArrayBuffer
import util.DynamicVariable
import org.scalatra.test.ScalatraTests
import java.net.HttpCookie
import java.io.{ByteArrayOutputStream, FileInputStream, File}
trait ScalatraFileUploadTests extends ScalatraTests {
private def makeRequest(method: String, path: String, files: Map[String, File], params: Map[String, String], headers: Map[String, String]): BinaryHttpTester = {
val boundary = "2ChY5dI4PKmv51s7Hs2n"
def reqContent = {
val out = new ByteArrayOutputStream()
def writeParamPart(param: (String, String)) {
out.write(
("--" + boundary + "\r\n" +
"Content-Disposition: form-data; name=\"" + param._1 + "\"\r\n\r\n" +
param._2 + "\r\n"
).getBytes
)
}
def writeFilePart(file: (String, File)) {
out.write(
("--" + boundary + "\r\n" +
"Content-Disposition: form-data; name=\"" + file._1 + "\"; filename=\"" + file._2.getName + "\"\r\n" +
"Content-Type: application/octet-stream\r\n\r\n"
).getBytes
)
IOUtils.copy(new FileInputStream(file._2), out)
out.write("\r\n".getBytes)
}
params.foreach(writeParamPart)
files.foreach(writeFilePart)
out.write(("--" + boundary + "--").getBytes)
out.toByteArray
}
val req = new BinaryHttpTester()
req.setVersion("HTTP/1.0")
req.setMethod(method)
req.setURI(path)
req.setHeader("Content-Type", "multipart/form-data; boundary=" + boundary)
headers.foreach( (header: (String, String)) =>
req.setHeader(header._1, header._2)
)
req.setContent(reqContent)
req
}
private val _response = new DynamicVariable[HttpTester](new HttpTester())
private val _cookies = new DynamicVariable[Seq[HttpCookie]](Nil)
private val _useSession = new DynamicVariable(false)
override def submit[A](req: HttpTester)(f: => A) = {
val res = new HttpTester("iso-8859-1")
req match {
case binaryReq: BinaryHttpTester => res.parse(tester.getResponses(binaryReq.generateByteArrayBuffer()).array(), req.getMethod == "HEAD")
case _ => res.parse(tester.getResponses(req.generate()), req.getMethod == "HEAD")
}
res.setContent(res.getContent match {
case null => ""
case content => content
})
_response.withValue(res) { f }
}
override def session[A](f: => A): A = {
_cookies.withValue(Nil) {
_useSession.withValue(true)(f)
}
}
// return the last response
override def response = _response.value
// shorthand for response.body
override def body = response.body
// shorthand for response.header
override def header = response.header
// shorthand for response.status
override def status = response.status
def postMulti[A](path: String, files: Map[String, File], params: Map[String, String], headers: Map[String, String])(f: => A): A = {
submit(makeRequest("POST", path, files, params, headers)) { f }
}
def postMulti[A](path: String, files: Map[String, File], params: Map[String, String])(f: => A): A = {
submit(makeRequest("POST", path, files, params, Map[String, String]())) { f }
}
}
class BinaryHttpTester extends HttpTester {
def setContent(content: Array[Byte]) {
_genContent = content
setLongHeader(HttpHeaders.CONTENT_LENGTH,_genContent.length);
}
def generateByteArrayBuffer(): ByteArrayBuffer = {
val tempContent = _genContent
_genContent = "".getBytes
val rawHttp = generate()
_genContent = tempContent
val bytes = rawHttp.getBytes.toList ::: _genContent.toList
new ByteArrayBuffer(bytes.toArray)
}
}
@mnylen
Copy link
Author

mnylen commented Apr 22, 2012

These are going to be added to Scalatra 2.1.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment