Port LedgerConfigurationServiceIT (#3188)

* Port LedgerConfigurationServiceIT

* Remove unused imports

* Fix compilation error

* Port SemanticLedgerTestsIT

* Expect failures for negative cases

* Add meaningful parentheses

* Do not require the ledger configuration test commands to succeed

* Remove unused command tracking

* Address https://github.com/digital-asset/daml/pull/3188#issuecomment-542616799

* Update unreleased.rst
This commit is contained in:
Stefano Baghino 2019-10-16 13:15:37 +02:00 committed by GitHub
parent 2bc6b8d4f5
commit 83e305b667
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 217 additions and 288 deletions

View File

@ -4,22 +4,18 @@
package com.digitalasset.platform.tests.integration.ledger.api
import akka.stream.scaladsl.Sink
import com.digitalasset.ledger.api.domain
import com.digitalasset.ledger.api.testing.utils.{
AkkaBeforeAndAfterAll,
IsStatusException,
SuiteResourceManagementAroundAll
}
import com.digitalasset.ledger.client.services.configuration.LedgerConfigurationClient
import com.digitalasset.platform.api.grpc.GrpcApiUtil
import com.digitalasset.platform.apitesting.{LedgerContext, MultiLedgerFixture}
import com.digitalasset.platform.esf.TestExecutionSequencerFactory
import io.grpc.Status
import org.scalatest.concurrent.AsyncTimeLimitedTests
import org.scalatest.time.Span
import org.scalatest.time.SpanSugar._
import org.scalatest.{AsyncWordSpec, Matchers, OptionValues}
import scalaz.syntax.tag._
@SuppressWarnings(Array("org.wartremover.warts.Any"))
class LedgerConfigurationServiceIT
@ -49,17 +45,6 @@ class LedgerConfigurationServiceIT
}
}
"fail with the expected status on a ledger Id mismatch" in allFixtures { context =>
new LedgerConfigurationClient(
domain.LedgerId("not" + context.ledgerId.unwrap),
context.ledgerConfigurationService).getLedgerConfiguration
.runWith(Sink.head)(materializer)
.failed map { ex =>
IsStatusException(Status.NOT_FOUND.getCode)(ex)
}
}
}
}

View File

