From e6f0ac0289ad3685e2af5dfc17ee79c3c1170bdf Mon Sep 17 00:00:00 2001 From: Piotr Buda Date: Mon, 31 Jul 2017 11:59:08 +0200 Subject: #7: Add asFile and asPath responses --- tests/src/test/resources/binaryfile.jpg | Bin 0 -> 42010 bytes tests/src/test/resources/textfile.txt | 100 ++++++++++++++++++ .../scala/com/softwaremill/sttp/BasicTests.scala | 115 ++++++++++++++++++++- .../scala/com/softwaremill/sttp/testHelpers.scala | 40 ++++++- 4 files changed, 249 insertions(+), 6 deletions(-) create mode 100644 tests/src/test/resources/binaryfile.jpg create mode 100644 tests/src/test/resources/textfile.txt (limited to 'tests') diff --git a/tests/src/test/resources/binaryfile.jpg b/tests/src/test/resources/binaryfile.jpg new file mode 100644 index 0000000..b9f5c5a Binary files /dev/null and b/tests/src/test/resources/binaryfile.jpg differ diff --git a/tests/src/test/resources/textfile.txt b/tests/src/test/resources/textfile.txt new file mode 100644 index 0000000..9904f90 --- /dev/null +++ b/tests/src/test/resources/textfile.txt @@ -0,0 +1,100 @@ +- Lorem ipsum dolor sit amet +- Vivamus sem ipsum. +- Ut molestie. +- Donec. +- Fusce non porta. +- Nulla ac metus. Morbi mattis. +- Etiam varius. +- Nulla. +- Phasellus id mollis. +- Suspendisse at. +- Quisque nec leo velit. +- Fusce. +- Maecenas nec tristique senectus et. +- Integer vestibulum lorem fermentum. +- Vestibulum consectetuer dolor. +- Lorem ipsum in. +- Fusce condimentum auctor scelerisque, wisi. +- Quisque. +- Curae. +- Curae, Nullam. +- Curae, Integer. +- Vestibulum dignissim massa. Donec. +- Pellentesque sed sem. +- Vivamus est. +- Maecenas elit sed est. +- Quisque sed tellus. +- Cum sociis natoque penatibus et. +- Fusce aliquam. +- Donec. +- Sed elementum, sapien accumsan odio. +- Nam mattis, magna lectus, tincidunt. +- Pellentesque scelerisque a, sodales. +- Sed sed condimentum. +- Curae, In nonummy. Phasellus adipiscing. +- Vestibulum quis diam mollis. +- Sed eros. Duis ipsum. +- Aenean pellentesque at, mollis tempus. +- Cras ornare facilisis sodales. Aenean. +- Cum sociis natoque penatibus. +- Donec id nulla. +- Quisque ut sapien. +- Phasellus purus. Proin ultricies. +- Aliquam auctor neque. Nunc. +- Nam nunc fringilla non, vehicula. +- Morbi molestie, felis ut lobortis. +- Nulla quis. +- In. +- Phasellus laoreet urna. +- Lorem ipsum. +- Phasellus. +- Class aptent taciti sociosqu ad. +- Sed lacinia. +- Pellentesque dapibus diam. Duis. +- Suspendisse est. Curabitur. +- Fusce condimentum justo. +- Aenean congue quis, faucibus. +- Ut pharetra leo. Donec. +- Fusce. +- Donec porta. +- Pellentesque orci. +- Sed. +- Quisque rutrum, wisi vulputate wisi. +- Cum sociis. +- Cras. +- Sed eros. Curabitur. +- Proin in velit wisi, tempor. +- Quisque eu. +- Proin. +- Nam pellentesque sed, imperdiet aliquam. +- Mauris euismod. Sed euismod orci. +- Etiam. +- Donec. +- Fusce wisi a metus. Proin. +- Phasellus quis. +- Donec non imperdiet. +- Aenean vel bibendum a, laoreet. +- Fusce non enim. Phasellus vulputate. +- Donec urna elit, sit. +- Pellentesque habitant morbi. +- Nulla ante. Curabitur elit. Donec. +- Cum sociis natoque penatibus. +- Maecenas eget leo at. +- Cum sociis natoque penatibus et. +- Vivamus lacus. +- Integer. +- Curae. +- Maecenas rhoncus. Morbi. +- Aenean posuere. +- Duis. +- Suspendisse a odio fermentum libero. +- Nam enim. Fusce enim. In. +- Maecenas. +- Lorem ipsum primis. +- Curabitur ac turpis semper sed. +- Quisque condimentum. Donec sit. +- Integer convallis non, posuere. +- Etiam vulputate, odio. +- Proin id lorem. Donec quis. +- Curae, Sed nec augue. +- Aliquam ut turpis. \ No newline at end of file diff --git a/tests/src/test/scala/com/softwaremill/sttp/BasicTests.scala b/tests/src/test/scala/com/softwaremill/sttp/BasicTests.scala index 36c82ef..28e210f 100644 --- a/tests/src/test/scala/com/softwaremill/sttp/BasicTests.scala +++ b/tests/src/test/scala/com/softwaremill/sttp/BasicTests.scala @@ -1,7 +1,8 @@ package com.softwaremill.sttp -import java.io.ByteArrayInputStream +import java.io.{ByteArrayInputStream, IOException} import java.nio.ByteBuffer +import java.nio.file.Paths import java.time.{ZoneId, ZonedDateTime} import akka.http.scaladsl.coding.{Deflate, Gzip, NoCoding} @@ -14,7 +15,7 @@ import akka.http.scaladsl.server.directives.Credentials import com.softwaremill.sttp.akkahttp.AkkaHttpSttpHandler import com.typesafe.scalalogging.StrictLogging import org.scalatest.concurrent.{IntegrationPatience, ScalaFutures} -import org.scalatest.{BeforeAndAfterAll, FlatSpec, Matchers} +import org.scalatest.{path => _, _} import better.files._ import com.softwaremill.sttp.asynchttpclient.cats.CatsAsyncHttpClientHandler import com.softwaremill.sttp.asynchttpclient.future.FutureAsyncHttpClientHandler @@ -32,14 +33,27 @@ class BasicTests with Matchers with BeforeAndAfterAll with ScalaFutures + with OptionValues with StrictLogging with IntegrationPatience with TestHttpServer - with ForceWrapped { + with ForceWrapped + with BeforeAndAfterEach { + + override def afterEach() { + val file = File(outPath) + if (file.exists) file.delete() + } private def paramsToString(m: Map[String, String]): String = m.toList.sortBy(_._1).map(p => s"${p._1}=${p._2}").mkString(" ") + private val textFile = + new java.io.File("tests/src/test/resources/textfile.txt") + private val binaryFile = + new java.io.File("tests/src/test/resources/binaryfile.jpg") + private val outPath = Paths.get("out") + override val serverRoutes: Route = pathPrefix("echo") { pathPrefix("form_params") { @@ -115,6 +129,12 @@ class BasicTests encodeResponseWith(Gzip, Deflate, NoCoding) { complete("I'm compressed!") } + } ~ pathPrefix("download") { + path("binary") { + getFromFile(binaryFile) + } ~ path("text") { + getFromFile(textFile) + } } override def port = 51823 @@ -402,6 +422,95 @@ class BasicTests resp.body should be(decompressedBody) } } + + def downloadFileTests(): Unit = { + import CustomMatchers._ + + name should "download a binary file using asFile" in { + val file = outPath.resolve("binaryfile.jpg").toFile + val req = + sttp.get(uri"$endpoint/download/binary").response(asFile(file)) + val resp = req.send().force() + + resp.body shouldBe file + file should exist + file should haveSameContentAs(binaryFile) + } + + name should "download a text file using asFile" in { + val file = outPath.resolve("textfile.txt").toFile + val req = + sttp.get(uri"$endpoint/download/text").response(asFile(file)) + val resp = req.send().force() + + resp.body shouldBe file + file should exist + file should haveSameContentAs(textFile) + } + + name should "download a binary file using asPath" in { + val path = outPath.resolve("binaryfile.jpg") + val req = + sttp.get(uri"$endpoint/download/binary").response(asPath(path)) + val resp = req.send().force() + + resp.body shouldBe path + path.toFile should exist + path.toFile should haveSameContentAs(binaryFile) + } + + name should "download a text file using asPath" in { + val path = outPath.resolve("textfile.txt") + val req = + sttp.get(uri"$endpoint/download/text").response(asPath(path)) + val resp = req.send().force() + + resp.body shouldBe path + path.toFile should exist + path.toFile should haveSameContentAs(textFile) + } + + name should "fail at trying to save file to a restricted location" in { + val path = Paths.get("/").resolve("textfile.txt") + val req = + sttp.get(uri"$endpoint/download/text").response(asPath(path)) + val caught = intercept[IOException] { + req.send().force() + } + + caught.getMessage shouldBe "Permission denied" + } + + name should "fail when file exists and overwrite flag is false" in { + val path = outPath.resolve("textfile.txt") + path.toFile.getParentFile.mkdirs() + path.toFile.createNewFile() + val req = + sttp.get(uri"$endpoint/download/text").response(asPath(path)) + + val caught = intercept[IOException] { + req.send().force() + } + + caught.getMessage shouldBe s"File ${path.toFile.getAbsolutePath} exists - overwriting prohibited" + + } + + name should "not fail when file exists and overwrite flag is true" in { + val path = outPath.resolve("textfile.txt") + path.toFile.getParentFile.mkdirs() + path.toFile.createNewFile() + val req = + sttp + .get(uri"$endpoint/download/text") + .response(asPath(path, overwrite = true)) + val resp = req.send().force() + + resp.body shouldBe path + path.toFile should exist + path.toFile should haveSameContentAs(textFile) + } + } } override protected def afterAll(): Unit = { diff --git a/tests/src/test/scala/com/softwaremill/sttp/testHelpers.scala b/tests/src/test/scala/com/softwaremill/sttp/testHelpers.scala index 558e9dd..59e1612 100644 --- a/tests/src/test/scala/com/softwaremill/sttp/testHelpers.scala +++ b/tests/src/test/scala/com/softwaremill/sttp/testHelpers.scala @@ -1,14 +1,20 @@ package com.softwaremill.sttp +import java.nio.file.{Files, Paths} +import java.{io, util} + import akka.actor.ActorSystem import akka.http.scaladsl.Http import akka.http.scaladsl.server.Route import akka.stream.ActorMaterializer import org.scalatest.{BeforeAndAfterAll, Suite} import org.scalatest.concurrent.ScalaFutures +import org.scalatest.exceptions.TestFailedException +import org.scalatest.matchers.{MatchResult, Matcher} import scala.concurrent.Future import scala.language.higherKinds +import scalaz._ trait TestHttpServer extends BeforeAndAfterAll with ScalaFutures { this: Suite => @@ -41,23 +47,35 @@ trait ForceWrapped extends ScalaFutures { this: Suite => } val future = new ForceWrappedValue[Future] { override def force[T](wrapped: Future[T]): T = - wrapped.futureValue + try { + wrapped.futureValue + } catch { + case e: TestFailedException if e.getCause != null => throw e.getCause + } } val scalazTask = new ForceWrappedValue[scalaz.concurrent.Task] { override def force[T](wrapped: scalaz.concurrent.Task[T]): T = - wrapped.unsafePerformSync + wrapped.unsafePerformSyncAttempt match { + case -\/(error) => throw error + case \/-(value) => value + } } val monixTask = new ForceWrappedValue[monix.eval.Task] { import monix.execution.Scheduler.Implicits.global override def force[T](wrapped: monix.eval.Task[T]): T = - wrapped.runAsync.futureValue + try { + wrapped.runAsync.futureValue + } catch { + case e: TestFailedException => throw e.getCause + } } val catsIo = new ForceWrappedValue[cats.effect.IO] { override def force[T](wrapped: cats.effect.IO[T]): T = wrapped.unsafeRunSync } } + implicit class ForceDecorator[R[_], T](wrapped: R[T]) { def force()(implicit fwv: ForceWrappedValue[R]): T = fwv.force(wrapped) } @@ -72,3 +90,19 @@ object EvalScala { tb.eval(tb.parse(code)) } } + +object CustomMatchers { + class FileContentsMatch(file: java.io.File) extends Matcher[java.io.File] { + override def apply(left: io.File): MatchResult = { + val inBA = Files.readAllBytes(Paths.get(left.getAbsolutePath)) + val expectedBA = Files.readAllBytes(Paths.get(file.getAbsolutePath)) + MatchResult( + util.Arrays.equals(inBA, expectedBA), + "The files' contents are not the same", + "The files' contents are the same" + ) + } + } + + def haveSameContentAs(file: io.File) = new FileContentsMatch(file) +} -- cgit v1.2.3