Skip to content

Commit

Permalink
Add correct handling of query parameters in SttpMockServerClient (#4220)
Browse files Browse the repository at this point in the history
  • Loading branch information
Husky22 authored Dec 24, 2024
1 parent dbfb1b1 commit 034c878
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import io.circe.{JsonObject, Printer}
import io.circe.syntax._
import sttp.client3._
import sttp.client3.testing._
import sttp.model.Uri.UriContext
import sttp.model.Uri.{QuerySegment, UriContext}
import sttp.model.{ContentTypeRange, HasHeaders, Header, HeaderNames, Headers, MediaType, StatusCode, Uri}
import sttp.tapir.internal.ParamsAsAny
import sttp.tapir.{CodecFormat, DecodeResult, Endpoint, RawBodyType, WebSocketBodyOutput}
Expand Down Expand Up @@ -134,7 +134,8 @@ object SttpMockServerClient {
val request = SttpClientInterpreter().toSecureRequest(endpoint, None).apply(securityInput).apply(input)
ExpectationRequestDefinition(
method = request.method,
path = request.uri,
path = request.uri.copy(querySegments = Seq()),
queryStringParameters = querySegmentsToMultiMapOpt(request.uri.querySegments),
body = toExpectationBody(request),
headers = headersToMultiMapOpt(request.headers)
)
Expand Down Expand Up @@ -206,6 +207,16 @@ object SttpMockServerClient {
if (headers.isEmpty) None
else Some(headers.groupBy(_.name).map { case (name, values) => name -> values.map(_.value).toList })

private def querySegmentsToMultiMapOpt(querySegments: Seq[QuerySegment]): Option[Map[String, List[String]]] =
if (querySegments.isEmpty) None
else
Some(
querySegments
.collect { case kv: QuerySegment.KeyValue => kv }
.groupBy(x => x.k)
.map { case (key, values) => key -> values.map(_.v).toList }
)

private val printer = Printer.noSpaces

private def handleSimpleResponse(response: Response[Either[String, String]]): Either[Throwable, Unit] = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ case class Expectation(
case class ExpectationRequestDefinition(
method: Method,
path: Uri,
queryStringParameters: Option[Map[String, List[String]]],
body: Option[ExpectationBodyDefinition],
headers: Option[Map[String, List[String]]]
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ class SttpMockServerClientSpec extends AnyFlatSpec with Matchers with BeforeAndA
.errorOut(circe.jsonBody[ApiError])
.out(circe.jsonBody[PersonView])

private val queryParameterEndpoint = endpoint
.in("api" / "v1" / "person")
.in(query[String]("name").and(query[Int]("age")).mapTo[CreatePersonCommand])
.put
.errorOut(circe.jsonBody[ApiError])
.out(circe.jsonBody[PersonView])

it should "create plain text expectation correctly" in {
val sampleIn = "Hello, world!"
val sampleOut = "Hello to you!"
Expand All @@ -67,6 +74,27 @@ class SttpMockServerClientSpec extends AnyFlatSpec with Matchers with BeforeAndA
actual shouldEqual Success(Value(Right(sampleOut)))
}

it should "create query parameters in expectation correctly" in {
val sampleIn = CreatePersonCommand("John", 23)
val sampleOut = PersonView(uuid(), "John", 23)

val actual = for {
_ <- mockServerClient
.whenInputMatches(queryParameterEndpoint)((), sampleIn)
.thenSuccess(sampleOut)

resp <- SttpClientInterpreter()
.toRequest(queryParameterEndpoint, baseUri = Some(baseUri))
.apply(sampleIn)
.send(backend)

_ <- mockServerClient
.verifyRequest(queryParameterEndpoint, VerificationTimes.exactlyOnce)((), sampleIn)
} yield resp.body

actual shouldEqual Success(Value(Right(sampleOut)))
}

it should "create plain text error expectation correctly" in {
val sampleIn = "Hello, world!"
val sampleOut = "BOOOM!"
Expand Down

0 comments on commit 034c878

Please sign in to comment.