@ -1,140 +0,0 @@
// Copyright (c) 2019 The DAML Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package com.digitalasset.platform.tests.integration.ledger.api
import java.util.concurrent.atomic.AtomicInteger
import akka.stream.scaladsl.Sink
import com.digitalasset.ledger.api.testing.utils.MockMessages.ledgerEffectiveTime
import com.digitalasset.ledger.api.testing.utils.{
AkkaBeforeAndAfterAll,
SuiteResourceManagementAroundAll
}
import com.digitalasset.ledger.api.v1.command_service.CommandServiceGrpc.CommandService
import com.digitalasset.ledger.api.v1.command_service.SubmitAndWaitRequest
import com.digitalasset.ledger.api.v1.command_submission_service.SubmitRequest
import com.digitalasset.ledger.client.services.commands.{CommandClient, SynchronousCommandClient}
import com.digitalasset.ledger.client.services.configuration.LedgerConfigurationClient
import com.digitalasset.platform.apitesting.{LedgerContext, MultiLedgerFixture}
import com.digitalasset.platform.esf.TestExecutionSequencerFactory
import com.digitalasset.platform.tests.integration.ledger.api.commands.MultiLedgerCommandUtils
import com.google.protobuf.empty.Empty
import io.grpc.{Status, StatusRuntimeException}
import org.scalatest.concurrent.AsyncTimeLimitedTests
import org.scalatest.time.Span
import org.scalatest.time.SpanSugar._
import org.scalatest.{AsyncWordSpec, Matchers, OptionValues}
import scalaz.syntax.tag._
import scalapb.lenses
import scalapb.lenses.Lens
class SemanticLedgerConfigurationIT
extends AsyncWordSpec
with AkkaBeforeAndAfterAll
with MultiLedgerFixture
with MultiLedgerCommandUtils
with SuiteResourceManagementAroundAll
with TestExecutionSequencerFactory
with AsyncTimeLimitedTests
with Matchers
with OptionValues {
override def timeLimit: Span = scaled(5.seconds)
private def configClient(ctx: LedgerContext): LedgerConfigurationClient =
new LedgerConfigurationClient(ctx.ledgerId, ctx.ledgerConfigurationService)
private def newSyncClient(commandService: CommandService) =
new SynchronousCommandClient(commandService)
private val newCommandId: () => String = {
val atomicInteger = new AtomicInteger()
() =>
atomicInteger.incrementAndGet().toString
}
private implicit class CommandClientOps(commandClient: CommandClient) {
def send(request: SubmitRequest) =
commandClient
.withTimeProvider(None)
.trackSingleCommand(request)
}
private def createRequest(
ctx: LedgerContext,
changes: Lens[SubmitAndWaitRequest, SubmitAndWaitRequest] => lenses.Mutation[
SubmitAndWaitRequest]): SubmitAndWaitRequest = {
submitAndWaitRequest.update(
_.commands.ledgerId := ctx.ledgerId.unwrap,
_.commands.commandId := newCommandId(),
changes
)
}
"a ledger" when {
"returning a minTTL in LedgerConfiguration" should {
"accept an MRT just minTTL greater than LET" in allFixtures { context =>
for {
config <- configClient(context).getLedgerConfiguration.runWith(Sink.head)(materializer)
syncClient = newSyncClient(context.commandService)
request = createRequest(
context,
_.commands.maximumRecordTime.seconds := (ledgerEffectiveTime.seconds + config.minTtl.value.seconds))
resp <- syncClient.submitAndWait(request)
} yield (resp should equal(Empty()))
}
"not accept an MRT less than minTTL greater than LET" in allFixtures { context =>
val resF = for {
config <- configClient(context).getLedgerConfiguration.runWith(Sink.head)(materializer)
syncClient = newSyncClient(context.commandService)
request = createRequest(
context,
_.commands.maximumRecordTime.seconds := ledgerEffectiveTime.seconds + config.minTtl.value.seconds - 1)
resp <- syncClient.submitAndWait(request)
} yield (resp)
resF.failed.map { failure =>
val exception = failure.asInstanceOf[StatusRuntimeException]
exception.getStatus.getCode should equal(Status.Code.INVALID_ARGUMENT)
}
}
}
"returning a maxTTL in LedgerConfiguration" should {
"accept an MRT exactly maxTTL greater than LET" in allFixtures { context =>
for {
config <- configClient(context).getLedgerConfiguration.runWith(Sink.head)(materializer)
syncClient = newSyncClient(context.commandService)
request = createRequest(
context,
_.commands.maximumRecordTime.seconds := ledgerEffectiveTime.seconds + config.maxTtl.value.seconds)
resp <- syncClient.submitAndWait(request)
} yield (resp should equal(Empty()))
}
"not accept an MRT more than maxTTL greater than LET" in allFixtures { context =>
val resF = for {
config <- configClient(context).getLedgerConfiguration.runWith(Sink.head)(materializer)
syncClient = newSyncClient(context.commandService)
request = createRequest(
context,
_.commands.maximumRecordTime.seconds := ledgerEffectiveTime.seconds + config.maxTtl.value.seconds + 1)
resp <- syncClient.submitAndWait(request)
} yield (resp)
resF.failed.map { failure =>
val exception = failure.asInstanceOf[StatusRuntimeException]
exception.getStatus.getCode should equal(Status.Code.INVALID_ARGUMENT)
}
}
}
}
}

View File

