mirror of
https://github.com/digital-asset/daml.git
synced 2024-09-20 01:07:18 +03:00
[JSON-API] Migrating tests to use sandbox next (#11034)
* Changes to use sandbox next for our integration tests CHANGELOG_BEGIN CHANGELOG_END * remove sandbox classic dependency for HttpServiceTestFixture and perf tests * rely on sandbox next fixture test class * add missing dependencies for http-json-oracle * changes based on code review comments * Add tag to skip test case for scala_2_12 and also add a jdbc backend for sandbox spun up for perf tests * Reduce size of contracts for archiving test
This commit is contained in:
parent
ffc8d6894f
commit
d3e6f16c61
@ -51,6 +51,7 @@ da_scala_test(
|
||||
"//daml-lf/transaction",
|
||||
"//language-support/scala/bindings-akka",
|
||||
"//ledger-api/rs-grpc-bridge",
|
||||
"//ledger-api/testing-utils",
|
||||
"//ledger-service/db-backend",
|
||||
"//ledger-service/http-json:http-json-ee",
|
||||
"//ledger-service/http-json:integration-tests-lib-ee",
|
||||
@ -58,6 +59,9 @@ da_scala_test(
|
||||
"//ledger-service/http-json-testing:ee",
|
||||
"//ledger-service/jwt",
|
||||
"//ledger-service/utils",
|
||||
"//ledger/sandbox:sandbox-scala-tests-lib",
|
||||
"//ledger/sandbox-common",
|
||||
"//ledger/sandbox-common:sandbox-common-scala-tests-lib",
|
||||
"//libs-scala/db-utils",
|
||||
"//libs-scala/oracle-testing",
|
||||
"//libs-scala/ports",
|
||||
|
@ -43,6 +43,7 @@ hj_scalacopts = lf_scalacopts + [
|
||||
"//bazel_tools/runfiles:scala_runfiles",
|
||||
"//language-support/scala/bindings-akka",
|
||||
"//ledger-api/rs-grpc-bridge",
|
||||
"//ledger-api/testing-utils",
|
||||
"@maven//:org_scalatest_scalatest_compatible",
|
||||
"//ledger-service/http-json:http-json-{}".format(edition),
|
||||
"//ledger-service/http-json-cli:{}".format(edition),
|
||||
@ -53,13 +54,17 @@ hj_scalacopts = lf_scalacopts + [
|
||||
"//ledger/ledger-api-auth",
|
||||
"//ledger/ledger-api-common",
|
||||
"//ledger/ledger-configuration",
|
||||
"//ledger/ledger-resources",
|
||||
"//ledger/metrics",
|
||||
"//ledger/participant-integration-api",
|
||||
"//ledger/sandbox-classic",
|
||||
"//ledger/sandbox",
|
||||
"//ledger/sandbox:sandbox-scala-tests-lib",
|
||||
"//ledger/sandbox-common",
|
||||
"//ledger/sandbox-common:sandbox-common-scala-tests-lib",
|
||||
"//libs-scala/contextualized-logging",
|
||||
"//libs-scala/db-utils",
|
||||
"//libs-scala/ports",
|
||||
"//libs-scala/resources",
|
||||
"@maven//:io_dropwizard_metrics_metrics_core",
|
||||
],
|
||||
)
|
||||
|
@ -37,13 +37,14 @@ import com.daml.ledger.client.configuration.{
|
||||
LedgerIdRequirement,
|
||||
}
|
||||
import com.daml.ledger.client.withoutledgerid.{LedgerClient => DamlLedgerClient}
|
||||
import com.daml.ledger.resources.ResourceContext
|
||||
import com.daml.logging.LoggingContextOf
|
||||
import com.daml.metrics.Metrics
|
||||
import com.daml.platform.apiserver.SeedService.Seeding
|
||||
import com.daml.platform.common.LedgerIdMode
|
||||
import com.daml.platform.sandbox
|
||||
import com.daml.platform.sandbox.SandboxServer
|
||||
import com.daml.platform.sandbox.SandboxBackend
|
||||
import com.daml.platform.sandbox.config.SandboxConfig
|
||||
import com.daml.platform.sandboxnext.Runner
|
||||
import com.daml.platform.services.time.TimeProviderType
|
||||
import com.daml.ports.Port
|
||||
import com.typesafe.scalalogging.LazyLogging
|
||||
@ -150,19 +151,35 @@ object HttpServiceTestFixture extends LazyLogging with Assertions with Inside {
|
||||
useTls: UseTls = UseTls.NoTls,
|
||||
authService: Option[AuthService] = None,
|
||||
)(testFn: (Port, DamlLedgerClient, LedgerId) => Future[A])(implicit
|
||||
mat: Materializer,
|
||||
aesf: ExecutionSequencerFactory,
|
||||
ec: ExecutionContext,
|
||||
): Future[A] = {
|
||||
|
||||
val ledgerId = LedgerId(testName)
|
||||
val applicationId = ApplicationId(testName)
|
||||
implicit val resourceContext: ResourceContext = ResourceContext(ec)
|
||||
|
||||
val ledgerF = for {
|
||||
ledger <- Future(
|
||||
new SandboxServer(ledgerConfig(Port.Dynamic, dars, ledgerId, authService, useTls), mat)
|
||||
urlResource <- Future(
|
||||
SandboxBackend.H2Database.owner
|
||||
.map(info => Some(info.jdbcUrl))
|
||||
.acquire()
|
||||
)
|
||||
port <- ledger.portF
|
||||
jdbcUrl <- urlResource.asFuture
|
||||
ledger <- Future(
|
||||
new Runner(
|
||||
ledgerConfig(
|
||||
Port.Dynamic,
|
||||
dars,
|
||||
ledgerId,
|
||||
useTls = useTls,
|
||||
authService = authService,
|
||||
jdbcUrl = jdbcUrl,
|
||||
)
|
||||
)
|
||||
.acquire()
|
||||
)
|
||||
port <- ledger.asFuture
|
||||
} yield (ledger, port)
|
||||
|
||||
val clientF: Future[DamlLedgerClient] = for {
|
||||
@ -179,11 +196,12 @@ object HttpServiceTestFixture extends LazyLogging with Assertions with Inside {
|
||||
a <- testFn(ledgerPort, client, ledgerId)
|
||||
} yield a
|
||||
|
||||
fa.onComplete { _ =>
|
||||
ledgerF.foreach(_._1.close())
|
||||
fa.transformWith { ta =>
|
||||
ledgerF
|
||||
.flatMap(_._1.release())
|
||||
.fallbackTo(Future.unit)
|
||||
.transform(_ => ta)
|
||||
}
|
||||
|
||||
fa
|
||||
}
|
||||
|
||||
private def ledgerConfig(
|
||||
@ -192,12 +210,15 @@ object HttpServiceTestFixture extends LazyLogging with Assertions with Inside {
|
||||
ledgerId: LedgerId,
|
||||
authService: Option[AuthService],
|
||||
useTls: UseTls,
|
||||
jdbcUrl: Option[String],
|
||||
): SandboxConfig =
|
||||
sandbox.DefaultConfig.copy(
|
||||
SandboxConfig.defaultConfig.copy(
|
||||
port = ledgerPort,
|
||||
damlPackages = dars,
|
||||
jdbcUrl = jdbcUrl,
|
||||
timeProviderType = Some(TimeProviderType.WallClock),
|
||||
tlsConfig = if (useTls) Some(serverTlsConfig) else None,
|
||||
engineMode = SandboxConfig.EngineMode.Dev,
|
||||
ledgerIdMode = LedgerIdMode.Static(ledgerId),
|
||||
authService = authService,
|
||||
seeding = Some(Seeding.Weak),
|
||||
@ -271,8 +292,8 @@ object HttpServiceTestFixture extends LazyLogging with Assertions with Inside {
|
||||
}
|
||||
}
|
||||
|
||||
private val serverTlsConfig = TlsConfiguration(enabled = true, serverCrt, serverPem, caCrt)
|
||||
private val clientTlsConfig = TlsConfiguration(enabled = true, clientCrt, clientPem, caCrt)
|
||||
final val serverTlsConfig = TlsConfiguration(enabled = true, serverCrt, serverPem, caCrt)
|
||||
final val clientTlsConfig = TlsConfiguration(enabled = true, clientCrt, clientPem, caCrt)
|
||||
private val noTlsConfig = TlsConfiguration(enabled = false, None, None, None)
|
||||
|
||||
def jwtForParties(actAs: List[String], readAs: List[String], ledgerId: String) = {
|
||||
|
@ -0,0 +1,78 @@
|
||||
// Copyright (c) 2021 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.http.util
|
||||
|
||||
import com.daml.grpc.adapter.ExecutionSequencerFactory
|
||||
import com.daml.http.HttpServiceTestFixture.{UseTls, clientTlsConfig, serverTlsConfig}
|
||||
import com.daml.ledger.api.domain.LedgerId
|
||||
import com.daml.ledger.client.configuration.{
|
||||
CommandClientConfiguration,
|
||||
LedgerClientConfiguration,
|
||||
LedgerIdRequirement,
|
||||
}
|
||||
import com.daml.ports.Port
|
||||
import com.daml.ledger.client.withoutledgerid.{LedgerClient => DamlLedgerClient}
|
||||
import com.daml.platform.apiserver.SeedService.Seeding
|
||||
import com.daml.platform.common.LedgerIdMode
|
||||
import com.daml.platform.sandbox.config.SandboxConfig
|
||||
import com.daml.platform.sandboxnext.SandboxNextFixture
|
||||
import com.daml.platform.services.time.TimeProviderType
|
||||
import org.scalatest.Suite
|
||||
|
||||
import scala.concurrent.{ExecutionContext, Future}
|
||||
|
||||
trait SandboxTestLedger extends SandboxNextFixture {
|
||||
self: Suite =>
|
||||
|
||||
protected def testId: String
|
||||
|
||||
def useTls: UseTls
|
||||
|
||||
def ledgerId = LedgerId(testId)
|
||||
|
||||
override protected def config: SandboxConfig = SandboxConfig.defaultConfig.copy(
|
||||
port = Port.Dynamic,
|
||||
damlPackages = packageFiles,
|
||||
timeProviderType = Some(TimeProviderType.WallClock),
|
||||
tlsConfig = if (useTls) Some(serverTlsConfig) else None,
|
||||
ledgerIdMode = LedgerIdMode.Static(ledgerId),
|
||||
authService = authService,
|
||||
scenario = scenario,
|
||||
engineMode = SandboxConfig.EngineMode.Dev,
|
||||
seeding = Some(Seeding.Weak),
|
||||
)
|
||||
|
||||
def clientCfg(token: Option[String], testName: String): LedgerClientConfiguration =
|
||||
LedgerClientConfiguration(
|
||||
applicationId = testName,
|
||||
ledgerIdRequirement = LedgerIdRequirement.none,
|
||||
commandClient = CommandClientConfiguration.default,
|
||||
sslContext = if (useTls) clientTlsConfig.client() else None,
|
||||
token = token,
|
||||
)
|
||||
|
||||
def usingLedger[A](testName: String, token: Option[String] = None)(
|
||||
testFn: (Port, DamlLedgerClient, LedgerId) => Future[A]
|
||||
)(implicit
|
||||
esf: ExecutionSequencerFactory,
|
||||
ec: ExecutionContext,
|
||||
): Future[A] = {
|
||||
|
||||
val clientF: Future[DamlLedgerClient] = for {
|
||||
ledgerPort <- Future(serverPort)
|
||||
} yield DamlLedgerClient.singleHost(
|
||||
"localhost",
|
||||
ledgerPort.value,
|
||||
clientCfg(token, testName),
|
||||
)(ec, esf)
|
||||
|
||||
val fa: Future[A] = for {
|
||||
ledgerPort <- Future(serverPort)
|
||||
client <- clientF
|
||||
a <- testFn(ledgerPort, client, ledgerId)
|
||||
} yield a
|
||||
|
||||
fa
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@ load(
|
||||
)
|
||||
load("//rules_daml:daml.bzl", "daml_compile")
|
||||
load("@os_info//:os_info.bzl", "is_windows")
|
||||
load("@scala_version//:index.bzl", "scala_version_suffix")
|
||||
load("@scala_version//:index.bzl", "scala_major_version", "scala_version_suffix")
|
||||
|
||||
hj_scalacopts = lf_scalacopts + [
|
||||
"-P:wartremover:traverser:org.wartremover.warts.NonUnitStatements",
|
||||
@ -283,7 +283,12 @@ alias(
|
||||
"//daml-lf/transaction-test-lib",
|
||||
"//language-support/scala/bindings-akka",
|
||||
"//ledger-api/rs-grpc-bridge",
|
||||
"//ledger-api/testing-utils",
|
||||
"//ledger/ledger-resources",
|
||||
"//ledger/metrics",
|
||||
"//ledger/sandbox:sandbox-scala-tests-lib",
|
||||
"//ledger/sandbox-common",
|
||||
"//ledger/sandbox-common:sandbox-common-scala-tests-lib",
|
||||
"//ledger-service/http-json-cli:{}".format(edition),
|
||||
"//ledger-service/http-json-testing:{}".format(edition),
|
||||
"//ledger-service/db-backend",
|
||||
@ -326,6 +331,10 @@ alias(
|
||||
"src/it/scala/**/*.scala",
|
||||
"src/it/edition/{}/**/*.scala".format(edition),
|
||||
]),
|
||||
args = [
|
||||
"-l",
|
||||
"skip_scala_2_12",
|
||||
] if scala_major_version == "2.12" else [],
|
||||
data = [
|
||||
":Account.dar",
|
||||
"//docs:quickstart-model.dar",
|
||||
@ -369,17 +378,23 @@ alias(
|
||||
"//daml-lf/transaction-test-lib",
|
||||
"//language-support/scala/bindings-akka",
|
||||
"//ledger-api/rs-grpc-bridge",
|
||||
"//ledger-api/testing-utils",
|
||||
"//ledger-service/db-backend",
|
||||
"//ledger/ledger-api-auth",
|
||||
"//ledger/ledger-resources",
|
||||
"//ledger/metrics",
|
||||
"//ledger/sandbox:sandbox-scala-tests-lib",
|
||||
"//ledger/sandbox-common",
|
||||
"//ledger/sandbox-common:sandbox-common-scala-tests-lib",
|
||||
"//ledger-service/http-json-cli:{}".format(edition),
|
||||
"//ledger-service/http-json-testing:{}".format(edition),
|
||||
"//ledger-service/jwt",
|
||||
"//ledger-service/utils",
|
||||
"//ledger/ledger-api-auth",
|
||||
"//libs-scala/contextualized-logging",
|
||||
"//libs-scala/db-utils",
|
||||
"//libs-scala/ports",
|
||||
"//libs-scala/postgresql-testing",
|
||||
"//libs-scala/resources",
|
||||
"//libs-scala/scala-utils",
|
||||
"//runtime-components/non-repudiation",
|
||||
"//runtime-components/non-repudiation-postgresql",
|
||||
|
@ -8,11 +8,14 @@ import akka.actor.ActorSystem
|
||||
import akka.stream.Materializer
|
||||
import com.daml.bazeltools.BazelRunfiles.rlocation
|
||||
import com.daml.grpc.adapter.{AkkaExecutionSequencerPool, ExecutionSequencerFactory}
|
||||
import com.daml.http.HttpServiceTestFixture.UseTls
|
||||
import com.daml.http.util.TestUtil.requiredFile
|
||||
import com.daml.http.util.Logging.instanceUUIDLogCtx
|
||||
import com.daml.http.util.SandboxTestLedger
|
||||
import com.daml.jwt.domain.Jwt
|
||||
import com.daml.ledger.api.auth.{AuthServiceStatic, Claim, ClaimPublic, ClaimSet}
|
||||
import com.daml.ledger.api.domain.LedgerId
|
||||
import com.daml.ledger.api.testing.utils.SuiteResourceManagementAroundAll
|
||||
import com.daml.ledger.client.withoutledgerid.{LedgerClient => DamlLedgerClient}
|
||||
import org.scalatest.BeforeAndAfterAll
|
||||
import org.scalatest.flatspec.AsyncFlatSpec
|
||||
@ -22,12 +25,18 @@ import org.slf4j.LoggerFactory
|
||||
import scala.concurrent.{ExecutionContext, Future}
|
||||
import scala.util.control.NonFatal
|
||||
|
||||
final class AuthorizationTest extends AsyncFlatSpec with BeforeAndAfterAll with Matchers {
|
||||
final class AuthorizationTest
|
||||
extends AsyncFlatSpec
|
||||
with BeforeAndAfterAll
|
||||
with Matchers
|
||||
with SandboxTestLedger
|
||||
with SuiteResourceManagementAroundAll {
|
||||
|
||||
private val dar = requiredFile(rlocation("docs/quickstart-model.dar"))
|
||||
.fold(e => throw new IllegalStateException(e), identity)
|
||||
|
||||
private val testId: String = this.getClass.getSimpleName
|
||||
protected val testId: String = this.getClass.getSimpleName
|
||||
override def useTls = UseTls.NoTls
|
||||
|
||||
implicit val asys: ActorSystem = ActorSystem(testId)
|
||||
implicit val mat: Materializer = Materializer(asys)
|
||||
@ -43,6 +52,9 @@ final class AuthorizationTest extends AsyncFlatSpec with BeforeAndAfterAll with
|
||||
|
||||
private val accessTokenFile = Files.createTempFile("Extractor", "AuthSpec")
|
||||
|
||||
override def authService = mockedAuthService
|
||||
override def packageFiles = List(dar)
|
||||
|
||||
override protected def afterAll(): Unit = {
|
||||
super.afterAll()
|
||||
try {
|
||||
@ -55,11 +67,11 @@ final class AuthorizationTest extends AsyncFlatSpec with BeforeAndAfterAll with
|
||||
}
|
||||
}
|
||||
|
||||
protected def withLedger[A](testFn: DamlLedgerClient => LedgerId => Future[A]): Future[A] =
|
||||
HttpServiceTestFixture
|
||||
.withLedger[A](List(dar), testId, Option(publicToken), authService = mockedAuthService) {
|
||||
case (_, client, ledgerId) => testFn(client)(ledgerId)
|
||||
}
|
||||
protected def withLedger[A](testFn: DamlLedgerClient => LedgerId => Future[A]): Future[A] = {
|
||||
usingLedger[A](testId, Some(publicToken)) { case (_, client, ledgerId) =>
|
||||
testFn(client)(ledgerId)
|
||||
}
|
||||
}
|
||||
|
||||
private def packageService(client: DamlLedgerClient): PackageService =
|
||||
new PackageService(HttpService.doLoad(client.packageClient))
|
||||
|
@ -20,11 +20,14 @@ class HttpServiceWithPostgresIntTest
|
||||
override def wsConfig: Option[WebsocketConfig] = None
|
||||
|
||||
"query persists all active contracts" in withHttpService { (uri, encoder, _, _) =>
|
||||
val (party, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
val searchDataSet = genSearchDataSet(party)
|
||||
searchExpectOk(
|
||||
searchDataSet,
|
||||
jsObject("""{"templateIds": ["Iou:Iou"], "query": {"currency": "EUR"}}"""),
|
||||
uri,
|
||||
encoder,
|
||||
headers,
|
||||
).flatMap { searchResult: List[domain.ActiveContract[JsValue]] =>
|
||||
discard { searchResult should have size 2 }
|
||||
discard { searchResult.map(getField("currency")) shouldBe List.fill(2)(JsString("EUR")) }
|
||||
|
@ -3,13 +3,14 @@
|
||||
|
||||
package com.daml.http
|
||||
|
||||
import com.daml.http.HttpServiceTestFixture.UseTls
|
||||
import com.daml.http.HttpServiceTestFixture.{UseTls, jwtForParties}
|
||||
import com.daml.http.dbbackend.JdbcConfig
|
||||
import com.typesafe.scalalogging.StrictLogging
|
||||
import org.scalatest._
|
||||
import org.scalatest.freespec.AsyncFreeSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import scalaz.\/-
|
||||
import scalaz.syntax.tag._
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
||||
@ -49,9 +50,10 @@ class WebsocketServiceOffsetTickIntTest
|
||||
|
||||
"Given non-empty ACS, JSON API should emit ACS block and after it only absolute offset ticks" in withHttpService {
|
||||
(uri, _, _, _) =>
|
||||
val (party, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
for {
|
||||
_ <- initialIouCreate(uri)
|
||||
|
||||
_ <- initialIouCreate(uri, party, headers)
|
||||
jwt = jwtForParties(List(party.unwrap), List(), testId)
|
||||
msgs <- singleClientQueryStream(jwt, uri, """{"templateIds": ["Iou:Iou"]}""")
|
||||
.take(10)
|
||||
.runWith(collectResultsAsTextMessage)
|
||||
|
@ -22,17 +22,18 @@ import com.daml.http.json.SprayJson.{decode, decode1, objectField}
|
||||
import com.daml.http.json._
|
||||
import com.daml.http.util.ClientUtil.{boxedRecord, uniqueId}
|
||||
import com.daml.http.util.FutureUtil.toFuture
|
||||
import com.daml.http.util.{FutureUtil, TestUtil}
|
||||
import com.daml.http.util.{FutureUtil, SandboxTestLedger}
|
||||
import com.daml.jwt.JwtSigner
|
||||
import com.daml.jwt.domain.{DecodedJwt, Jwt}
|
||||
import com.daml.ledger.api.refinements.{ApiTypes => lar}
|
||||
import com.daml.ledger.api.v1.{value => v}
|
||||
import com.daml.ledger.client.withoutledgerid.{LedgerClient => DamlLedgerClient}
|
||||
import com.daml.ledger.service.MetadataReader
|
||||
import com.daml.ledger.test.ModelTestDar
|
||||
import com.daml.ledger.test.{ModelTestDar, SemanticTestDar}
|
||||
import com.daml.platform.participant.util.LfEngineToApi.lfValueToApiValue
|
||||
import com.daml.http.util.Logging.instanceUUIDLogCtx
|
||||
import com.daml.ledger.api.domain.LedgerId
|
||||
import com.daml.ledger.api.testing.utils.SuiteResourceManagementAroundAll
|
||||
import com.typesafe.scalalogging.StrictLogging
|
||||
import org.scalatest._
|
||||
import org.scalatest.freespec.AsyncFreeSpec
|
||||
@ -51,13 +52,16 @@ import scala.concurrent.{ExecutionContext, Future}
|
||||
import scala.util.{Success, Try}
|
||||
import com.daml.ledger.api.{domain => LedgerApiDomain}
|
||||
import com.daml.ports.Port
|
||||
import org.scalatest.Tag
|
||||
|
||||
object SkipScala212 extends Tag("skip_scala_2_12")
|
||||
|
||||
object AbstractHttpServiceIntegrationTestFuns {
|
||||
private[http] val dar1 = requiredResource("docs/quickstart-model.dar")
|
||||
private[http] val dar1 = requiredResource(ModelTestDar.path)
|
||||
|
||||
private[http] val dar2 = requiredResource("ledger-service/http-json/Account.dar")
|
||||
|
||||
private[http] val dar3 = requiredResource(ModelTestDar.path)
|
||||
private[http] val dar3 = requiredResource(SemanticTestDar.path)
|
||||
|
||||
def sha256(source: Source[ByteString, Any])(implicit mat: Materializer): Try[String] = Try {
|
||||
import java.security.MessageDigest
|
||||
@ -77,7 +81,10 @@ object AbstractHttpServiceIntegrationTestFuns {
|
||||
}
|
||||
|
||||
@SuppressWarnings(Array("org.wartremover.warts.NonUnitStatements"))
|
||||
trait AbstractHttpServiceIntegrationTestFuns extends StrictLogging {
|
||||
trait AbstractHttpServiceIntegrationTestFuns
|
||||
extends StrictLogging
|
||||
with SandboxTestLedger
|
||||
with SuiteResourceManagementAroundAll {
|
||||
this: AsyncTestSuite with Matchers with Inside =>
|
||||
import AbstractHttpServiceIntegrationTestFuns._
|
||||
import json.JsonProtocol._
|
||||
@ -116,36 +123,40 @@ trait AbstractHttpServiceIntegrationTestFuns extends StrictLogging {
|
||||
import tag.@@ // used for subtyping to make `AHS ec` beat executionContext
|
||||
implicit val `AHS ec`: ExecutionContext @@ this.type = tag[this.type](`AHS asys`.dispatcher)
|
||||
|
||||
override def packageFiles = List(dar1, dar2)
|
||||
|
||||
protected def getUniqueParty(name: String) = getUniquePartyAndAuthHeaders(name)._1
|
||||
protected def getUniquePartyAndAuthHeaders(name: String): (domain.Party, List[HttpHeader]) = {
|
||||
val partyName = s"${name}_${uniqueId()}"
|
||||
(domain.Party(partyName), headersWithPartyAuth(List(partyName)))
|
||||
}
|
||||
|
||||
protected def withHttpServiceAndClient[A](
|
||||
testFn: (Uri, DomainJsonEncoder, DomainJsonDecoder, DamlLedgerClient, LedgerId) => Future[A]
|
||||
): Future[A] =
|
||||
HttpServiceTestFixture.withLedger[A](List(dar1, dar2), testId, None, useTls) {
|
||||
case (ledgerPort, _, ledgerId) =>
|
||||
HttpServiceTestFixture.withHttpService[A](
|
||||
testId,
|
||||
ledgerPort,
|
||||
jdbcConfig,
|
||||
staticContentConfig,
|
||||
useTls = useTls,
|
||||
wsConfig = wsConfig,
|
||||
)(testFn(_, _, _, _, ledgerId))
|
||||
}
|
||||
): Future[A] = usingLedger[A](testId) { case (ledgerPort, _, ledgerId) =>
|
||||
HttpServiceTestFixture.withHttpService[A](
|
||||
testId,
|
||||
ledgerPort,
|
||||
jdbcConfig,
|
||||
staticContentConfig,
|
||||
useTls = useTls,
|
||||
wsConfig = wsConfig,
|
||||
)(testFn(_, _, _, _, ledgerId))
|
||||
}
|
||||
|
||||
protected def withHttpServiceAndClient[A](maxInboundMessageSize: Int)(
|
||||
testFn: (Uri, DomainJsonEncoder, DomainJsonDecoder, DamlLedgerClient, LedgerId) => Future[A]
|
||||
): Future[A] =
|
||||
HttpServiceTestFixture.withLedger[A](List(dar1, dar2), testId, None, useTls) {
|
||||
case (ledgerPort, _, ledgerId) =>
|
||||
HttpServiceTestFixture.withHttpService[A](
|
||||
testId,
|
||||
ledgerPort,
|
||||
jdbcConfig,
|
||||
staticContentConfig,
|
||||
useTls = useTls,
|
||||
wsConfig = wsConfig,
|
||||
maxInboundMessageSize = maxInboundMessageSize,
|
||||
)(testFn(_, _, _, _, ledgerId))
|
||||
}
|
||||
): Future[A] = usingLedger[A](testId) { case (ledgerPort, _, ledgerId) =>
|
||||
HttpServiceTestFixture.withHttpService[A](
|
||||
testId,
|
||||
ledgerPort,
|
||||
jdbcConfig,
|
||||
staticContentConfig,
|
||||
useTls = useTls,
|
||||
wsConfig = wsConfig,
|
||||
maxInboundMessageSize = maxInboundMessageSize,
|
||||
)(testFn(_, _, _, _, ledgerId))
|
||||
}
|
||||
|
||||
protected def withHttpService[A](
|
||||
f: (Uri, DomainJsonEncoder, DomainJsonDecoder, LedgerId) => Future[A]
|
||||
@ -165,12 +176,12 @@ trait AbstractHttpServiceIntegrationTestFuns extends StrictLogging {
|
||||
)((uri, encoder, decoder, _) => f(uri, encoder, decoder))
|
||||
|
||||
protected def withLedger[A](testFn: (DamlLedgerClient, LedgerId) => Future[A]): Future[A] =
|
||||
HttpServiceTestFixture.withLedger[A](List(dar1, dar2), testId) { case (_, client, ledgerId) =>
|
||||
usingLedger[A](testId) { case (_, client, ledgerId) =>
|
||||
testFn(client, ledgerId)
|
||||
}
|
||||
|
||||
protected def withLedger2[A](testFn: (Port, DamlLedgerClient, LedgerId) => Future[A]): Future[A] =
|
||||
HttpServiceTestFixture.withLedger[A](List(dar1, dar2), testId)(testFn)
|
||||
usingLedger[A](testId)(testFn)
|
||||
|
||||
protected val headersWithAuth = authorizationHeader(jwt)
|
||||
|
||||
@ -224,8 +235,9 @@ trait AbstractHttpServiceIntegrationTestFuns extends StrictLogging {
|
||||
create: domain.CreateCommand[v.Record, OptionalPkg],
|
||||
encoder: DomainJsonEncoder,
|
||||
uri: Uri,
|
||||
headers: List[HttpHeader] = headersWithAuth,
|
||||
): Future[Assertion] =
|
||||
postContractsLookup(contractLocator, uri).flatMap { case (status, output) =>
|
||||
postContractsLookup(contractLocator, uri, headers).flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
val result = getResult(output)
|
||||
@ -283,15 +295,16 @@ trait AbstractHttpServiceIntegrationTestFuns extends StrictLogging {
|
||||
}
|
||||
|
||||
protected def iouCreateCommand(
|
||||
partyName: String,
|
||||
amount: String = "999.9900000000",
|
||||
currency: String = "USD",
|
||||
): domain.CreateCommand[v.Record, OptionalPkg] = {
|
||||
val templateId: OptionalPkg = domain.TemplateId(None, "Iou", "Iou")
|
||||
val alice = Ref.Party assertFromString "Alice"
|
||||
val party = Ref.Party assertFromString partyName
|
||||
val arg = argToApi(iouVA)(
|
||||
ShRecord(
|
||||
issuer = alice,
|
||||
owner = alice,
|
||||
issuer = party,
|
||||
owner = party,
|
||||
currency = currency,
|
||||
amount = LfNumeric assertFromString amount,
|
||||
observers = Vector.empty,
|
||||
@ -314,15 +327,16 @@ trait AbstractHttpServiceIntegrationTestFuns extends StrictLogging {
|
||||
}
|
||||
|
||||
protected def iouCreateAndExerciseTransferCommand(
|
||||
partyName: String,
|
||||
amount: String = "999.9900000000",
|
||||
currency: String = "USD",
|
||||
): domain.CreateAndExerciseCommand[v.Record, v.Value, OptionalPkg] = {
|
||||
val templateId: OptionalPkg = domain.TemplateId(None, "Iou", "Iou")
|
||||
val alice = Ref.Party assertFromString "Alice"
|
||||
val party = Ref.Party assertFromString partyName
|
||||
val payload = argToApi(iouVA)(
|
||||
ShRecord(
|
||||
issuer = alice,
|
||||
owner = alice,
|
||||
issuer = party,
|
||||
owner = party,
|
||||
currency = currency,
|
||||
amount = LfNumeric assertFromString amount,
|
||||
observers = Vector.empty,
|
||||
@ -412,10 +426,11 @@ trait AbstractHttpServiceIntegrationTestFuns extends StrictLogging {
|
||||
protected def postContractsLookup(
|
||||
cmd: domain.ContractLocator[JsValue],
|
||||
uri: Uri,
|
||||
headers: List[HttpHeader] = headersWithAuth,
|
||||
): Future[(StatusCode, JsValue)] =
|
||||
for {
|
||||
json <- toFuture(SprayJson.encode(cmd)): Future[JsValue]
|
||||
result <- postJsonRequest(uri.withPath(Uri.Path("/v1/fetch")), json)
|
||||
result <- postJsonRequest(uri.withPath(Uri.Path("/v1/fetch")), json, headers)
|
||||
} yield result
|
||||
|
||||
protected def activeContractList(output: JsValue): List[domain.ActiveContract[JsValue]] = {
|
||||
@ -539,21 +554,40 @@ trait AbstractHttpServiceIntegrationTestFuns extends StrictLogging {
|
||||
}
|
||||
}
|
||||
|
||||
protected def initialIouCreate(serviceUri: Uri): Future[(StatusCode, JsValue)] = {
|
||||
val payload = TestUtil.readFile("it/iouCreateCommand.json")
|
||||
protected def initialIouCreate(
|
||||
serviceUri: Uri,
|
||||
party: domain.Party,
|
||||
headers: List[HttpHeader],
|
||||
): Future[(StatusCode, JsValue)] = {
|
||||
val partyJson = party.unwrap
|
||||
val payload =
|
||||
s"""
|
||||
|{
|
||||
| "templateId": "Iou:Iou",
|
||||
| "payload": {
|
||||
| "observers": [],
|
||||
| "issuer": "$partyJson",
|
||||
| "amount": "999.99",
|
||||
| "currency": "USD",
|
||||
| "owner": "$partyJson"
|
||||
| }
|
||||
|}
|
||||
|""".stripMargin
|
||||
HttpServiceTestFixture.postJsonStringRequest(
|
||||
serviceUri.withPath(Uri.Path("/v1/create")),
|
||||
payload,
|
||||
headersWithAuth,
|
||||
headers,
|
||||
)
|
||||
}
|
||||
|
||||
protected def initialAccountCreate(
|
||||
serviceUri: Uri,
|
||||
encoder: DomainJsonEncoder,
|
||||
owner: domain.Party,
|
||||
headers: List[HttpHeader],
|
||||
): Future[(StatusCode, JsValue)] = {
|
||||
val command = accountCreateCommand(domain.Party("Alice"), "abc123")
|
||||
postCreateCommand(command, encoder, serviceUri)
|
||||
val command = accountCreateCommand(owner, "abc123")
|
||||
postCreateCommand(command, encoder, serviceUri, headers)
|
||||
}
|
||||
|
||||
protected def jsObject(s: String): JsObject = {
|
||||
@ -617,25 +651,31 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
override final def useTls = UseTls.NoTls
|
||||
|
||||
"query GET empty results" in withHttpService { (uri: Uri, _, _, _) =>
|
||||
searchAllExpectOk(uri).flatMap { case vector =>
|
||||
val (_, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
searchAllExpectOk(uri, headers).flatMap { case vector =>
|
||||
vector should have size 0L
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected val searchDataSet: List[domain.CreateCommand[v.Record, OptionalPkg]] =
|
||||
protected def genSearchDataSet(
|
||||
party: domain.Party
|
||||
): List[domain.CreateCommand[v.Record, OptionalPkg]] = {
|
||||
val partyName = party.unwrap
|
||||
List(
|
||||
iouCreateCommand(amount = "111.11", currency = "EUR"),
|
||||
iouCreateCommand(amount = "222.22", currency = "EUR"),
|
||||
iouCreateCommand(amount = "333.33", currency = "GBP"),
|
||||
iouCreateCommand(amount = "444.44", currency = "BTC"),
|
||||
iouCreateCommand(amount = "111.11", currency = "EUR", partyName = partyName),
|
||||
iouCreateCommand(amount = "222.22", currency = "EUR", partyName = partyName),
|
||||
iouCreateCommand(amount = "333.33", currency = "GBP", partyName = partyName),
|
||||
iouCreateCommand(amount = "444.44", currency = "BTC", partyName = partyName),
|
||||
)
|
||||
}
|
||||
|
||||
"query GET" in withHttpService { (uri: Uri, encoder, _, _) =>
|
||||
searchDataSet.traverse(c => postCreateCommand(c, encoder, uri)).flatMap { rs =>
|
||||
val (alice, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
val searchDataSet = genSearchDataSet(alice)
|
||||
searchDataSet.traverse(c => postCreateCommand(c, encoder, uri, headers)).flatMap { rs =>
|
||||
rs.map(_._1) shouldBe List.fill(searchDataSet.size)(StatusCodes.OK)
|
||||
|
||||
getRequest(uri = uri.withPath(Uri.Path("/v1/query")))
|
||||
getRequest(uri = uri.withPath(Uri.Path("/v1/query")), headers)
|
||||
.flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
@ -649,54 +689,59 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
}
|
||||
|
||||
"multi-party query GET" in withHttpService { (uri, encoder, _, _) =>
|
||||
val (alice, aliceHeaders) = getUniquePartyAndAuthHeaders("Alice")
|
||||
val (bob, bobHeaders) = getUniquePartyAndAuthHeaders("Alice")
|
||||
for {
|
||||
_ <- postCreateCommand(
|
||||
accountCreateCommand(owner = domain.Party("Alice"), number = "42"),
|
||||
accountCreateCommand(owner = alice, number = "42"),
|
||||
encoder,
|
||||
uri,
|
||||
headers = aliceHeaders,
|
||||
).map(r => r._1 shouldBe StatusCodes.OK)
|
||||
_ <- postCreateCommand(
|
||||
accountCreateCommand(owner = domain.Party("Bob"), number = "23"),
|
||||
accountCreateCommand(owner = bob, number = "23"),
|
||||
encoder,
|
||||
uri,
|
||||
headers = headersWithPartyAuth(List("Bob")),
|
||||
headers = bobHeaders,
|
||||
).map(r => r._1 shouldBe StatusCodes.OK)
|
||||
_ <- searchAllExpectOk(uri, headersWithPartyAuth(List("Alice"))).map(cs =>
|
||||
cs should have size 1
|
||||
)
|
||||
_ <- searchAllExpectOk(uri, headersWithPartyAuth(List("Bob"))).map(cs =>
|
||||
cs should have size 1
|
||||
)
|
||||
_ <- searchAllExpectOk(uri, headersWithPartyAuth(List("Alice", "Bob"))).map(cs =>
|
||||
_ <- searchAllExpectOk(uri, aliceHeaders).map(cs => cs should have size 1)
|
||||
_ <- searchAllExpectOk(uri, bobHeaders).map(cs => cs should have size 1)
|
||||
_ <- searchAllExpectOk(uri, headersWithPartyAuth(List(alice.unwrap, bob.unwrap))).map(cs =>
|
||||
cs should have size 2
|
||||
)
|
||||
} yield succeed
|
||||
}
|
||||
|
||||
"query POST with empty query" in withHttpService { (uri, encoder, _, _) =>
|
||||
val (alice, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
val searchDataSet = genSearchDataSet(alice)
|
||||
searchExpectOk(
|
||||
searchDataSet,
|
||||
jsObject("""{"templateIds": ["Iou:Iou"]}"""),
|
||||
uri,
|
||||
encoder,
|
||||
headers,
|
||||
).map { acl: List[domain.ActiveContract[JsValue]] =>
|
||||
acl.size shouldBe searchDataSet.size
|
||||
}
|
||||
}
|
||||
|
||||
"multi-party query POST with empty query" in withHttpService { (uri, encoder, _, _) =>
|
||||
val (alice, aliceHeaders) = getUniquePartyAndAuthHeaders("Alice")
|
||||
val (bob, bobHeaders) = getUniquePartyAndAuthHeaders("Alice")
|
||||
for {
|
||||
aliceAccountResp <- postCreateCommand(
|
||||
accountCreateCommand(owner = domain.Party("Alice"), number = "42"),
|
||||
accountCreateCommand(owner = alice, number = "42"),
|
||||
encoder,
|
||||
uri,
|
||||
aliceHeaders,
|
||||
)
|
||||
_ = aliceAccountResp._1 shouldBe StatusCodes.OK
|
||||
bobAccountResp <- postCreateCommand(
|
||||
accountCreateCommand(owner = domain.Party("Bob"), number = "23"),
|
||||
accountCreateCommand(owner = bob, number = "23"),
|
||||
encoder,
|
||||
uri,
|
||||
headers = headersWithPartyAuth(List("Bob")),
|
||||
bobHeaders,
|
||||
)
|
||||
_ = bobAccountResp._1 shouldBe StatusCodes.OK
|
||||
_ <- searchExpectOk(
|
||||
@ -704,7 +749,7 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
jsObject("""{"templateIds": ["Account:Account"]}"""),
|
||||
uri,
|
||||
encoder,
|
||||
headers = headersWithPartyAuth(List("Alice")),
|
||||
aliceHeaders,
|
||||
)
|
||||
.map(acl => acl.size shouldBe 1)
|
||||
_ <- searchExpectOk(
|
||||
@ -712,7 +757,7 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
jsObject("""{"templateIds": ["Account:Account"]}"""),
|
||||
uri,
|
||||
encoder,
|
||||
headers = headersWithPartyAuth(List("Bob")),
|
||||
bobHeaders,
|
||||
)
|
||||
.map(acl => acl.size shouldBe 1)
|
||||
_ <- searchExpectOk(
|
||||
@ -720,7 +765,7 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
jsObject("""{"templateIds": ["Account:Account"]}"""),
|
||||
uri,
|
||||
encoder,
|
||||
headers = headersWithPartyAuth(List("Alice", "Bob")),
|
||||
headers = headersWithPartyAuth(List(alice.unwrap, bob.unwrap)),
|
||||
)
|
||||
.map(acl => acl.size shouldBe 2)
|
||||
} yield {
|
||||
@ -729,11 +774,14 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
}
|
||||
|
||||
"query with query, one field" in withHttpService { (uri, encoder, _, _) =>
|
||||
val (alice, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
val searchDataSet = genSearchDataSet(alice)
|
||||
searchExpectOk(
|
||||
searchDataSet,
|
||||
jsObject("""{"templateIds": ["Iou:Iou"], "query": {"currency": "EUR"}}"""),
|
||||
uri,
|
||||
encoder,
|
||||
headers,
|
||||
).map { acl: List[domain.ActiveContract[JsValue]] =>
|
||||
acl.size shouldBe 2
|
||||
acl.map(a => objectField(a.payload, "currency")) shouldBe List.fill(2)(Some(JsString("EUR")))
|
||||
@ -746,23 +794,28 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
"""{"templateIds": ["Iou:Iou", "UnknownModule:UnknownEntity"], "query": {"currency": "EUR"}}"""
|
||||
)
|
||||
|
||||
search(List(), query, uri, encoder).map { response =>
|
||||
inside(response) { case domain.OkResponse(acl, warnings, StatusCodes.OK) =>
|
||||
acl.size shouldBe 0
|
||||
warnings shouldBe Some(
|
||||
domain.UnknownTemplateIds(List(domain.TemplateId(None, "UnknownModule", "UnknownEntity")))
|
||||
)
|
||||
}
|
||||
search(List(), query, uri, encoder, headersWithPartyAuth(List("UnknownParty"))).map {
|
||||
response =>
|
||||
inside(response) { case domain.OkResponse(acl, warnings, StatusCodes.OK) =>
|
||||
acl.size shouldBe 0
|
||||
warnings shouldBe Some(
|
||||
domain.UnknownTemplateIds(
|
||||
List(domain.TemplateId(None, "UnknownModule", "UnknownEntity"))
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"query returns unknown Template IDs as warnings and error" in withHttpService {
|
||||
(uri, encoder, _, _) =>
|
||||
val (alice, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
search(
|
||||
searchDataSet,
|
||||
genSearchDataSet(alice),
|
||||
jsObject("""{"templateIds": ["AAA:BBB", "XXX:YYY"]}"""),
|
||||
uri,
|
||||
encoder,
|
||||
headers,
|
||||
).map { response =>
|
||||
inside(response) { case domain.ErrorResponse(errors, warnings, StatusCodes.BadRequest) =>
|
||||
errors shouldBe List(ErrorMessages.cannotResolveAnyTemplateId)
|
||||
@ -780,7 +833,9 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
(uri, encoder, _, _) =>
|
||||
import scalaz.std.scalaFuture._
|
||||
|
||||
searchDataSet.traverse(c => postCreateCommand(c, encoder, uri)).flatMap {
|
||||
val (alice, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
val searchDataSet = genSearchDataSet(alice)
|
||||
searchDataSet.traverse(c => postCreateCommand(c, encoder, uri, headers)).flatMap {
|
||||
rs: List[(StatusCode, JsValue)] =>
|
||||
rs.map(_._1) shouldBe List.fill(searchDataSet.size)(StatusCodes.OK)
|
||||
|
||||
@ -791,8 +846,8 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
val queryAmountAsNumber = queryAmountAs("111.11")
|
||||
|
||||
List(
|
||||
postJsonRequest(uri.withPath(Uri.Path("/v1/query")), queryAmountAsString),
|
||||
postJsonRequest(uri.withPath(Uri.Path("/v1/query")), queryAmountAsNumber),
|
||||
postJsonRequest(uri.withPath(Uri.Path("/v1/query")), queryAmountAsString, headers),
|
||||
postJsonRequest(uri.withPath(Uri.Path("/v1/query")), queryAmountAsNumber, headers),
|
||||
).sequence.flatMap { rs: List[(StatusCode, JsValue)] =>
|
||||
rs.map(_._1) shouldBe List.fill(2)(StatusCodes.OK)
|
||||
inside(rs.map(_._2)) { case List(jsVal1, jsVal2) =>
|
||||
@ -826,13 +881,18 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
).foreach { case (testLbl, testCurrency) =>
|
||||
s"query record contains handles '$testLbl' strings properly" in withHttpService {
|
||||
(uri, encoder, _, _) =>
|
||||
val (alice, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
searchExpectOk(
|
||||
searchDataSet :+ iouCreateCommand(currency = testCurrency),
|
||||
genSearchDataSet(alice) :+ iouCreateCommand(
|
||||
currency = testCurrency,
|
||||
partyName = alice.unwrap,
|
||||
),
|
||||
jsObject(
|
||||
s"""{"templateIds": ["Iou:Iou"], "query": {"currency": ${testCurrency.toJson}}}"""
|
||||
),
|
||||
uri,
|
||||
encoder,
|
||||
headers,
|
||||
).map(inside(_) { case Seq(domain.ActiveContract(_, _, _, JsObject(fields), _, _, _)) =>
|
||||
fields.get("currency") should ===(Some(JsString(testCurrency)))
|
||||
})
|
||||
@ -840,6 +900,8 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
}
|
||||
|
||||
"query with query, two fields" in withHttpService { (uri, encoder, _, _) =>
|
||||
val (alice, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
val searchDataSet = genSearchDataSet(alice)
|
||||
searchExpectOk(
|
||||
searchDataSet,
|
||||
jsObject(
|
||||
@ -847,6 +909,7 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
),
|
||||
uri,
|
||||
encoder,
|
||||
headers,
|
||||
).map { acl: List[domain.ActiveContract[JsValue]] =>
|
||||
acl.size shouldBe 1
|
||||
acl.map(a => objectField(a.payload, "currency")) shouldBe List(Some(JsString("EUR")))
|
||||
@ -855,6 +918,8 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
}
|
||||
|
||||
"query with query, no results" in withHttpService { (uri, encoder, _, _) =>
|
||||
val (alice, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
val searchDataSet = genSearchDataSet(alice)
|
||||
searchExpectOk(
|
||||
searchDataSet,
|
||||
jsObject(
|
||||
@ -862,6 +927,7 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
),
|
||||
uri,
|
||||
encoder,
|
||||
headers,
|
||||
).map { acl: List[domain.ActiveContract[JsValue]] =>
|
||||
acl.size shouldBe 0
|
||||
}
|
||||
@ -894,9 +960,10 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
}
|
||||
|
||||
"create IOU" in withHttpService { (uri, encoder, _, _) =>
|
||||
val command: domain.CreateCommand[v.Record, OptionalPkg] = iouCreateCommand()
|
||||
val (alice, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
val command: domain.CreateCommand[v.Record, OptionalPkg] = iouCreateCommand(alice.unwrap)
|
||||
|
||||
postCreateCommand(command, encoder, uri).flatMap { case (status, output) =>
|
||||
postCreateCommand(command, encoder, uri, headers).flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
val activeContract = getResult(output)
|
||||
@ -906,8 +973,8 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
|
||||
"create IOU should fail if authorization header is missing" in withHttpService {
|
||||
(uri, encoder, _, _) =>
|
||||
val command: domain.CreateCommand[v.Record, OptionalPkg] =
|
||||
iouCreateCommand()
|
||||
val alice = getUniqueParty("Alice")
|
||||
val command: domain.CreateCommand[v.Record, OptionalPkg] = iouCreateCommand(alice.unwrap)
|
||||
val input: JsValue = encoder.encodeCreateCommand(command).valueOr(e => fail(e.shows))
|
||||
|
||||
postJsonRequest(uri.withPath(Uri.Path("/v1/create")), input, List()).flatMap {
|
||||
@ -921,13 +988,14 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
}
|
||||
|
||||
"create IOU should support extra readAs parties" in withHttpService { (uri, encoder, _, _) =>
|
||||
val command: domain.CreateCommand[v.Record, OptionalPkg] = iouCreateCommand()
|
||||
val alice = getUniqueParty("Alice")
|
||||
val command: domain.CreateCommand[v.Record, OptionalPkg] = iouCreateCommand(alice.unwrap)
|
||||
val input: JsValue = encoder.encodeCreateCommand(command).valueOr(e => fail(e.shows))
|
||||
|
||||
postJsonRequest(
|
||||
uri.withPath(Uri.Path("/v1/create")),
|
||||
input,
|
||||
headers = headersWithPartyAuth(actAs = List("Alice"), readAs = List("Bob")),
|
||||
headers = headersWithPartyAuth(actAs = List(alice.unwrap), readAs = List("Bob")),
|
||||
).flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
@ -938,11 +1006,12 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
|
||||
"create IOU with unsupported templateId should return proper error" in withHttpService {
|
||||
(uri, encoder, _, _) =>
|
||||
val (alice, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
val command: domain.CreateCommand[v.Record, OptionalPkg] =
|
||||
iouCreateCommand().copy(templateId = domain.TemplateId(None, "Iou", "Dummy"))
|
||||
iouCreateCommand(alice.unwrap).copy(templateId = domain.TemplateId(None, "Iou", "Dummy"))
|
||||
val input: JsValue = encoder.encodeCreateCommand(command).valueOr(e => fail(e.shows))
|
||||
|
||||
postJsonRequest(uri.withPath(Uri.Path("/v1/create")), input).flatMap {
|
||||
postJsonRequest(uri.withPath(Uri.Path("/v1/create")), input, headers).flatMap {
|
||||
case (status, output) =>
|
||||
status shouldBe StatusCodes.BadRequest
|
||||
assertStatus(output, StatusCodes.BadRequest)
|
||||
@ -955,8 +1024,9 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
}
|
||||
|
||||
"exercise IOU_Transfer" in withHttpService { (uri, encoder, decoder, ledgerId) =>
|
||||
val create: domain.CreateCommand[v.Record, OptionalPkg] = iouCreateCommand()
|
||||
postCreateCommand(create, encoder, uri)
|
||||
val (alice, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
val create: domain.CreateCommand[v.Record, OptionalPkg] = iouCreateCommand(alice.unwrap)
|
||||
postCreateCommand(create, encoder, uri, headers)
|
||||
.flatMap { case (createStatus, createOutput) =>
|
||||
createStatus shouldBe StatusCodes.OK
|
||||
assertStatus(createOutput, StatusCodes.OK)
|
||||
@ -966,7 +1036,7 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
iouExerciseTransferCommand(contractId)
|
||||
val exerciseJson: JsValue = encodeExercise(encoder)(exercise)
|
||||
|
||||
postJsonRequest(uri.withPath(Uri.Path("/v1/exercise")), exerciseJson)
|
||||
postJsonRequest(uri.withPath(Uri.Path("/v1/exercise")), exerciseJson, headers)
|
||||
.flatMap { case (exerciseStatus, exerciseOutput) =>
|
||||
exerciseStatus shouldBe StatusCodes.OK
|
||||
assertStatus(exerciseOutput, StatusCodes.OK)
|
||||
@ -977,18 +1047,20 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
decoder,
|
||||
uri,
|
||||
ledgerId,
|
||||
headers,
|
||||
)
|
||||
}
|
||||
}: Future[Assertion]
|
||||
}
|
||||
|
||||
"create-and-exercise IOU_Transfer" in withHttpService { (uri, encoder, _, _) =>
|
||||
val (alice, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
val cmd: domain.CreateAndExerciseCommand[v.Record, v.Value, OptionalPkg] =
|
||||
iouCreateAndExerciseTransferCommand()
|
||||
iouCreateAndExerciseTransferCommand(alice.unwrap)
|
||||
|
||||
val json: JsValue = encoder.encodeCreateAndExerciseCommand(cmd).valueOr(e => fail(e.shows))
|
||||
|
||||
postJsonRequest(uri.withPath(Uri.Path("/v1/create-and-exercise")), json)
|
||||
postJsonRequest(uri.withPath(Uri.Path("/v1/create-and-exercise")), json, headers)
|
||||
.flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
inside(
|
||||
@ -1019,6 +1091,7 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
decoder: DomainJsonDecoder,
|
||||
uri: Uri,
|
||||
ledgerId: LedgerId,
|
||||
headers: List[HttpHeader],
|
||||
): Future[Assertion] = {
|
||||
inside(SprayJson.decode[domain.ExerciseResponse[JsValue]](exerciseResponse)) {
|
||||
case \/-(domain.ExerciseResponse(JsString(exerciseResult), List(contract1, contract2))) =>
|
||||
@ -1038,7 +1111,7 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
Some(domain.TemplateId(None, "Iou", "IouTransfer")),
|
||||
domain.ContractId(exerciseResult),
|
||||
)
|
||||
postContractsLookup(newContractLocator, uri).flatMap { case (status, output) =>
|
||||
postContractsLookup(newContractLocator, uri, headers).flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
getContractId(getResult(output)) shouldBe newContractLocator.contractId
|
||||
@ -1049,21 +1122,23 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
|
||||
"exercise IOU_Transfer with unknown contractId should return proper error" in withHttpService {
|
||||
(uri, encoder, _, _) =>
|
||||
val contractId = lar.ContractId("#NonExistentContractId")
|
||||
val contractIdString = "0" * 66
|
||||
val contractId = lar.ContractId(contractIdString)
|
||||
val exerciseJson: JsValue = encodeExercise(encoder)(iouExerciseTransferCommand(contractId))
|
||||
postJsonRequest(uri.withPath(Uri.Path("/v1/exercise")), exerciseJson)
|
||||
.flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.InternalServerError
|
||||
assertStatus(output, StatusCodes.InternalServerError)
|
||||
expectedOneErrorMessage(output) should include(
|
||||
"Contract could not be found with id ContractId(#NonExistentContractId)"
|
||||
s"Contract could not be found with id ContractId($contractIdString)"
|
||||
)
|
||||
}: Future[Assertion]
|
||||
}
|
||||
|
||||
"exercise Archive" in withHttpService { (uri, encoder, _, _) =>
|
||||
val create: domain.CreateCommand[v.Record, OptionalPkg] = iouCreateCommand()
|
||||
postCreateCommand(create, encoder, uri)
|
||||
val (alice, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
val create: domain.CreateCommand[v.Record, OptionalPkg] = iouCreateCommand(alice.unwrap)
|
||||
postCreateCommand(create, encoder, uri, headers)
|
||||
.flatMap { case (createStatus, createOutput) =>
|
||||
createStatus shouldBe StatusCodes.OK
|
||||
assertStatus(createOutput, StatusCodes.OK)
|
||||
@ -1074,7 +1149,7 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
val exercise = archiveCommand(reference)
|
||||
val exerciseJson: JsValue = encodeExercise(encoder)(exercise)
|
||||
|
||||
postJsonRequest(uri.withPath(Uri.Path("/v1/exercise")), exerciseJson)
|
||||
postJsonRequest(uri.withPath(Uri.Path("/v1/exercise")), exerciseJson, headers)
|
||||
.flatMap { case (exerciseStatus, exerciseOutput) =>
|
||||
exerciseStatus shouldBe StatusCodes.OK
|
||||
assertStatus(exerciseOutput, StatusCodes.OK)
|
||||
@ -1085,17 +1160,7 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
}
|
||||
|
||||
"should support multi-party command submissions" in withHttpService { (uri, encoder, _, _) =>
|
||||
val newDar = AbstractHttpServiceIntegrationTestFuns.dar3
|
||||
for {
|
||||
_ <- Http()
|
||||
.singleRequest(
|
||||
HttpRequest(
|
||||
method = HttpMethods.POST,
|
||||
uri = uri.withPath(Uri.Path("/v1/packages")),
|
||||
headers = authorizationHeader(jwtAdminNoParty),
|
||||
entity = HttpEntity.fromFile(ContentTypes.`application/octet-stream`, newDar),
|
||||
)
|
||||
)
|
||||
// multi-party actAs on create
|
||||
cid <- postCreateCommand(
|
||||
multiPartyCreateCommand(List("Alice", "Bob"), ""),
|
||||
@ -1174,7 +1239,7 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
import json.JsonProtocol._
|
||||
import util.ErrorOps._
|
||||
|
||||
val command0: domain.CreateCommand[v.Record, OptionalPkg] = iouCreateCommand()
|
||||
val command0: domain.CreateCommand[v.Record, OptionalPkg] = iouCreateCommand("Alice")
|
||||
|
||||
type F[A] = EitherT[Future, JsonError, A]
|
||||
val x: F[Assertion] = for {
|
||||
@ -1214,7 +1279,7 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
"parties endpoint should return all known parties" in withHttpServiceAndClient {
|
||||
(uri, _, _, client, _) =>
|
||||
import scalaz.std.vector._
|
||||
val partyIds = Vector("Alice", "Bob", "Charlie", "Dave")
|
||||
val partyIds = Vector("P1", "P2", "P3", "P4")
|
||||
val partyManagement = client.partyManagementClient
|
||||
|
||||
partyIds
|
||||
@ -1230,8 +1295,8 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
response.status shouldBe StatusCodes.OK
|
||||
response.warnings shouldBe empty
|
||||
val actualIds: Set[domain.Party] = response.result.view.map(_.identifier).toSet
|
||||
actualIds shouldBe domain.Party.subst(partyIds.toSet)
|
||||
response.result.toSet shouldBe
|
||||
actualIds should contain allElementsOf domain.Party.subst(partyIds.toSet)
|
||||
response.result.toSet should contain allElementsOf
|
||||
allocatedParties.toSet.map(domain.PartyDetails.fromLedgerApi)
|
||||
}
|
||||
}
|
||||
@ -1242,9 +1307,9 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
(uri, _, _, client, _) =>
|
||||
import scalaz.std.vector._
|
||||
|
||||
val charlie = domain.Party("Charlie")
|
||||
val knownParties = domain.Party.subst(Vector("Alice", "Bob", "Dave")) :+ charlie
|
||||
val erin = domain.Party("Erin")
|
||||
val charlie = getUniqueParty("Charlie")
|
||||
val knownParties = Vector(getUniqueParty("Alice"), getUniqueParty("Bob")) :+ charlie
|
||||
val erin = getUniqueParty("Erin")
|
||||
val requestedPartyIds: Vector[domain.Party] = knownParties.filterNot(_ == charlie) :+ erin
|
||||
|
||||
val partyManagement = client.partyManagementClient
|
||||
@ -1308,8 +1373,7 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
"parties endpoint returns empty result with warnings and OK status if nothing found" in withHttpServiceAndClient {
|
||||
(uri, _, _, _, _) =>
|
||||
val requestedPartyIds: Vector[domain.Party] =
|
||||
domain.Party.subst(Vector("Alice", "Bob", "Dave"))
|
||||
|
||||
Vector(getUniqueParty("Alice"), getUniqueParty("Bob"))
|
||||
postJsonRequest(
|
||||
uri = uri.withPath(Uri.Path("/v1/parties")),
|
||||
JsArray(requestedPartyIds.map(x => JsString(x.unwrap))),
|
||||
@ -1402,26 +1466,27 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
}
|
||||
|
||||
"fetch by contractId" in withHttpService { (uri, encoder, _, _) =>
|
||||
val command: domain.CreateCommand[v.Record, OptionalPkg] = iouCreateCommand()
|
||||
val (alice, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
val command: domain.CreateCommand[v.Record, OptionalPkg] = iouCreateCommand(alice.unwrap)
|
||||
|
||||
postCreateCommand(command, encoder, uri).flatMap { case (status, output) =>
|
||||
postCreateCommand(command, encoder, uri, headers).flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
val contractId: ContractId = getContractId(getResult(output))
|
||||
val locator = domain.EnrichedContractId(None, contractId)
|
||||
lookupContractAndAssert(locator)(contractId, command, encoder, uri)
|
||||
lookupContractAndAssert(locator)(contractId, command, encoder, uri, headers)
|
||||
}: Future[Assertion]
|
||||
}
|
||||
|
||||
"fetch returns {status:200, result:null} when contract is not found" in withHttpService {
|
||||
(uri, _, _, _) =>
|
||||
val owner = domain.Party("Alice")
|
||||
val (alice, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
val accountNumber = "abc123"
|
||||
val locator = domain.EnrichedContractKey(
|
||||
domain.TemplateId(None, "Account", "Account"),
|
||||
JsArray(JsString(owner.unwrap), JsString(accountNumber)),
|
||||
JsArray(JsString(alice.unwrap), JsString(accountNumber)),
|
||||
)
|
||||
postContractsLookup(locator, uri.withPath(Uri.Path("/v1/fetch"))).flatMap {
|
||||
postContractsLookup(locator, uri.withPath(Uri.Path("/v1/fetch")), headers).flatMap {
|
||||
case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
@ -1433,32 +1498,32 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
}
|
||||
|
||||
"fetch by key" in withHttpService { (uri, encoder, _, _) =>
|
||||
val owner = domain.Party("Alice")
|
||||
val (alice, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
val accountNumber = "abc123"
|
||||
val command: domain.CreateCommand[v.Record, OptionalPkg] =
|
||||
accountCreateCommand(owner, accountNumber)
|
||||
accountCreateCommand(alice, accountNumber)
|
||||
|
||||
postCreateCommand(command, encoder, uri).flatMap { case (status, output) =>
|
||||
postCreateCommand(command, encoder, uri, headers).flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
val contractId: ContractId = getContractId(getResult(output))
|
||||
val locator = domain.EnrichedContractKey(
|
||||
domain.TemplateId(None, "Account", "Account"),
|
||||
JsArray(JsString(owner.unwrap), JsString(accountNumber)),
|
||||
JsArray(JsString(alice.unwrap), JsString(accountNumber)),
|
||||
)
|
||||
lookupContractAndAssert(locator)(contractId, command, encoder, uri)
|
||||
lookupContractAndAssert(locator)(contractId, command, encoder, uri, headers)
|
||||
}: Future[Assertion]
|
||||
}
|
||||
|
||||
"commands/exercise Archive by key" in withHttpService { (uri, encoder, _, _) =>
|
||||
val owner = domain.Party("Alice")
|
||||
val (alice, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
val accountNumber = "abc123"
|
||||
val create: domain.CreateCommand[v.Record, OptionalPkg] =
|
||||
accountCreateCommand(owner, accountNumber)
|
||||
accountCreateCommand(alice, accountNumber)
|
||||
|
||||
val keyRecord = v.Record(
|
||||
fields = Seq(
|
||||
v.RecordField(value = Some(v.Value(v.Value.Sum.Party(owner.unwrap)))),
|
||||
v.RecordField(value = Some(v.Value(v.Value.Sum.Party(alice.unwrap)))),
|
||||
v.RecordField(value = Some(v.Value(v.Value.Sum.Text(accountNumber)))),
|
||||
)
|
||||
)
|
||||
@ -1470,11 +1535,11 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
archiveCommand(locator)
|
||||
val archiveJson: JsValue = encodeExercise(encoder)(archive)
|
||||
|
||||
postCreateCommand(create, encoder, uri).flatMap { case (status, output) =>
|
||||
postCreateCommand(create, encoder, uri, headers).flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
|
||||
postJsonRequest(uri.withPath(Uri.Path("/v1/exercise")), archiveJson).flatMap {
|
||||
postJsonRequest(uri.withPath(Uri.Path("/v1/exercise")), archiveJson, headers).flatMap {
|
||||
case (exerciseStatus, exerciseOutput) =>
|
||||
exerciseStatus shouldBe StatusCodes.OK
|
||||
assertStatus(exerciseOutput, StatusCodes.OK)
|
||||
@ -1484,53 +1549,63 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
|
||||
"fetch by key containing variant and record, encoded as array with number num" in withHttpService {
|
||||
(uri, _, _, _) =>
|
||||
val (alice, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
testFetchByCompositeKey(
|
||||
uri,
|
||||
jsObject("""{
|
||||
jsObject(s"""{
|
||||
"templateId": "Account:KeyedByVariantAndRecord",
|
||||
"key": [
|
||||
"Alice",
|
||||
"$alice",
|
||||
{"tag": "Bar", "value": 42},
|
||||
{"baz": "another baz value"}
|
||||
]
|
||||
}"""),
|
||||
alice,
|
||||
headers,
|
||||
)
|
||||
}
|
||||
|
||||
"fetch by key containing variant and record, encoded as record with string num" in withHttpService {
|
||||
(uri, _, _, _) =>
|
||||
val (alice, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
testFetchByCompositeKey(
|
||||
uri,
|
||||
jsObject("""{
|
||||
jsObject(s"""{
|
||||
"templateId": "Account:KeyedByVariantAndRecord",
|
||||
"key": {
|
||||
"_1": "Alice",
|
||||
"_1": "$alice",
|
||||
"_2": {"tag": "Bar", "value": "42"},
|
||||
"_3": {"baz": "another baz value"}
|
||||
}
|
||||
}"""),
|
||||
alice,
|
||||
headers,
|
||||
)
|
||||
}
|
||||
|
||||
private def testFetchByCompositeKey(uri: Uri, request: JsObject) = {
|
||||
val createCommand = jsObject("""{
|
||||
private def testFetchByCompositeKey(
|
||||
uri: Uri,
|
||||
request: JsObject,
|
||||
party: domain.Party,
|
||||
headers: List[HttpHeader],
|
||||
) = {
|
||||
val createCommand = jsObject(s"""{
|
||||
"templateId": "Account:KeyedByVariantAndRecord",
|
||||
"payload": {
|
||||
"name": "ABC DEF",
|
||||
"party": "Alice",
|
||||
"party": "${party.unwrap}",
|
||||
"age": 123,
|
||||
"fooVariant": {"tag": "Bar", "value": 42},
|
||||
"bazRecord": {"baz": "another baz value"}
|
||||
}
|
||||
}""")
|
||||
|
||||
postJsonRequest(uri.withPath(Uri.Path("/v1/create")), createCommand).flatMap {
|
||||
postJsonRequest(uri.withPath(Uri.Path("/v1/create")), createCommand, headers).flatMap {
|
||||
case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
val contractId: ContractId = getContractId(getResult(output))
|
||||
|
||||
postJsonRequest(uri.withPath(Uri.Path("/v1/fetch")), request).flatMap {
|
||||
postJsonRequest(uri.withPath(Uri.Path("/v1/fetch")), request, headers).flatMap {
|
||||
case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
@ -1540,12 +1615,12 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
}
|
||||
|
||||
"query by a variant field" in withHttpService { (uri, encoder, _, _) =>
|
||||
val owner = domain.Party("Alice")
|
||||
val (alice, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
val accountNumber = "abc123"
|
||||
val now = TimestampConversion.instantToMicros(Instant.now)
|
||||
val nowStr = TimestampConversion.microsToInstant(now).toString
|
||||
val command: domain.CreateCommand[v.Record, OptionalPkg] =
|
||||
accountCreateCommand(owner, accountNumber, now)
|
||||
accountCreateCommand(alice, accountNumber, now)
|
||||
|
||||
val packageId: Ref.PackageId = MetadataReader
|
||||
.templateByName(metadata2)(Ref.QualifiedName.assertFromString("Account:Account"))
|
||||
@ -1553,7 +1628,7 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
.map(_._1)
|
||||
.getOrElse(fail(s"Cannot retrieve packageId"))
|
||||
|
||||
postCreateCommand(command, encoder, uri).flatMap { case (status, output) =>
|
||||
postCreateCommand(command, encoder, uri, headers).flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
val contractId: ContractId = getContractId(getResult(output))
|
||||
@ -1566,7 +1641,7 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
}
|
||||
}""")
|
||||
|
||||
postJsonRequest(uri.withPath(Uri.Path("/v1/query")), query).map {
|
||||
postJsonRequest(uri.withPath(Uri.Path("/v1/query")), query, headers).map {
|
||||
case (searchStatus, searchOutput) =>
|
||||
searchStatus shouldBe StatusCodes.OK
|
||||
assertStatus(searchOutput, StatusCodes.OK)
|
||||
@ -1635,14 +1710,16 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
|
||||
"package list is updated when a query request is made" in withLedger2[Assertion] {
|
||||
(ledgerPort: Port, _, _) =>
|
||||
val (alice, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
for {
|
||||
_ <- withHttpServiceOnly(ledgerPort) { (uri, encoder, _) =>
|
||||
searchDataSet.traverse(c => postCreateCommand(c, encoder, uri)).flatMap { rs =>
|
||||
val searchDataSet = genSearchDataSet(alice)
|
||||
searchDataSet.traverse(c => postCreateCommand(c, encoder, uri, headers)).flatMap { rs =>
|
||||
rs.map(_._1) shouldBe List.fill(searchDataSet.size)(StatusCodes.OK)
|
||||
}
|
||||
}
|
||||
_ <- withHttpServiceOnly(ledgerPort) { (uri, _, _) =>
|
||||
getRequest(uri = uri.withPath(Uri.Path("/v1/query")))
|
||||
getRequest(uri = uri.withPath(Uri.Path("/v1/query")), headers)
|
||||
.flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
@ -1654,13 +1731,15 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
} yield succeed
|
||||
}
|
||||
|
||||
"archiving a large number of contracts should succeed" in withHttpServiceAndClient(
|
||||
"archiving a large number of contracts should succeed" taggedAs (SkipScala212) in withHttpServiceAndClient(
|
||||
StartSettings.DefaultMaxInboundMessageSize * 10
|
||||
) { (uri, encoder, _, _, _) =>
|
||||
val numContracts: Long = 10000
|
||||
val (alice, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
//The numContracts size should test for https://github.com/digital-asset/daml/issues/10339
|
||||
val numContracts: Long = 2000
|
||||
val helperId = domain.TemplateId(None, "Account", "Helper")
|
||||
val payload = v.Record(
|
||||
fields = List(v.RecordField("owner", Some(v.Value(v.Value.Sum.Party("Alice")))))
|
||||
fields = List(v.RecordField("owner", Some(v.Value(v.Value.Sum.Party(alice.unwrap)))))
|
||||
)
|
||||
val createCmd: domain.CreateAndExerciseCommand[v.Record, v.Value, OptionalPkg] =
|
||||
domain.CreateAndExerciseCommand(
|
||||
@ -1700,6 +1779,7 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
def queryN(n: Long): Future[Assertion] = postJsonRequest(
|
||||
uri.withPath(Uri.Path("/v1/query")),
|
||||
jsObject("""{"templateIds": ["Account:Account"]}"""),
|
||||
headers,
|
||||
).flatMap { case (status, output) =>
|
||||
status shouldBe StatusCodes.OK
|
||||
assertStatus(output, StatusCodes.OK)
|
||||
@ -1709,7 +1789,11 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
}
|
||||
|
||||
for {
|
||||
resp <- postJsonRequest(uri.withPath(Uri.Path("/v1/create-and-exercise")), encode(createCmd))
|
||||
resp <- postJsonRequest(
|
||||
uri.withPath(Uri.Path("/v1/create-and-exercise")),
|
||||
encode(createCmd),
|
||||
headers,
|
||||
)
|
||||
(status, output) = resp
|
||||
_ = {
|
||||
status shouldBe StatusCodes.OK
|
||||
@ -1723,6 +1807,7 @@ abstract class AbstractHttpServiceIntegrationTest
|
||||
status <- postJsonRequest(
|
||||
uri.withPath(Uri.Path("/v1/create-and-exercise")),
|
||||
encode(archiveCmd(created)),
|
||||
headers,
|
||||
).map(_._1)
|
||||
_ = {
|
||||
status shouldBe StatusCodes.OK
|
||||
|
@ -9,7 +9,6 @@ import java.time.Clock
|
||||
|
||||
import akka.http.scaladsl.model.Uri
|
||||
import com.daml.doobie.logging.Slf4jLogHandler
|
||||
import com.daml.http.AbstractHttpServiceIntegrationTestFuns.{dar1, dar2}
|
||||
import com.daml.http.dbbackend.JdbcConfig
|
||||
import com.daml.http.json.{DomainJsonDecoder, DomainJsonEncoder}
|
||||
import com.daml.ledger.api.v1.command_service.CommandServiceGrpc
|
||||
@ -85,7 +84,7 @@ abstract class AbstractNonRepudiationTest
|
||||
}
|
||||
|
||||
private def withParticipant[A] =
|
||||
HttpServiceTestFixture.withLedger[A](List(dar1, dar2), testId, None, useTls) _
|
||||
usingLedger[A](testId) _
|
||||
|
||||
private def withJsonApi[A](participantPort: Port) =
|
||||
HttpServiceTestFixture.withHttpService[A](
|
||||
|
@ -6,7 +6,7 @@ package com.daml.http
|
||||
import akka.NotUsed
|
||||
import akka.http.scaladsl.Http
|
||||
import akka.http.scaladsl.model.ws.{Message, TextMessage, WebSocketRequest}
|
||||
import akka.http.scaladsl.model.{StatusCodes, Uri}
|
||||
import akka.http.scaladsl.model.{HttpHeader, StatusCodes, Uri}
|
||||
import akka.stream.{KillSwitches, UniqueKillSwitch}
|
||||
import akka.stream.scaladsl.{Keep, Sink, Source}
|
||||
import com.daml.http.json.SprayJson
|
||||
@ -159,9 +159,10 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
|
||||
"query endpoint should publish transactions when command create is completed" in withHttpService {
|
||||
(uri, _, _, _) =>
|
||||
val (alice, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
for {
|
||||
_ <- initialIouCreate(uri)
|
||||
|
||||
_ <- initialIouCreate(uri, alice, headers)
|
||||
jwt = jwtForParties(List(alice.unwrap), List(), testId)
|
||||
clientMsg <- singleClientQueryStream(
|
||||
jwt,
|
||||
uri,
|
||||
@ -169,7 +170,7 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
).take(2)
|
||||
.runWith(collectResultsAsTextMessage)
|
||||
} yield inside(clientMsg) { case result +: heartbeats =>
|
||||
result should include(""""issuer":"Alice"""")
|
||||
result should include(s""""issuer":"$alice"""")
|
||||
result should include(""""amount":"999.99"""")
|
||||
Inspectors.forAll(heartbeats)(assertHeartbeat)
|
||||
}
|
||||
@ -177,14 +178,16 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
|
||||
"fetch endpoint should publish transactions when command create is completed" in withHttpService {
|
||||
(uri, encoder, _, _) =>
|
||||
val (alice, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
for {
|
||||
_ <- initialAccountCreate(uri, encoder)
|
||||
|
||||
_ <- initialAccountCreate(uri, encoder, alice, headers)
|
||||
jwt = jwtForParties(List(alice.unwrap), Nil, testId)
|
||||
fetchRequest = s"""[{"templateId": "Account:Account", "key": ["$alice", "abc123"]}]"""
|
||||
clientMsg <- singleClientFetchStream(jwt, uri, fetchRequest)
|
||||
.take(2)
|
||||
.runWith(collectResultsAsTextMessage)
|
||||
} yield inside(clientMsg) { case result +: heartbeats =>
|
||||
result should include(""""owner":"Alice"""")
|
||||
result should include(s""""owner":"$alice"""")
|
||||
result should include(""""number":"abc123"""")
|
||||
result should not include (""""offset":"""")
|
||||
Inspectors.forAll(heartbeats)(assertHeartbeat)
|
||||
@ -192,35 +195,37 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
}
|
||||
|
||||
"query endpoint should warn on unknown template IDs" in withHttpService { (uri, _, _, _) =>
|
||||
val (alice, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
for {
|
||||
_ <- initialIouCreate(uri)
|
||||
_ <- initialIouCreate(uri, alice, headers)
|
||||
|
||||
clientMsg <- singleClientQueryStream(
|
||||
jwt,
|
||||
jwtForParties(List(alice.unwrap), List(), testId),
|
||||
uri,
|
||||
"""{"templateIds": ["Iou:Iou", "Unknown:Template"]}""",
|
||||
).take(3)
|
||||
.runWith(collectResultsAsTextMessage)
|
||||
} yield inside(clientMsg) { case warning +: result +: heartbeats =>
|
||||
warning should include("\"warnings\":{\"unknownTemplateIds\":[\"Unk")
|
||||
result should include("\"issuer\":\"Alice\"")
|
||||
result should include(s""""issuer":"$alice"""")
|
||||
Inspectors.forAll(heartbeats)(assertHeartbeat)
|
||||
}
|
||||
}
|
||||
|
||||
"fetch endpoint should warn on unknown template IDs" in withHttpService { (uri, encoder, _, _) =>
|
||||
val (alice, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
for {
|
||||
_ <- initialAccountCreate(uri, encoder)
|
||||
_ <- initialAccountCreate(uri, encoder, alice, headers)
|
||||
|
||||
clientMsg <- singleClientFetchStream(
|
||||
jwt,
|
||||
jwtForParties(List(alice.unwrap), List(), testId),
|
||||
uri,
|
||||
"""[{"templateId": "Account:Account", "key": ["Alice", "abc123"]}, {"templateId": "Unknown:Template", "key": ["Alice", "abc123"]}]""",
|
||||
s"""[{"templateId": "Account:Account", "key": ["$alice", "abc123"]}, {"templateId": "Unknown:Template", "key": ["$alice", "abc123"]}]""",
|
||||
).take(3)
|
||||
.runWith(collectResultsAsTextMessage)
|
||||
} yield inside(clientMsg) { case warning +: result +: heartbeats =>
|
||||
warning should include("""{"warnings":{"unknownTemplateIds":["Unk""")
|
||||
result should include(""""owner":"Alice"""")
|
||||
result should include(s""""owner":"$alice"""")
|
||||
result should include(""""number":"abc123"""")
|
||||
Inspectors.forAll(heartbeats)(assertHeartbeat)
|
||||
}
|
||||
@ -267,7 +272,8 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
(uri, _, _, _) =>
|
||||
import spray.json._
|
||||
|
||||
val initialCreate = initialIouCreate(uri)
|
||||
val (party, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
val initialCreate = initialIouCreate(uri, party, headers)
|
||||
|
||||
val query =
|
||||
"""[
|
||||
@ -292,7 +298,7 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
postJsonRequest(
|
||||
uri.withPath(Uri.Path("/v1/exercise")),
|
||||
exercisePayload(domain.ContractId(ctid)),
|
||||
headersWithAuth,
|
||||
headers,
|
||||
) map { case (statusCode, _) =>
|
||||
statusCode.isSuccess shouldBe true
|
||||
}
|
||||
@ -348,6 +354,7 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
creation <- initialCreate
|
||||
_ = creation._1 shouldBe a[StatusCodes.Success]
|
||||
iouCid = getContractId(getResult(creation._2))
|
||||
jwt = jwtForParties(List(party.unwrap), List(), testId)
|
||||
(kill, source) = singleClientQueryStream(jwt, uri, query)
|
||||
.viaMat(KillSwitches.single)(Keep.right)
|
||||
.preMaterialize()
|
||||
@ -368,19 +375,21 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
(uri, encoder, _, _) =>
|
||||
import spray.json._
|
||||
|
||||
val (alice, aliceAuthHeaders) = getUniquePartyAndAuthHeaders("Alice")
|
||||
val (bob, bobAuthHeaders) = getUniquePartyAndAuthHeaders("Bob")
|
||||
val f1 =
|
||||
postCreateCommand(
|
||||
accountCreateCommand(domain.Party("Alice"), "abc123"),
|
||||
accountCreateCommand(alice, "abc123"),
|
||||
encoder,
|
||||
uri,
|
||||
headers = headersWithPartyAuth(List("Alice")),
|
||||
headers = aliceAuthHeaders,
|
||||
)
|
||||
val f2 =
|
||||
postCreateCommand(
|
||||
accountCreateCommand(domain.Party("Bob"), "def456"),
|
||||
accountCreateCommand(bob, "def456"),
|
||||
encoder,
|
||||
uri,
|
||||
headers = headersWithPartyAuth(List("Bob")),
|
||||
headers = bobAuthHeaders,
|
||||
)
|
||||
|
||||
val query =
|
||||
@ -402,33 +411,33 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
ContractDelta(Vector(), _, Some(liveStartOffset)) <- readOne
|
||||
_ <- liftF(
|
||||
postCreateCommand(
|
||||
accountCreateCommand(domain.Party("Alice"), "abc234"),
|
||||
accountCreateCommand(alice, "abc234"),
|
||||
encoder,
|
||||
uri,
|
||||
headers = headersWithPartyAuth(List("Alice")),
|
||||
headers = aliceAuthHeaders,
|
||||
)
|
||||
)
|
||||
ContractDelta(Vector((_, aliceAccount)), _, Some(_)) <- readOne
|
||||
_ = inside(aliceAccount) { case JsObject(obj) =>
|
||||
inside((obj get "owner", obj get "number")) {
|
||||
case (Some(JsString(owner)), Some(JsString(number))) =>
|
||||
owner shouldBe "Alice"
|
||||
owner shouldBe alice.unwrap
|
||||
number shouldBe "abc234"
|
||||
}
|
||||
}
|
||||
_ <- liftF(
|
||||
postCreateCommand(
|
||||
accountCreateCommand(domain.Party("Bob"), "def567"),
|
||||
accountCreateCommand(bob, "def567"),
|
||||
encoder,
|
||||
uri,
|
||||
headers = headersWithPartyAuth(List("Bob")),
|
||||
headers = bobAuthHeaders,
|
||||
)
|
||||
)
|
||||
ContractDelta(Vector((_, bobAccount)), _, Some(lastSeenOffset)) <- readOne
|
||||
_ = inside(bobAccount) { case JsObject(obj) =>
|
||||
inside((obj get "owner", obj get "number")) {
|
||||
case (Some(JsString(owner)), Some(JsString(number))) =>
|
||||
owner shouldBe "Bob"
|
||||
owner shouldBe bob.unwrap
|
||||
number shouldBe "def567"
|
||||
}
|
||||
}
|
||||
@ -456,7 +465,7 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
cid2 = getContractId(getResult(r2._2))
|
||||
|
||||
(kill, source) = singleClientQueryStream(
|
||||
jwtForParties(List("Alice", "Bob"), List(), testId),
|
||||
jwtForParties(List(alice.unwrap, bob.unwrap), List(), testId),
|
||||
uri,
|
||||
query,
|
||||
).viaMat(KillSwitches.single)(Keep.right).preMaterialize()
|
||||
@ -465,7 +474,12 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
lastSeen.unwrap should be > liveStart.unwrap
|
||||
liveStart
|
||||
}
|
||||
rescan <- (singleClientQueryStream(jwt, uri, query, Some(liveOffset))
|
||||
rescan <- (singleClientQueryStream(
|
||||
jwtForParties(List(alice.unwrap), List(), testId),
|
||||
uri,
|
||||
query,
|
||||
Some(liveOffset),
|
||||
)
|
||||
via parseResp).take(1) runWith remainingDeltas
|
||||
} yield inside(rescan) { case (Vector(_), _, Some(_)) =>
|
||||
succeed
|
||||
@ -474,20 +488,34 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
|
||||
"fetch should receive deltas as contracts are archived/created, filtering out phantom archives" in withHttpService {
|
||||
(uri, encoder, _, _) =>
|
||||
val (alice, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
val templateId = domain.TemplateId(None, "Account", "Account")
|
||||
def fetchRequest(contractIdAtOffset: Option[Option[domain.ContractId]] = None) = {
|
||||
import spray.json._, json.JsonProtocol._
|
||||
List(
|
||||
Map("templateId" -> "Account:Account".toJson, "key" -> List("Alice", "abc123").toJson)
|
||||
Map(
|
||||
"templateId" -> "Account:Account".toJson,
|
||||
"key" -> List(alice.unwrap, "abc123").toJson,
|
||||
)
|
||||
++ contractIdAtOffset
|
||||
.map(ocid => contractIdAtOffsetKey -> ocid.toJson)
|
||||
.toList
|
||||
).toJson.compactPrint
|
||||
}
|
||||
val f1 =
|
||||
postCreateCommand(accountCreateCommand(domain.Party("Alice"), "abc123"), encoder, uri)
|
||||
postCreateCommand(
|
||||
accountCreateCommand(alice, "abc123"),
|
||||
encoder,
|
||||
uri,
|
||||
headers,
|
||||
)
|
||||
val f2 =
|
||||
postCreateCommand(accountCreateCommand(domain.Party("Alice"), "def456"), encoder, uri)
|
||||
postCreateCommand(
|
||||
accountCreateCommand(alice, "def456"),
|
||||
encoder,
|
||||
uri,
|
||||
headers,
|
||||
)
|
||||
|
||||
def resp(
|
||||
cid1: domain.ContractId,
|
||||
@ -500,12 +528,13 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
for {
|
||||
ContractDelta(Vector((cid, c)), Vector(), None) <- readOne
|
||||
_ = (cid: String) shouldBe (cid1.unwrap: String)
|
||||
ctid <- liftF(postArchiveCommand(templateId, cid2, encoder, uri).flatMap {
|
||||
ctid <- liftF(postArchiveCommand(templateId, cid2, encoder, uri, headers).flatMap {
|
||||
case (statusCode, _) =>
|
||||
statusCode.isSuccess shouldBe true
|
||||
postArchiveCommand(templateId, cid1, encoder, uri).map { case (statusCode, _) =>
|
||||
statusCode.isSuccess shouldBe true
|
||||
cid
|
||||
postArchiveCommand(templateId, cid1, encoder, uri, headers).map {
|
||||
case (statusCode, _) =>
|
||||
statusCode.isSuccess shouldBe true
|
||||
cid
|
||||
}
|
||||
})
|
||||
|
||||
@ -541,7 +570,7 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
r2 <- f2
|
||||
_ = r2._1 shouldBe a[StatusCodes.Success]
|
||||
cid2 = getContractId(getResult(r2._2))
|
||||
|
||||
jwt = jwtForParties(List(alice.unwrap), List(), testId)
|
||||
(kill, source) = singleClientFetchStream(jwt, uri, fetchRequest())
|
||||
.viaMat(KillSwitches.single)(Keep.right)
|
||||
.preMaterialize()
|
||||
@ -576,16 +605,29 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
}
|
||||
|
||||
"fetch multiple keys should work" in withHttpService { (uri, encoder, _, _) =>
|
||||
val (alice, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
val jwt = jwtForParties(List(alice.unwrap), List(), testId)
|
||||
def create(account: String): Future[domain.ContractId] =
|
||||
for {
|
||||
r <- postCreateCommand(accountCreateCommand(domain.Party("Alice"), account), encoder, uri)
|
||||
r <- postCreateCommand(
|
||||
accountCreateCommand(alice, account),
|
||||
encoder,
|
||||
uri,
|
||||
headers,
|
||||
)
|
||||
} yield {
|
||||
assert(r._1.isSuccess)
|
||||
getContractId(getResult(r._2))
|
||||
}
|
||||
def archive(id: domain.ContractId): Future[Assertion] =
|
||||
for {
|
||||
r <- postArchiveCommand(domain.TemplateId(None, "Account", "Account"), id, encoder, uri)
|
||||
r <- postArchiveCommand(
|
||||
domain.TemplateId(None, "Account", "Account"),
|
||||
id,
|
||||
encoder,
|
||||
uri,
|
||||
headers,
|
||||
)
|
||||
} yield {
|
||||
assert(r._1.isSuccess)
|
||||
}
|
||||
@ -620,9 +662,9 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
)
|
||||
}
|
||||
val req =
|
||||
"""
|
||||
|[{"templateId": "Account:Account", "key": ["Alice", "abc123"]},
|
||||
| {"templateId": "Account:Account", "key": ["Alice", "def456"]}]
|
||||
s"""
|
||||
|[{"templateId": "Account:Account", "key": ["$alice", "abc123"]},
|
||||
| {"templateId": "Account:Account", "key": ["$alice", "def456"]}]
|
||||
|""".stripMargin
|
||||
|
||||
val (kill, source) = singleClientFetchStream(jwt, uri, req)
|
||||
@ -637,26 +679,28 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
import spray.json._
|
||||
|
||||
val templateId = domain.TemplateId(None, "Account", "Account")
|
||||
val (alice, aliceAuthHeaders) = getUniquePartyAndAuthHeaders("Alice")
|
||||
val (bob, bobAuthHeaders) = getUniquePartyAndAuthHeaders("Bob")
|
||||
|
||||
val f1 =
|
||||
postCreateCommand(
|
||||
accountCreateCommand(domain.Party("Alice"), "abc123"),
|
||||
accountCreateCommand(alice, "abc123"),
|
||||
encoder,
|
||||
uri,
|
||||
headers = headersWithPartyAuth(List("Alice")),
|
||||
headers = aliceAuthHeaders,
|
||||
)
|
||||
val f2 =
|
||||
postCreateCommand(
|
||||
accountCreateCommand(domain.Party("Bob"), "def456"),
|
||||
accountCreateCommand(bob, "def456"),
|
||||
encoder,
|
||||
uri,
|
||||
headers = headersWithPartyAuth(List("Bob")),
|
||||
headers = bobAuthHeaders,
|
||||
)
|
||||
|
||||
val query =
|
||||
"""[
|
||||
{"templateId": "Account:Account", "key": ["Alice", "abc123"]},
|
||||
{"templateId": "Account:Account", "key": ["Bob", "def456"]}
|
||||
s"""[
|
||||
{"templateId": "Account:Account", "key": ["$alice", "abc123"]},
|
||||
{"templateId": "Account:Account", "key": ["$bob", "def456"]}
|
||||
]"""
|
||||
|
||||
def resp(
|
||||
@ -671,7 +715,7 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
Vector((account1, _), (account2, _)) <- readAcsN(2)
|
||||
_ = Seq(account1, account2) should contain theSameElementsAs Seq(cid1, cid2)
|
||||
ContractDelta(Vector(), _, Some(liveStartOffset)) <- readOne
|
||||
_ <- liftF(postArchiveCommand(templateId, cid1, encoder, uri))
|
||||
_ <- liftF(postArchiveCommand(templateId, cid1, encoder, uri, aliceAuthHeaders))
|
||||
ContractDelta(Vector(), Vector(archivedCid1), Some(_)) <- readOne
|
||||
_ = archivedCid1.contractId shouldBe cid1
|
||||
_ <- liftF(
|
||||
@ -680,7 +724,7 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
cid2,
|
||||
encoder,
|
||||
uri,
|
||||
headers = headersWithPartyAuth(List("Bob")),
|
||||
headers = bobAuthHeaders,
|
||||
)
|
||||
)
|
||||
ContractDelta(Vector(), Vector(archivedCid2), Some(lastSeenOffset)) <- readOne
|
||||
@ -708,8 +752,9 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
_ = r2._1 shouldBe a[StatusCodes.Success]
|
||||
cid2 = getContractId(getResult(r2._2))
|
||||
|
||||
jwt = jwtForParties(List(alice.unwrap, bob.unwrap), List(), testId)
|
||||
(kill, source) = singleClientFetchStream(
|
||||
jwtForParties(List("Alice", "Bob"), List(), testId),
|
||||
jwt,
|
||||
uri,
|
||||
query,
|
||||
).viaMat(KillSwitches.single)(Keep.right).preMaterialize()
|
||||
@ -719,7 +764,7 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
liveStart
|
||||
}
|
||||
rescan <- (singleClientFetchStream(
|
||||
jwtForParties(List("Alice", "Bob"), List(), testId),
|
||||
jwt,
|
||||
uri,
|
||||
query,
|
||||
Some(liveOffset),
|
||||
@ -791,25 +836,29 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
|
||||
"query on a bunch of random splits should yield consistent results" in withHttpService {
|
||||
(uri, _, _, _) =>
|
||||
val (alice, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
val splitSample = SplitSeq.gen.map(_ map (BigDecimal(_))).sample.get
|
||||
val query =
|
||||
"""[
|
||||
{"templateIds": ["Iou:Iou"]}
|
||||
]"""
|
||||
val (kill, source) = singleClientQueryStream(jwt, uri, query)
|
||||
.viaMat(KillSwitches.single)(Keep.right)
|
||||
.preMaterialize()
|
||||
val (kill, source) =
|
||||
singleClientQueryStream(jwtForParties(List(alice.unwrap), List(), testId), uri, query)
|
||||
.viaMat(KillSwitches.single)(Keep.right)
|
||||
.preMaterialize()
|
||||
source
|
||||
.via(parseResp)
|
||||
.map(iouSplitResult)
|
||||
.filterNot(_ == \/-((Vector(), Vector()))) // liveness marker/heartbeat
|
||||
.runWith(Consume.interpret(trialSplitSeq(uri, splitSample, kill)))
|
||||
.runWith(Consume.interpret(trialSplitSeq(uri, splitSample, kill, alice.unwrap, headers)))
|
||||
}
|
||||
|
||||
private def trialSplitSeq(
|
||||
serviceUri: Uri,
|
||||
ss: SplitSeq[BigDecimal],
|
||||
kill: UniqueKillSwitch,
|
||||
partyName: String,
|
||||
headers: List[HttpHeader],
|
||||
): Consume.FCC[IouSplitResult, Assertion] = {
|
||||
val dslSyntax = Consume.syntax[IouSplitResult]
|
||||
import SplitSeq._
|
||||
@ -826,7 +875,7 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
postJsonRequest(
|
||||
serviceUri.withPath(Uri.Path("/v1/exercise")),
|
||||
exercisePayload(createdCid, l.x),
|
||||
headersWithAuth,
|
||||
headers,
|
||||
)
|
||||
)
|
||||
|
||||
@ -848,10 +897,10 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
"templateId" -> "Iou:Iou".toJson,
|
||||
"payload" -> Map(
|
||||
"observers" -> List[String]().toJson,
|
||||
"issuer" -> "Alice".toJson,
|
||||
"issuer" -> partyName.toJson,
|
||||
"amount" -> ss.x.toJson,
|
||||
"currency" -> "USD".toJson,
|
||||
"owner" -> "Alice".toJson,
|
||||
"owner" -> partyName.toJson,
|
||||
).toJson,
|
||||
).toJson
|
||||
}
|
||||
@ -860,7 +909,7 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
postJsonRequest(
|
||||
serviceUri.withPath(Uri.Path("/v1/create")),
|
||||
initialPayload,
|
||||
headersWithAuth,
|
||||
headers,
|
||||
)
|
||||
)
|
||||
\/-((Vector((genesisCid, amt)), Vector())) <- readOne
|
||||
@ -947,15 +996,17 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
val dslSyntax = Consume.syntax[JsValue]
|
||||
import dslSyntax._
|
||||
import spray.json._
|
||||
val (alice, headers) = getUniquePartyAndAuthHeaders("Alice")
|
||||
val jwt = jwtForParties(List(alice.unwrap), List(), testId)
|
||||
def createIouCommand(currency: String): String =
|
||||
s"""{
|
||||
| "templateId": "Iou:Iou",
|
||||
| "payload": {
|
||||
| "observers": [],
|
||||
| "issuer": "Alice",
|
||||
| "issuer": "$alice",
|
||||
| "amount": "999.99",
|
||||
| "currency": "$currency",
|
||||
| "owner": "Alice"
|
||||
| "owner": "$alice"
|
||||
| }
|
||||
|}""".stripMargin
|
||||
def createIou(currency: String): Future[Assertion] =
|
||||
@ -963,7 +1014,7 @@ abstract class AbstractWebsocketServiceIntegrationTest
|
||||
.postJsonStringRequest(
|
||||
uri.withPath(Uri.Path("/v1/create")),
|
||||
createIouCommand(currency),
|
||||
headersWithAuth,
|
||||
headers,
|
||||
)
|
||||
.map(_._1 shouldBe a[StatusCodes.Success])
|
||||
def contractsQuery(currency: String): String =
|
||||
|
Loading…
Reference in New Issue
Block a user