-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #44 from innFactory/feature/smithy4s-0-16-4
updating smithy4s, implementing a GenericAPIClient and a ComplianceTest Client
- Loading branch information
Showing
15 changed files
with
307 additions
and
86 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
addSbtPlugin("com.codecommit" % "sbt-github-packages" % "0.5.3") | ||
addSbtPlugin("org.wartremover" % "sbt-wartremover" % "3.0.5") | ||
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.6") | ||
addSbtPlugin("com.disneystreaming.smithy4s" % "smithy4s-sbt-codegen" % "0.15.2") | ||
addSbtPlugin("com.disneystreaming.smithy4s" % "smithy4s-sbt-codegen" % "0.16.4") | ||
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.8.15") | ||
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.9.3") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
42 changes: 42 additions & 0 deletions
42
smithy4play/src/main/scala/de/innfactory/smithy4play/client/GenericAPIClient.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package de.innfactory.smithy4play.client | ||
|
||
import de.innfactory.smithy4play.{ ClientRequest, ClientResponse } | ||
import smithy4s.{ Service, Transformation } | ||
|
||
import scala.concurrent.ExecutionContext | ||
|
||
private class GenericAPIClient[Alg[_[_, _, _, _, _]], Op[_, _, _, _, _]]( | ||
service: Service[Alg, Op], | ||
client: RequestClient | ||
)(implicit ec: ExecutionContext) { | ||
|
||
private val smithyPlayClient = new SmithyPlayClient("/", service, client) | ||
|
||
/* Takes a service and creates a Transformation[Op, ClientRequest] */ | ||
private def transformer(additionalHeaders: Option[Map[String, Seq[String]]]): Alg[ClientRequest] = | ||
service.transform(this.opToResponse(additionalHeaders)) | ||
|
||
/* uses the SmithyPlayClient to transform a Operation to a ClientResponse */ | ||
private def opToResponse(additionalHeaders: Option[Map[String, Seq[String]]]): Transformation[Op, ClientRequest] = | ||
new Transformation[Op, ClientRequest] { | ||
def apply[I, E, O, SI, SO](op: Op[I, E, O, SI, SO]): ClientResponse[O] = | ||
smithyPlayClient.send(op, additionalHeaders) | ||
} | ||
} | ||
|
||
object GenericAPIClient { | ||
|
||
implicit class EnhancedGenericAPIClient[Alg[_[_, _, _, _, _]], Op[_, _, _, _, _]](service: Service[Alg, Op]) { | ||
def withClient( | ||
client: RequestClient, | ||
additionalHeaders: Option[Map[String, Seq[String]]] = None | ||
)(implicit ec: ExecutionContext) = apply(service, additionalHeaders, client) | ||
} | ||
def apply[Alg[_[_, _, _, _, _]], Op[_, _, _, _, _]]( | ||
serviceI: Service[Alg, Op], | ||
additionalHeaders: Option[Map[String, Seq[String]]] = None, | ||
client: RequestClient | ||
)(implicit ec: ExecutionContext): Alg[ClientRequest] = | ||
new GenericAPIClient(serviceI, client).transformer(additionalHeaders) | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
105 changes: 105 additions & 0 deletions
105
smithy4play/src/main/scala/de/innfactory/smithy4play/compliancetests/ComplianceClient.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
package de.innfactory.smithy4play.compliancetests | ||
|
||
import de.innfactory.smithy4play.ClientResponse | ||
import de.innfactory.smithy4play.client.{ SmithyPlayClientEndpointErrorResponse, SmithyPlayClientEndpointResponse } | ||
import play.api.libs.json.Json | ||
import smithy.test._ | ||
import smithy4s.http.HttpEndpoint | ||
import smithy4s.{ Document, Endpoint, GenLift, Monadic, Service } | ||
|
||
import scala.concurrent.duration.DurationInt | ||
import scala.concurrent.{ Await, ExecutionContext } | ||
|
||
class ComplianceClient[ | ||
Alg[_[_, _, _, _, _]], | ||
Op[_, _, _, _, _] | ||
]( | ||
client: Monadic[Alg, ClientResponse] | ||
)(implicit | ||
service: Service[Alg, Op], | ||
ec: ExecutionContext | ||
) { | ||
|
||
private def clientRequest[I, E, O, SE, SO]( | ||
endpoint: Endpoint[Op, I, E, O, SE, SO], | ||
requestTestCase: Option[HttpRequestTestCase], | ||
responseTestCase: Option[HttpResponseTestCase] | ||
) = { | ||
|
||
val inputFromDocument = Document.Decoder.fromSchema(endpoint.input) | ||
val input = inputFromDocument.decode(requestTestCase.flatMap(_.params).getOrElse(Document.obj())).toOption.get | ||
|
||
val result = service | ||
.asTransformation[GenLift[ClientResponse]#λ](client) | ||
.apply(endpoint.wrap(input)) | ||
.map(res => matchResponse(res, endpoint, responseTestCase)) | ||
Await.result(result, 5.seconds) | ||
} | ||
|
||
private def matchResponse[I, E, O, SE, SO]( | ||
response: Either[SmithyPlayClientEndpointErrorResponse, SmithyPlayClientEndpointResponse[O]], | ||
endpoint: Endpoint[Op, I, E, O, SE, SO], | ||
responseTestCase: Option[HttpResponseTestCase] | ||
) = { | ||
|
||
val httpEp = HttpEndpoint.cast(endpoint).get | ||
val responseStatusCode = response match { | ||
case Left(value) => value.statusCode | ||
case Right(value) => value.statusCode | ||
} | ||
val expectedStatusCode = responseTestCase.map(_.code).getOrElse(httpEp.code) | ||
// val statusAssert = expectedStatusCode == responseStatusCode | ||
|
||
val outputFromDocument = Document.Decoder.fromSchema(endpoint.output) | ||
val expectedOutput = | ||
outputFromDocument.decode(responseTestCase.flatMap(_.params).getOrElse(Document.obj())).toOption | ||
|
||
// responseTestCase.forall(_ => expectedOutput == response.toOption.flatMap(_.body)) && statusAssert | ||
ComplianceResponse( | ||
expectedCode = expectedStatusCode, | ||
receivedCode = responseStatusCode, | ||
expectedBody = expectedOutput, | ||
receivedBody = response.toOption.flatMap(_.body), | ||
expectedError = responseTestCase match { | ||
case Some(value) => value.body.getOrElse("") | ||
case None => "" | ||
}, | ||
receivedError = response match { | ||
case Left(value) => Json.parse(value.error).toString() | ||
case Right(value) => "" | ||
} | ||
) | ||
} | ||
|
||
case class ComplianceResponse[O]( | ||
expectedCode: Int, | ||
receivedCode: Int, | ||
expectedBody: Option[O], | ||
receivedBody: Option[O], | ||
expectedError: String, | ||
receivedError: String | ||
) | ||
|
||
def tests(suite: Option[String] = None) = | ||
service.endpoints.flatMap { endpoint => | ||
val requests = endpoint.hints | ||
.get(HttpRequestTests) | ||
.map(_.value) | ||
.getOrElse(Nil) | ||
.filter(tc => | ||
suite.isEmpty && tc.documentation.isEmpty || tc.documentation.getOrElse("") == suite.getOrElse("") | ||
) | ||
val responses = endpoint.hints | ||
.get(HttpResponseTests) | ||
.map(_.value) | ||
.getOrElse(Nil) | ||
.filter(tc => | ||
suite.isEmpty && tc.documentation.isEmpty || tc.documentation.getOrElse("") == suite.getOrElse("") | ||
) | ||
val ids = requests.map(_.id).toSet ++ responses.map(_.id).toSet | ||
|
||
ids | ||
.map(id => (requests.find(_.id == id), responses.find(_.id == id))) | ||
.map(x => clientRequest(endpoint, x._1, x._2)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.