@ -11,6 +11,8 @@ import com.digitalasset.ledger.api.v1.admin.party_management_service.PartyManage
import com.digitalasset.ledger.api.v1.admin.party_management_service.PartyManagementServiceGrpc.PartyManagementService
import com.digitalasset.ledger.api.v1.command_service.CommandServiceGrpc
import com.digitalasset.ledger.api.v1.command_service.CommandServiceGrpc.CommandService
import com.digitalasset.ledger.api.v1.command_submission_service.CommandSubmissionServiceGrpc
import com.digitalasset.ledger.api.v1.command_submission_service.CommandSubmissionServiceGrpc.CommandSubmissionService
import com.digitalasset.ledger.api.v1.ledger_configuration_service.LedgerConfigurationServiceGrpc
import com.digitalasset.ledger.api.v1.ledger_configuration_service.LedgerConfigurationServiceGrpc.LedgerConfigurationService
import com.digitalasset.ledger.api.v1.ledger_identity_service.LedgerIdentityServiceGrpc
@ -26,6 +28,7 @@ import io.grpc.Channel
private[infrastructure] final class LedgerServices(channel: Channel) {
val activeContracts: ActiveContractsService = ActiveContractsServiceGrpc.stub(channel)
val command: CommandService = CommandServiceGrpc.stub(channel)
val commandSubmission: CommandSubmissionService = CommandSubmissionServiceGrpc.stub(channel)
val configuration: LedgerConfigurationService = LedgerConfigurationServiceGrpc.stub(channel)
val identity: LedgerIdentityService = LedgerIdentityServiceGrpc.stub(channel)
val partyManagement: PartyManagementService = PartyManagementServiceGrpc.stub(channel)

View File

@ -26,11 +26,13 @@ import com.digitalasset.ledger.api.v1.admin.party_management_service.{
GetParticipantIdRequest
}
import com.digitalasset.ledger.api.v1.command_service.SubmitAndWaitRequest
import com.digitalasset.ledger.api.v1.command_submission_service.SubmitRequest
import com.digitalasset.ledger.api.v1.commands.{Command, Commands}
import com.digitalasset.ledger.api.v1.event.Event.Event.Created
import com.digitalasset.ledger.api.v1.event.{CreatedEvent, Event}
import com.digitalasset.ledger.api.v1.ledger_configuration_service.{
GetLedgerConfigurationRequest,
GetLedgerConfigurationResponse,
LedgerConfiguration
}
import com.digitalasset.ledger.api.v1.ledger_offset.LedgerOffset
@ -437,6 +439,20 @@ private[testtool] final class ParticipantTestContext private[participant] (
.flatMap(submitAndWaitForTransaction)
.map(extractContracts)
def submitRequest(party: Party, commands: Command*): Future[SubmitRequest] =
time().map(
let =>
new SubmitRequest(
Some(new Commands(
ledgerId = ledgerId,
applicationId = applicationId,
commandId = nextCommandId(),
party = party.unwrap,
ledgerEffectiveTime = timestamp(let),
maximumRecordTime = timestamp(let.plusNanos(ttl.toNanos)),
commands = commands
))))
def submitAndWaitRequest(party: Party, commands: Command*): Future[SubmitAndWaitRequest] =
time().map(
let =>
@ -451,6 +467,9 @@ private[testtool] final class ParticipantTestContext private[participant] (
commands = commands
))))
def submit(request: SubmitRequest): Future[Unit] =
services.commandSubmission.submit(request).map(_ => ())
def submitAndWait(request: SubmitAndWaitRequest): Future[Unit] =
services.command.submitAndWait(request).map(_ => ())
@ -463,26 +482,13 @@ private[testtool] final class ParticipantTestContext private[participant] (
def submitAndWaitForTransactionTree(request: SubmitAndWaitRequest): Future[TransactionTree] =
services.command.submitAndWaitForTransactionTree(request).map(_.getTransaction)
private def configurations[Res](
request: GetLedgerConfigurationRequest,
service: (GetLedgerConfigurationRequest, StreamObserver[Res]) => Unit): Future[Option[Res]] =
SingleItemObserver.first[Res](service(request, _))
def configuration(overrideLedgerId: Option[String] = None): Future[LedgerConfiguration] =
SingleItemObserver
.first[GetLedgerConfigurationResponse](
services.configuration
.getLedgerConfiguration(
new GetLedgerConfigurationRequest(overrideLedgerId.getOrElse(ledgerId)),
_))
.map(_.fold(sys.error("No ledger configuration available."))(_.getLedgerConfiguration))
def latestConfiguration(): Future[LedgerConfiguration] =
configurations(
new GetLedgerConfigurationRequest(ledgerId),
services.configuration.getLedgerConfiguration)
.map(
_.flatMap(_.ledgerConfiguration).getOrElse(sys.error("No ledger configuration available.")))
def latestMaxTtl(): Future[java.time.Duration] =
latestConfiguration()
.map(
_.maxTtl
.map(
t =>
java.time.Duration
.ofSeconds(t.seconds)
.plus(java.time.Duration.ofNanos(t.nanos.toLong)))
.getOrElse(sys.error("Ledger configuration has no maxTtl duration.")))
}

View File

@ -199,9 +199,9 @@ final class CommandService(session: LedgerSession) extends LedgerTestSuite(sessi
for {
ledger <- context.participant()
alice <- ledger.allocateParty()
request <- ledger.submitAndWaitRequest(alice, Dummy(alice).create.command)
request <- ledger.submitRequest(alice, Dummy(alice).create.command)
badLedgerId = request.update(_.commands.ledgerId := invalidLedgerId)
failure <- ledger.submitAndWait(badLedgerId).failed
failure <- ledger.submit(badLedgerId).failed
} yield
assertGrpcError(failure, Status.Code.NOT_FOUND, s"Ledger ID '$invalidLedgerId' not found.")
}

