aboutsummaryrefslogtreecommitdiff
path: root/tests/src/test/scala/com/softwaremill/sttp/BasicTests.scala
blob: 597c042d3b4b604c5981429214c545a18bc69671 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package com.softwaremill.sttp

import java.io.ByteArrayInputStream
import java.net.URI
import java.nio.ByteBuffer

import akka.stream.ActorMaterializer
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.server.Directives._
import com.softwaremill.sttp.akkahttp.AkkaHttpSttpHandler
import com.typesafe.scalalogging.StrictLogging
import org.scalatest.concurrent.{IntegrationPatience, ScalaFutures}
import org.scalatest.{BeforeAndAfterAll, FlatSpec, Matchers}
import better.files._

import scala.concurrent.Future
import scala.language.higherKinds

class BasicTests extends FlatSpec with Matchers with BeforeAndAfterAll with ScalaFutures with StrictLogging with IntegrationPatience {
  private def paramsToString(m: Map[String, String]): String = m.toList.sortBy(_._1).map(p => s"${p._1}=${p._2}").mkString(" ")

  private val serverRoutes =
    path("echo") {
      get {
        parameterMap { params =>
          complete(List("GET", "/echo", paramsToString(params)).filter(_.nonEmpty).mkString(" "))
        }
      } ~
        post {
          parameterMap { params =>
            entity(as[String]) { body: String =>
              complete(List("POST", "/echo", paramsToString(params), body).filter(_.nonEmpty).mkString(" "))
            }
          }
        }
    }

  private implicit val actorSystem: ActorSystem = ActorSystem("sttp-test")
  import actorSystem.dispatcher

  private implicit val materializer = ActorMaterializer()
  private val endpoint = "http://localhost:51823"

  override protected def beforeAll(): Unit = {
    Http().bindAndHandle(serverRoutes, "localhost", 51823)
  }

  override protected def afterAll(): Unit = {
    actorSystem.terminate().futureValue
  }

  trait ForceWrappedValue[R[_]] {
    def force[T](wrapped: R[T]): T
  }

  runTests("HttpURLConnection", HttpConnectionSttpHandler, new ForceWrappedValue[Id] {
    override def force[T](wrapped: Id[T]): T = wrapped
  })
  runTests("Akka HTTP", new AkkaHttpSttpHandler(actorSystem), new ForceWrappedValue[Future] {
    override def force[T](wrapped: Future[T]): T = wrapped.futureValue
  })

  def runTests[R[_]](name: String, handler: SttpHandler[R, Nothing], forceResponse: ForceWrappedValue[R]): Unit = {
    implicit val h = handler

    val postEcho = sttp.post(new URI(endpoint + "/echo"))
    val testBody = "this is the body"
    val testBodyBytes = testBody.getBytes("UTF-8")
    val expectedPostEchoResponse = "POST /echo this is the body"

    parseResponseTests()
    parameterTests()
    bodyTests()

    def parseResponseTests(): Unit = {
      name should "parse response as string" in {
        val response = postEcho.body(testBody).send(responseAsString)
        val fc = forceResponse.force(response).body
        fc should be (expectedPostEchoResponse)
      }

      name should "parse response as a byte array" in {
        val response = postEcho.body(testBody).send(responseAsByteArray)
        val fc = new String(forceResponse.force(response).body, "UTF-8")
        fc should be (expectedPostEchoResponse)
      }
    }

    def parameterTests(): Unit = {
      name should "make a get request with parameters" in {
        val response = sttp
          .get(new URI(endpoint + "/echo?p2=v2&p1=v1"))
          .send(responseAsString)

        val fc = forceResponse.force(response).body
        fc should be ("GET /echo p1=v1 p2=v2")
      }
    }

    def bodyTests(): Unit = {
      name should "post a string" in {
        val response = postEcho.body(testBody).send(responseAsString)
        val fc = forceResponse.force(response).body
        fc should be (expectedPostEchoResponse)
      }

      name should "post a byte array" in {
        val response = postEcho.body(testBodyBytes).send(responseAsString)
        val fc = forceResponse.force(response).body
        fc should be (expectedPostEchoResponse)
      }

      name should "post an input stream" in {
        val response = postEcho.body(new ByteArrayInputStream(testBodyBytes)).send(responseAsString)
        val fc = forceResponse.force(response).body
        fc should be (expectedPostEchoResponse)
      }

      name should "post a byte buffer" in {
        val response = postEcho.body(ByteBuffer.wrap(testBodyBytes)).send(responseAsString)
        val fc = forceResponse.force(response).body
        fc should be (expectedPostEchoResponse)
      }

      name should "post a file" in {
        val f = File.newTemporaryFile().write(testBody)
        try {
          val response = postEcho.body(f.toJava).send(responseAsString)
          val fc = forceResponse.force(response).body
          fc should be(expectedPostEchoResponse)
        } finally f.delete()
      }

      name should "post a path" in {
        val f = File.newTemporaryFile().write(testBody)
        try {
          val response = postEcho.body(f.toJava.toPath).send(responseAsString)
          val fc = forceResponse.force(response).body
          fc should be(expectedPostEchoResponse)
        } finally f.delete()
      }
    }
  }
}