Skip to content

Commit

Permalink
Improve script errors when the endpoint is not the JSON API (#9550)
Browse files Browse the repository at this point in the history
fixes #9532

changelog_begin
changelog_end
  • Loading branch information
cocreature committed May 3, 2021
1 parent 8678791 commit ca012c3
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package com.daml.lf.engine.script.ledgerinteraction

import java.time.Instant

import akka.util.ByteString
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
Expand Down Expand Up @@ -72,15 +73,6 @@ class JsonLedgerClient(
private def damlLfTypeLookup(id: Identifier) =
envIface.typeDecls.get(id).map(_.`type`)

case class FailedJsonApiRequest(
path: Path,
reqBody: Option[JsValue],
respStatus: StatusCode,
errors: List[String],
) extends RuntimeException(
s"Request to $path with ${reqBody.map(_.compactPrint)} failed with status $respStatus: $errors"
)

def request[A, B](path: Path, a: A)(implicit
wa: JsonWriter[A],
rb: JsonReader[B],
Expand All @@ -94,7 +86,16 @@ class JsonLedgerClient(
),
headers = List(Authorization(OAuth2BearerToken(token.value))),
)
Http().singleRequest(req).flatMap(resp => Unmarshal(resp.entity).to[Response[B]])
Http()
.singleRequest(req)
.flatMap(resp =>
Unmarshal(resp.entity).to[Response[B]].recoverWith { case _ =>
resp.entity.dataBytes
.runFold(ByteString.empty)((b, a) => b ++ a)
.map(_.utf8String)
.map(body => ErrorResponse(status = resp.status, errors = List(body)))
}
)
}

def request[A](path: Path)(implicit ra: JsonReader[A]): Future[Response[A]] = {
Expand Down Expand Up @@ -457,6 +458,15 @@ class JsonLedgerClient(

object JsonLedgerClient {

case class FailedJsonApiRequest(
path: Path,
reqBody: Option[JsValue],
respStatus: StatusCode,
errors: List[String],
) extends RuntimeException(
s"Request to $path with ${reqBody.map(_.compactPrint)} failed with status $respStatus: $errors"
)

def validateSubmitParties(
actAs: OneAnd[Set, Ref.Party],
readAs: Set[Ref.Party],
Expand Down
1 change: 1 addition & 0 deletions daml-script/test/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ da_scala_test_suite(
resources = glob(["src/main/resources/**/*"]),
scala_deps = [
"@maven//:com_typesafe_akka_akka_http_core",
"@maven//:com_typesafe_akka_akka_http",
"@maven//:com_typesafe_akka_akka_stream",
"@maven//:io_spray_spray_json",
"@maven//:org_scalaz_scalaz_core",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import java.io.File
import java.nio.file.Files

import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.Http.ServerBinding
import akka.http.scaladsl.model.StatusCodes
import akka.http.scaladsl.server.Directives._
import akka.stream.Materializer
import com.daml.bazeltools.BazelRunfiles._
import com.daml.grpc.adapter.{AkkaExecutionSequencerPool, ExecutionSequencerFactory}
Expand All @@ -28,7 +31,11 @@ import com.daml.ledger.resources.{Resource, ResourceContext, ResourceOwner}
import com.daml.lf.archive.{Dar, DarReader, Decode}
import com.daml.lf.data.Ref._
import com.daml.lf.engine.script._
import com.daml.lf.engine.script.ledgerinteraction.{ScriptLedgerClient, ScriptTimeMode}
import com.daml.lf.engine.script.ledgerinteraction.{
JsonLedgerClient,
ScriptLedgerClient,
ScriptTimeMode,
}
import com.daml.lf.iface.EnvironmentInterface
import com.daml.lf.iface.reader.InterfaceReader
import com.daml.lf.language.Ast.Package
Expand Down Expand Up @@ -484,5 +491,44 @@ final class JsonApiIt
assert(r == SUnit)
}
}
"invalid response" in {
def withServer[A](f: ServerBinding => Future[A]) = {
val bindingF: Future[ServerBinding] = Http().newServerAt("localhost", 0).bind(reject)
val fa: Future[A] = bindingF.flatMap(f)
fa.transformWith { ta =>
Future
.sequence(
Seq(
bindingF.flatMap(_.unbind())
)
)
.transform(_ => ta)
}
}
withServer { binding =>
val participant = ApiParameters(
"http://localhost",
binding.localAddress.getPort,
Some(getToken(List(party), List(), true)),
None,
)
val participants = Participants(
Some(participant),
Map.empty,
Map.empty,
)
for {
clients <- Runner.jsonClients(participants, envIface)
exc <- recoverToExceptionIf[ScriptF.FailedCmd](
run(clients, QualifiedName.assertFromString("ScriptTest:jsonBasic"))
)
} yield {
exc.cause shouldBe a[JsonLedgerClient.FailedJsonApiRequest]
val cause = exc.cause.asInstanceOf[JsonLedgerClient.FailedJsonApiRequest]
cause.respStatus shouldBe StatusCodes.NotFound
cause.errors shouldBe List("The requested resource could not be found.")
}
}
}
}
}

0 comments on commit ca012c3

Please sign in to comment.