View File

@ -1,109 +0,0 @@
// Copyright (c) 2019 The DAML Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package com.daml.ledger.api.testtool.tests
import java.time.{Duration, Instant}
import com.daml.ledger.api.testtool.infrastructure.{LedgerSession, LedgerTest, LedgerTestSuite}
import com.digitalasset.ledger.api.v1.command_service.SubmitAndWaitRequest
import com.digitalasset.ledger.test_stable.Test.Dummy
import com.google.protobuf.timestamp.Timestamp
import io.grpc.{Status, StatusException, StatusRuntimeException}
final class CommandSubmissionLet(session: LedgerSession) extends LedgerTestSuite(session) {
private[this] def timestamp(i: Instant): Timestamp =
new Timestamp(i.getEpochSecond, i.getNano)
private[this] def instant(t: Timestamp): Instant =
Instant.ofEpochSecond(t.seconds, t.nanos.toLong)
/** Moves all time values in the request (the LET and MRT) by the specified amount.
* This simulates a request from a client with a skewed clock. */
private[this] def moveRequestTime(
request: SubmitAndWaitRequest,
offset: java.time.Duration): SubmitAndWaitRequest =
request.copy(
commands = request.commands.map(command =>
command.copy(
ledgerEffectiveTime = command.ledgerEffectiveTime.map(let =>
timestamp(instant(let).plus(offset))),
maximumRecordTime = command.maximumRecordTime.map(mrt =>
timestamp(instant(mrt).plus(offset)))
)))
private val submitAndWaitAbortIfLetHigh =
LedgerTest("CSLAbortIfLetHigh", "SubmitAndWait returns ABORTED if LET is too high") { context =>
for {
ledger <- context.participant()
alice <- ledger.allocateParty()
maxTtl <- ledger.latestMaxTtl()
request <- ledger
.submitAndWaitRequest(alice, Dummy(alice).create.command)
.map(moveRequestTime(_, maxTtl.plus(Duration.ofSeconds(1L))))
submitFailure <- ledger.submitAndWait(request).failed
} yield {
assertGrpcError(submitFailure, Status.Code.ABORTED, "TRANSACTION_OUT_OF_TIME_WINDOW: ")
}
}
private val submitAndWaitSuccessIfLetRight =
LedgerTest(
"CSLSuccessIfLetRight",
"SubmitAndWait returns OK if LET is within the accepted interval") { context =>
// The maximum accepted clock skew depends on the ledger and is not exposed through the LedgerConfigurationService,
// and there might be an actual clock skew between the devices running the test and the ledger.
// This test therefore does not attempt to simulate any clock skew
// but simply checks whether basic command submission with an unmodified LET works.
val maxAcceptableSkew = Duration.ofMillis(0L)
for {
ledger <- context.participant()
alice <- ledger.allocateParty()
request <- ledger
.submitAndWaitRequest(alice, Dummy(alice).create.command)
.map(moveRequestTime(_, maxAcceptableSkew))
_ <- ledger.submitAndWait(request)
} yield {
// No assertions to make, since the command went through as expected
()
}
}
private val submitAndWaitAbortIfLetLow =
LedgerTest("CSLAbortIfLetLow", "SubmitAndWait returns ABORTED if LET is too low") { context =>
for {
ledger <- context.participant()
alice <- ledger.allocateParty()
maxTtl <- ledger.latestMaxTtl()
request <- ledger
.submitAndWaitRequest(alice, Dummy(alice).create.command)
.map(
moveRequestTime(
_,
Duration
.ofSeconds(0)
.minus(maxTtl)
.minus(Duration.ofSeconds(1L))))
submitFailure <- ledger.submitAndWait(request).failed
} yield {
// In this case, the ledger's response races with the client's timeout detection.
// So we can't be sure what the error message will be.
submitFailure match {
case _: StatusRuntimeException => ()
case _: StatusException => ()
case _ =>
assert(
false,
"submitAndWait did not fail with a StatusException or StatusRuntimeException")
}
}
}
override val tests: Vector[LedgerTest] = Vector(
submitAndWaitAbortIfLetHigh,
submitAndWaitSuccessIfLetRight,
submitAndWaitAbortIfLetLow
)
}

