0

He guys,

I'm having issues with testing play controller that handles multipart form data. It expects text field and some files.

The controller uses temporary files def insert(): Action[MultipartFormData[TemporaryFile]].

It works fine on production but I'm trying to add tests and I can't figure out how to properly create test request.

I first tried:

        val formData: MultipartFormData[TemporaryFile] = MultipartFormData(
          dataParts = Map(
            "json" -> Seq(Json.stringify(Json.toJson(newCreateRequest(name = "library".some))))
          ),
          files = Seq(filePart),
          badParts = Seq.empty
        )
        
        val request = requestWithToken.withMultipartFormDataBody(formData)
        val result = controller.insert()(request) 

but it tells me boundary is missing so I tried explicitly setting content type header:

        FakeRequest()
            .withHeaders(
              "Content-Type" -> "multipart/form-data; boundary=----geckoformboundary689e6c2fb6158cafd1b47222ed5f83d3")

Now it doesn't make sense as MultipartFormData doesn't know boundary I used and I don't see any way to set it there. Anyway I'm getting bad request "Unexpected end of input".

I gave up with this approach and started creating raw request just to see if I get any other result.

        val boundary = "----geckoformboundary689e6c2fb6158cafd1b47222ed5f83d3"
        val body = """------geckoformboundary689e6c2fb6158cafd1b47222ed5f83d3
                     |Content-Disposition: form-data; name="json"
                     |
                     |{"name":"test"}
                     |------geckoformboundary689e6c2fb6158cafd1b47222ed5f83d3--
                     |""".stripMargin

And obviously creating request with content type and content length headers.

Nothing seems to work.

Since I added boundary I'm getting "Unexpected end of input".

I tried everything using ByteString instead of string body, using string body but replacing line endings.

I even tried running the test in a loop where iterator is being used to set content length in case the length is being calculated differently.

I obviously also tried with empty request (empty files or empty both text and file fields).

Nothing. I'm aways getting Unexpected end of input.

Has anyone had any luck with testing this stuff?

I'm running scala 2.13.16 and play 3.0.6.

1 Answer 1

0

As per one of the test available in Play Framework codebase, you should be able to write something like the following:

      val boundary = "-----------------------------14568445977970839651285587160"
      val header =
        s"--$boundary\r\n" +
          "Content-Disposition: form-data; name=\"uploadedfile\"; filename=\"uploadedfile.txt\"\r\n" +
          "Content-Type: application/octet-stream\r\n" +
          "\r\n"
      val content = Array.ofDim[Byte](fileSize)
      val footer =
        "\r\n" +
          "\r\n" +
          s"--$boundary--\r\n"

      val body = Source(
        ByteString(header) ::
          ByteString(content) ::
          ByteString(footer) ::
          Nil
      )

      val bodySize = header.length + fileSize + footer.length

      val request = FakeRequest(
        method = "POST",
        uri = "/x",
        headers = FakeHeaders(
          Seq("Content-Type" -> s"multipart/form-data; boundary=$boundary", "Content-Length" -> bodySize.toString)
        ),
        body = body
      )
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.