Есть ли ошибка в тестировании Play2 с FakeRequests и фрагментированными ответами (Enumerator)?

Я столкнулся с проблемой в Play 2.3.7 при тестировании действия, которое возвращает фрагментированный ответ с помощью перечислителя:

def text = Action {
    Ok.chunked(Enumerator("abc"))
}

Используя curl http://localhost:9000/text, я получаю ожидаемый результат: abc, но следующий тест:

class ApplicationSpec extends Specification {
    "Application" should {
        "stream text" in new WithApplication{
            val request = route(FakeRequest(GET, "/text")).get
            contentAsString(request) mustEqual "abc"
        }
    }
}

терпит неудачу с ошибкой сравнения:

[info] Application should
[info] x stream text
[error]    '3
[error]    abc
[error]    0
[error]    
[error]    ' is not equal to 'abc' (ApplicationSpec.scala:31)

Откуда берутся эти лишние символы? Я подозреваю, что это может быть проблема с FakeRequest и Enumerators? В более сложном случае с конкатенированными перечислителями в действии будут смешаны символы между содержимым, созданным перечислителями.


person Stefan K.    schedule 11.02.2015    source источник


Ответы (1)


Это известная проблема, которая была исправлена ​​в грядущей версии Play 2.4, но недоступна в версии 2.3.x. Дополнительные символы вводятся из фрагментированной кодировки. Они представляют длины фрагментов в шестнадцатеричном формате, которые находятся в начале каждого тела ответа HTTP. Старый помощник по игровому тесту просто объединяет их вместе, а не отсеивает.

Я использовал следующий код, чтобы обойти проблему на 2.3.x на данный момент (спасибо marcuslinke сообщению из этого проблема с github):

import scala.concurrent._
import scala.concurrent.duration._
import play.api.mvc._
import play.api.libs.iteratee._
import akka.util.Timeout

def contentAsBytes(of: Future[Result])(implicit timeout: Timeout): Array[Byte] = {
    val result = Await.result(of, timeout.duration)
    val eBytes = result.header.headers.get(TRANSFER_ENCODING) match {
        case Some("chunked") => result.body &> Results.dechunk
        case _ => result.body
    }
    Await.result(eBytes |>>> Iteratee.consume[Array[Byte]](), timeout.duration)
}

Который я использую в тестах (specs2) следующим образом:

new String(contentAsBytes(result)) must equalTo("expected value")

Для справки, вот запрос на извлечение, который был объединен с мастером.

person Michael Zajac    schedule 11.02.2015