View File

@ -0,0 +1,183 @@
// Copyright (c) 2019 The DAML Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package com.daml.ledger.api.testtool.tests
import com.daml.ledger.api.testtool.infrastructure.{LedgerSession, LedgerTest, LedgerTestSuite}
import com.digitalasset.ledger.api.v1.ledger_configuration_service.LedgerConfiguration
import com.digitalasset.ledger.test_stable.Test.Dummy
import com.google.protobuf.duration.Duration
import com.google.protobuf.timestamp.Timestamp
import io.grpc.{Status, StatusException, StatusRuntimeException}
class LedgerConfigurationService(session: LedgerSession) extends LedgerTestSuite(session) {
private[this] val configSucceeds =
LedgerTest("ConfigSucceeds", "Return a valid configuration for a valid request") { context =>
for {
ledger <- context.participant()
config <- ledger.configuration()
} yield {
assert(config.minTtl.isDefined, "The minTTL field of the configuration is empty")
assert(config.maxTtl.isDefined, "The maxTTL field of the configuration is empty")
}
}
private[this] val configLedgerId =
LedgerTest("ConfigLedgerId", "Return NOT_FOUND to invalid ledger identifier") { context =>
val invalidLedgerId = "THIS_IS_AN_INVALID_LEDGER_ID"
for {
ledger <- context.participant()
failure <- ledger.configuration(overrideLedgerId = Some(invalidLedgerId)).failed
} yield {
assertGrpcError(failure, Status.Code.NOT_FOUND, s"Ledger ID '$invalidLedgerId' not found.")
}
}
private def sum(t: Timestamp, d: Duration): Timestamp =
t.withSeconds(t.seconds + d.seconds + ((t.nanos + d.nanos) / 1E9).toLong)
.withNanos(((t.nanos + d.nanos) % 1E9).toInt)
private def offset(t: Timestamp, s: Long): Timestamp =
Timestamp(t.seconds + s, t.nanos)
private[this] val configJustMinTtl =
LedgerTest("ConfigJustMinTtl", "LET+minTTL should be an acceptable MRT") { context =>
for {
ledger <- context.participant()
party <- ledger.allocateParty()
LedgerConfiguration(Some(minTtl), _) <- ledger.configuration()
request <- ledger.submitRequest(party, Dummy(party).create.command)
let = request.getCommands.getLedgerEffectiveTime
adjustedRequest = request.update(_.commands.maximumRecordTime := sum(let, minTtl))
_ <- ledger.submit(adjustedRequest)
} yield {
// Nothing to do, success is enough
}
}
private[this] val configUnderflowMinTtl =
LedgerTest("ConfigUnderflowMinTtl", "LET+minTTL-1 should NOT be an acceptable MRT") { context =>
for {
ledger <- context.participant()
party <- ledger.allocateParty()
LedgerConfiguration(Some(minTtl), _) <- ledger.configuration()
request <- ledger.submitRequest(party, Dummy(party).create.command)
let = request.getCommands.getLedgerEffectiveTime
adjustedRequest = request.update(
_.commands.maximumRecordTime := offset(sum(let, minTtl), -1))
failure <- ledger.submit(adjustedRequest).failed
} yield {
assertGrpcError(failure, Status.Code.INVALID_ARGUMENT, "out of bounds")
}
}
private[this] val configJustMaxTtl =
LedgerTest("ConfigJustMaxTtl", "LET+maxTTL should be an acceptable MRT") { context =>
for {
ledger <- context.participant()
party <- ledger.allocateParty()
LedgerConfiguration(_, Some(maxTtl)) <- ledger.configuration()
request <- ledger.submitRequest(party, Dummy(party).create.command)
let = request.getCommands.getLedgerEffectiveTime
adjustedRequest = request.update(_.commands.maximumRecordTime := sum(let, maxTtl))
_ <- ledger.submit(adjustedRequest)
} yield {
// Nothing to do, success is enough
}
}
private[this] val configOverflowMaxTtl =
LedgerTest("ConfigOverflowMaxTtl", "LET+maxTTL+1 should NOT be an acceptable MRT") { context =>
for {
ledger <- context.participant()
party <- ledger.allocateParty()
LedgerConfiguration(_, Some(maxTtl)) <- ledger.configuration()
request <- ledger.submitRequest(party, Dummy(party).create.command)
let = request.getCommands.getLedgerEffectiveTime
adjustedRequest = request.update(
_.commands.maximumRecordTime := offset(sum(let, maxTtl), 1))
failure <- ledger.submit(adjustedRequest).failed
} yield {
assertGrpcError(failure, Status.Code.INVALID_ARGUMENT, "out of bounds")
}
}
// Adds (maxTTL+1) seconds to a Timestamp
private def overflow(maxTtl: Duration)(t: Timestamp): Timestamp =
t.withSeconds(t.seconds + maxTtl.seconds + ((t.nanos + maxTtl.nanos) / 1E9).toLong + 1L)
.withNanos(((t.nanos + maxTtl.nanos) % 1E9).toInt)
// Subtracts (maxTTL+1) seconds from a Timestamp
private def underflow(maxTtl: Duration)(t: Timestamp): Timestamp =
t.withSeconds(t.seconds - maxTtl.seconds + ((t.nanos + maxTtl.nanos) / 1E9).toLong - 1L)
.withNanos(((t.nanos - maxTtl.nanos) % 1E9).toInt)
private[this] val submitSuccessIfLetRight =
LedgerTest(
"CSLSuccessIfLetRight",
"Submission returns OK if LET is within the accepted interval") { context =>
// The maximum accepted clock skew depends on the ledger and is not exposed through the LedgerConfigurationService,
// and there might be an actual clock skew between the devices running the test and the ledger.
// This test therefore does not attempt to simulate any clock skew
// but simply checks whether basic command submission with an unmodified LET works.
for {
ledger <- context.participant()
alice <- ledger.allocateParty()
request <- ledger.submitRequest(alice, Dummy(alice).create.command)
_ <- ledger.submit(request)
} yield {
// No assertions to make, since the command went through as expected
}
}
private[this] val submitAbortIfLetHigh =
LedgerTest("CSLAbortIfLetHigh", "Submission returns ABORTED if LET is too high") { context =>
for {
ledger <- context.participant()
alice <- ledger.allocateParty()
LedgerConfiguration(_, Some(maxTtl)) <- ledger.configuration()
request <- ledger.submitRequest(alice, Dummy(alice).create.command)
invalidRequest = request
.update(_.commands.ledgerEffectiveTime.modify(overflow(maxTtl)))
.update(_.commands.maximumRecordTime.modify(overflow(maxTtl)))
failure <- ledger.submit(invalidRequest).failed
} yield {
assertGrpcError(failure, Status.Code.ABORTED, "TRANSACTION_OUT_OF_TIME_WINDOW: ")
}
}
private[this] val submitAbortIfLetLow =
LedgerTest("CSLAbortIfLetLow", "Submission returns ABORTED if LET is too low") { context =>
for {
ledger <- context.participant()
alice <- ledger.allocateParty()
LedgerConfiguration(_, Some(maxTtl)) <- ledger.configuration()
request <- ledger.submitRequest(alice, Dummy(alice).create.command)
invalidRequest = request
.update(_.commands.ledgerEffectiveTime.modify(underflow(maxTtl)))
.update(_.commands.maximumRecordTime.modify(underflow(maxTtl)))
failure <- ledger.submit(invalidRequest).failed
} yield {
// In this case, the ledger's response races with the client's timeout detection.
// So we can't be sure what the error message will be.
failure match {
case _: StatusRuntimeException | _: StatusException => ()
case _ => fail("Submission should have failed with gRPC exception")
}
}
}
override val tests: Vector[LedgerTest] = Vector(
configSucceeds,
configLedgerId,
configJustMinTtl,
configUnderflowMinTtl,
configJustMaxTtl,
configOverflowMaxTtl,
submitSuccessIfLetRight,
submitAbortIfLetHigh,
submitAbortIfLetLow
)
}

View File

@ -33,7 +33,7 @@ package object tests {
"TransactionServiceIT" -> (new TransactionService(_)),
"WitnessesIT" -> (new Witnesses(_)),
"WronglyTypedContractIdIT" -> (new WronglyTypedContractId(_)),
"CommandSubmissionLetIT" -> (new CommandSubmissionLet(_))
"LedgerConfigurationServiceIT" -> (new LedgerConfigurationService(_))
)
val all = default ++ optional

View File

@ -8,3 +8,4 @@ This page contains release notes for the SDK.
HEAD — ongoing
--------------
- [DAML Ledger Integration Kit] Skew/LET/MRT/Config tests consolidated in a single suite.