mirror of
https://github.com/digital-asset/daml.git
synced 2024-09-20 01:07:18 +03:00
Disallow empty command submission (#3270)
* Disallow empty command submission Fixes #592
This commit is contained in:
parent
819f8a8af5
commit
d9ae487fec
@ -41,7 +41,8 @@ final class CommandsValidator(ledgerId: LedgerId) {
|
|||||||
let <- requirePresence(commands.ledgerEffectiveTime, "ledger_effective_time")
|
let <- requirePresence(commands.ledgerEffectiveTime, "ledger_effective_time")
|
||||||
ledgerEffectiveTime = TimestampConversion.toInstant(let)
|
ledgerEffectiveTime = TimestampConversion.toInstant(let)
|
||||||
mrt <- requirePresence(commands.maximumRecordTime, "maximum_record_time")
|
mrt <- requirePresence(commands.maximumRecordTime, "maximum_record_time")
|
||||||
validatedCommands <- validateInnerCommands(commands.commands, submitter)
|
commandz <- requireNonEmpty(commands.commands, "commands")
|
||||||
|
validatedCommands <- validateInnerCommands(commandz, submitter)
|
||||||
ledgerEffectiveTimestamp <- Time.Timestamp
|
ledgerEffectiveTimestamp <- Time.Timestamp
|
||||||
.fromInstant(ledgerEffectiveTime)
|
.fromInstant(ledgerEffectiveTime)
|
||||||
.left
|
.left
|
||||||
|
@ -6,14 +6,14 @@ package com.digitalasset.ledger.api.validation
|
|||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
import com.digitalasset.api.util.TimestampConversion
|
import com.digitalasset.api.util.TimestampConversion
|
||||||
import com.digitalasset.daml.lf.command.{Commands => LfCommands}
|
import com.digitalasset.daml.lf.command.{Commands => LfCommands, CreateCommand => LfCreateCommand}
|
||||||
import com.digitalasset.daml.lf.data._
|
import com.digitalasset.daml.lf.data._
|
||||||
import com.digitalasset.daml.lf.value.Value.ValueRecord
|
import com.digitalasset.daml.lf.value.Value.ValueRecord
|
||||||
import com.digitalasset.daml.lf.value.{Value => Lf}
|
import com.digitalasset.daml.lf.value.{Value => Lf}
|
||||||
import com.digitalasset.ledger.api.DomainMocks
|
import com.digitalasset.ledger.api.DomainMocks
|
||||||
import com.digitalasset.ledger.api.DomainMocks.{applicationId, commandId, workflowId}
|
import com.digitalasset.ledger.api.DomainMocks.{applicationId, commandId, workflowId}
|
||||||
import com.digitalasset.ledger.api.domain.{LedgerId, Commands => ApiCommands}
|
import com.digitalasset.ledger.api.domain.{LedgerId, Commands => ApiCommands}
|
||||||
import com.digitalasset.ledger.api.v1.commands.Commands
|
import com.digitalasset.ledger.api.v1.commands.{Command, Commands, CreateCommand}
|
||||||
import com.digitalasset.ledger.api.v1.value.Value.Sum
|
import com.digitalasset.ledger.api.v1.value.Value.Sum
|
||||||
import com.digitalasset.ledger.api.v1.value.{
|
import com.digitalasset.ledger.api.v1.value.{
|
||||||
List => ApiList,
|
List => ApiList,
|
||||||
@ -45,6 +45,14 @@ class SubmitRequestValidatorTest
|
|||||||
val submitter = "party"
|
val submitter = "party"
|
||||||
val let = TimestampConversion.fromInstant(Instant.now)
|
val let = TimestampConversion.fromInstant(Instant.now)
|
||||||
val mrt = TimestampConversion.fromInstant(Instant.now)
|
val mrt = TimestampConversion.fromInstant(Instant.now)
|
||||||
|
val command =
|
||||||
|
Command(
|
||||||
|
Command.Command.Create(CreateCommand(
|
||||||
|
Some(Identifier("package", moduleName = "module", entityName = "entity")),
|
||||||
|
Some(Record(
|
||||||
|
Some(Identifier("package", moduleName = "module", entityName = "entity")),
|
||||||
|
Seq(RecordField("something", Some(Value(Value.Sum.Bool(true)))))))
|
||||||
|
)))
|
||||||
|
|
||||||
val commands = Commands(
|
val commands = Commands(
|
||||||
ledgerId.unwrap,
|
ledgerId.unwrap,
|
||||||
@ -54,7 +62,7 @@ class SubmitRequestValidatorTest
|
|||||||
submitter,
|
submitter,
|
||||||
Some(let),
|
Some(let),
|
||||||
Some(mrt),
|
Some(mrt),
|
||||||
Seq.empty
|
Seq(command)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +81,23 @@ class SubmitRequestValidatorTest
|
|||||||
mrt,
|
mrt,
|
||||||
LfCommands(
|
LfCommands(
|
||||||
DomainMocks.party,
|
DomainMocks.party,
|
||||||
ImmArray.empty,
|
ImmArray(
|
||||||
|
LfCreateCommand(
|
||||||
|
Ref.Identifier(
|
||||||
|
Ref.PackageId.assertFromString("package"),
|
||||||
|
Ref.QualifiedName(
|
||||||
|
Ref.ModuleName.assertFromString("module"),
|
||||||
|
Ref.DottedName.assertFromString("entity"))),
|
||||||
|
Lf.ValueRecord(
|
||||||
|
Option(
|
||||||
|
Ref.Identifier(
|
||||||
|
Ref.PackageId.assertFromString("package"),
|
||||||
|
Ref.QualifiedName(
|
||||||
|
Ref.ModuleName.assertFromString("module"),
|
||||||
|
Ref.DottedName.assertFromString("entity")))),
|
||||||
|
ImmArray((Option(Ref.Name.assertFromString("something")), Lf.ValueTrue))
|
||||||
|
)
|
||||||
|
)),
|
||||||
Time.Timestamp.assertFromInstant(let),
|
Time.Timestamp.assertFromInstant(let),
|
||||||
workflowId.unwrap
|
workflowId.unwrap
|
||||||
)
|
)
|
||||||
@ -89,8 +113,11 @@ class SubmitRequestValidatorTest
|
|||||||
|
|
||||||
"CommandSubmissionRequestValidator" when {
|
"CommandSubmissionRequestValidator" when {
|
||||||
"validating command submission requests" should {
|
"validating command submission requests" should {
|
||||||
"convert valid requests with empty commands" in {
|
"reject requests with empty commands" in {
|
||||||
commandsValidator.validateCommands(api.commands) shouldEqual Right(internal.emptyCommands)
|
requestMustFailWith(
|
||||||
|
commandsValidator.validateCommands(api.commands.withCommands(Seq.empty)),
|
||||||
|
INVALID_ARGUMENT,
|
||||||
|
"Missing field: commands")
|
||||||
}
|
}
|
||||||
|
|
||||||
"not allow missing ledgerId" in {
|
"not allow missing ledgerId" in {
|
||||||
|
@ -18,10 +18,10 @@ import com.digitalasset.ledger.api.v1.ledger_offset.LedgerOffset
|
|||||||
import com.digitalasset.ledger.api.v1.ledger_offset.LedgerOffset.LedgerBoundary.LEDGER_BEGIN
|
import com.digitalasset.ledger.api.v1.ledger_offset.LedgerOffset.LedgerBoundary.LEDGER_BEGIN
|
||||||
import com.digitalasset.ledger.api.v1.ledger_offset.LedgerOffset.Value.Boundary
|
import com.digitalasset.ledger.api.v1.ledger_offset.LedgerOffset.Value.Boundary
|
||||||
import com.digitalasset.ledger.api.v1.transaction_filter.{Filters, TransactionFilter}
|
import com.digitalasset.ledger.api.v1.transaction_filter.{Filters, TransactionFilter}
|
||||||
import com.digitalasset.ledger.api.v1.value.{Record, RecordField}
|
import com.digitalasset.ledger.api.v1.value.{Record, RecordField, Value}
|
||||||
import com.digitalasset.ledger.client.services.commands.{CommandClient, CompletionStreamElement}
|
import com.digitalasset.ledger.client.services.commands.{CommandClient, CompletionStreamElement}
|
||||||
import com.digitalasset.platform.apitesting.LedgerContextExtensions._
|
import com.digitalasset.platform.apitesting.LedgerContextExtensions._
|
||||||
import com.digitalasset.platform.apitesting.TestTemplateIds
|
import com.digitalasset.platform.apitesting.LedgerContext
|
||||||
import com.digitalasset.platform.esf.TestExecutionSequencerFactory
|
import com.digitalasset.platform.esf.TestExecutionSequencerFactory
|
||||||
import com.digitalasset.platform.participant.util.ValueConversions._
|
import com.digitalasset.platform.participant.util.ValueConversions._
|
||||||
import com.digitalasset.platform.tests.integration.ledger.api.ParameterShowcaseTesting
|
import com.digitalasset.platform.tests.integration.ledger.api.ParameterShowcaseTesting
|
||||||
@ -31,8 +31,8 @@ import io.grpc.{Status, StatusRuntimeException}
|
|||||||
import org.scalatest.time.Span
|
import org.scalatest.time.Span
|
||||||
import org.scalatest.time.SpanSugar._
|
import org.scalatest.time.SpanSugar._
|
||||||
import org.scalatest.{AsyncWordSpec, Matchers, Succeeded, TryValues}
|
import org.scalatest.{AsyncWordSpec, Matchers, Succeeded, TryValues}
|
||||||
|
|
||||||
import scalaz.syntax.tag._
|
import scalaz.syntax.tag._
|
||||||
|
|
||||||
import scala.concurrent.Future
|
import scala.concurrent.Future
|
||||||
import scala.concurrent.duration.FiniteDuration
|
import scala.concurrent.duration.FiniteDuration
|
||||||
import scala.util.Success
|
import scala.util.Success
|
||||||
@ -48,15 +48,22 @@ class CommandClientIT
|
|||||||
with TryValues
|
with TryValues
|
||||||
with MultiLedgerCommandUtils {
|
with MultiLedgerCommandUtils {
|
||||||
|
|
||||||
protected val testTemplateIds = new TestTemplateIds(config)
|
|
||||||
protected val templateIds = testTemplateIds.templateIds
|
|
||||||
|
|
||||||
private val submittingParty: String = submitRequest.getCommands.party
|
private val submittingParty: String = submitRequest.getCommands.party
|
||||||
private val submittingPartyList = List(submittingParty)
|
private val submittingPartyList = List(submittingParty)
|
||||||
private val LedgerBegin = LedgerOffset(Boundary(LEDGER_BEGIN))
|
private val LedgerBegin = LedgerOffset(Boundary(LEDGER_BEGIN))
|
||||||
|
|
||||||
private def submitRequestWithId(id: String): SubmitRequest =
|
private def submitRequestWithId(id: String, ctx: LedgerContext): SubmitRequest =
|
||||||
submitRequest.copy(commands = submitRequest.commands.map(_.copy(commandId = id)))
|
ctx.command(
|
||||||
|
id,
|
||||||
|
submittingParty,
|
||||||
|
List(
|
||||||
|
CreateCommand(
|
||||||
|
Some(templateIds.dummy),
|
||||||
|
Some(
|
||||||
|
Record(
|
||||||
|
Some(templateIds.dummy),
|
||||||
|
Seq(RecordField("operator", Option(Value(Value.Sum.Party(submittingParty)))))))).wrap)
|
||||||
|
)
|
||||||
|
|
||||||
// Commands and completions can be read out of order. Since we use GRPC monocalls to send,
|
// Commands and completions can be read out of order. Since we use GRPC monocalls to send,
|
||||||
// they can even be sent out of order.
|
// they can even be sent out of order.
|
||||||
@ -119,7 +126,7 @@ class CommandClientIT
|
|||||||
|
|
||||||
for {
|
for {
|
||||||
client <- ctx.commandClient()
|
client <- ctx.commandClient()
|
||||||
result <- Source(contexts.map(i => Ctx(i, submitRequestWithId(i.toString))))
|
result <- Source(contexts.map(i => Ctx(i, submitRequestWithId(i.toString, ctx))))
|
||||||
.via(client.submissionFlow)
|
.via(client.submissionFlow)
|
||||||
.map(_.map(_.isSuccess))
|
.map(_.map(_.isSuccess))
|
||||||
.runWith(Sink.seq)
|
.runWith(Sink.seq)
|
||||||
@ -130,9 +137,10 @@ class CommandClientIT
|
|||||||
|
|
||||||
"fail with the expected status on a ledger Id mismatch" in allFixtures { ctx =>
|
"fail with the expected status on a ledger Id mismatch" in allFixtures { ctx =>
|
||||||
Source
|
Source
|
||||||
.single(Ctx(
|
.single(
|
||||||
1,
|
Ctx(
|
||||||
submitRequestWithId(1.toString).update(_.commands.ledgerId := testNotLedgerId.unwrap)))
|
1,
|
||||||
|
submitRequestWithId("1", ctx).update(_.commands.ledgerId := testNotLedgerId.unwrap)))
|
||||||
.via(ctx.commandClientWithoutTime(testNotLedgerId).submissionFlow)
|
.via(ctx.commandClientWithoutTime(testNotLedgerId).submissionFlow)
|
||||||
.runWith(Sink.head)
|
.runWith(Sink.head)
|
||||||
.map(err => IsStatusException(Status.NOT_FOUND)(err.value.failure.exception))
|
.map(err => IsStatusException(Status.NOT_FOUND)(err.value.failure.exception))
|
||||||
@ -141,7 +149,7 @@ class CommandClientIT
|
|||||||
"fail with INVALID REQUEST for empty application ids" in allFixtures { ctx =>
|
"fail with INVALID REQUEST for empty application ids" in allFixtures { ctx =>
|
||||||
val resF = for {
|
val resF = for {
|
||||||
client <- ctx.commandClient(applicationId = "")
|
client <- ctx.commandClient(applicationId = "")
|
||||||
request = submitRequestWithId(7000.toString).update(_.commands.applicationId := "")
|
request = submitRequestWithId("7000", ctx).update(_.commands.applicationId := "")
|
||||||
res <- client.submitSingleCommand(request)
|
res <- client.submitSingleCommand(request)
|
||||||
} yield (res)
|
} yield (res)
|
||||||
|
|
||||||
@ -192,7 +200,7 @@ class CommandClientIT
|
|||||||
client <- ctx.commandClient()
|
client <- ctx.commandClient()
|
||||||
checkpoint <- client.getCompletionEnd
|
checkpoint <- client.getCompletionEnd
|
||||||
submissionResults <- Source(
|
submissionResults <- Source(
|
||||||
commandIds.map(i => Ctx(i, submitRequestWithId(i.toString))))
|
commandIds.map(i => Ctx(i, submitRequestWithId(i.toString, ctx))))
|
||||||
.flatMapMerge(10, randomDelay)
|
.flatMapMerge(10, randomDelay)
|
||||||
.via(client.submissionFlow)
|
.via(client.submissionFlow)
|
||||||
.map(_.value)
|
.map(_.value)
|
||||||
@ -225,7 +233,7 @@ class CommandClientIT
|
|||||||
client <- ctx.commandClient()
|
client <- ctx.commandClient()
|
||||||
checkpoint <- client.getCompletionEnd
|
checkpoint <- client.getCompletionEnd
|
||||||
result = readExpectedCommandIds(client, checkpoint.getOffset, commandIdStrings)
|
result = readExpectedCommandIds(client, checkpoint.getOffset, commandIdStrings)
|
||||||
_ <- Source(commandIds.map(i => Ctx(i, submitRequestWithId(i.toString))))
|
_ <- Source(commandIds.map(i => Ctx(i, submitRequestWithId(i.toString, ctx))))
|
||||||
.flatMapMerge(10, randomDelay)
|
.flatMapMerge(10, randomDelay)
|
||||||
.via(client.submissionFlow)
|
.via(client.submissionFlow)
|
||||||
.map(_.context)
|
.map(_.context)
|
||||||
@ -252,7 +260,7 @@ class CommandClientIT
|
|||||||
for {
|
for {
|
||||||
client <- ctx.commandClient()
|
client <- ctx.commandClient()
|
||||||
tracker <- client.trackCommands[Int](submittingPartyList)
|
tracker <- client.trackCommands[Int](submittingPartyList)
|
||||||
result <- Source(contexts.map(i => Ctx(i, submitRequestWithId(i.toString))))
|
result <- Source(contexts.map(i => Ctx(i, submitRequestWithId(i.toString, ctx))))
|
||||||
.via(tracker)
|
.via(tracker)
|
||||||
.map(_.context)
|
.map(_.context)
|
||||||
.runWith(Sink.seq)
|
.runWith(Sink.seq)
|
||||||
@ -265,7 +273,7 @@ class CommandClientIT
|
|||||||
for {
|
for {
|
||||||
client <- ctx.commandClient()
|
client <- ctx.commandClient()
|
||||||
tracker <- client.trackCommands[Int](submittingPartyList)
|
tracker <- client.trackCommands[Int](submittingPartyList)
|
||||||
result <- Source.empty[Ctx[Int, SubmitRequest]].via(tracker).runWith(Sink.ignore)
|
_ <- Source.empty[Ctx[Int, SubmitRequest]].via(tracker).runWith(Sink.ignore)
|
||||||
} yield {
|
} yield {
|
||||||
succeed
|
succeed
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,9 @@ import scalaz.syntax.tag._
|
|||||||
import scala.concurrent.Future
|
import scala.concurrent.Future
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
import com.digitalasset.platform.apitesting.TestParties._
|
import com.digitalasset.platform.apitesting.TestParties._
|
||||||
|
import com.digitalasset.platform.participant.util.ValueConversions._
|
||||||
import com.digitalasset.platform.testing.SingleItemObserver
|
import com.digitalasset.platform.testing.SingleItemObserver
|
||||||
|
|
||||||
@SuppressWarnings(Array("org.wartremover.warts.Any"))
|
@SuppressWarnings(Array("org.wartremover.warts.Any"))
|
||||||
class CommandCompletionServiceIT
|
class CommandCompletionServiceIT
|
||||||
extends AsyncWordSpec
|
extends AsyncWordSpec
|
||||||
@ -75,7 +77,21 @@ class CommandCompletionServiceIT
|
|||||||
for {
|
for {
|
||||||
commandClient <- ctx.commandClient(ctx.ledgerId)
|
commandClient <- ctx.commandClient(ctx.ledgerId)
|
||||||
tracker <- commandClient.trackCommands[String](configuredParties)
|
tracker <- commandClient.trackCommands[String](configuredParties)
|
||||||
commands = configuredParties.map(p => Ctx(p, ctx.command(p, p, Nil)))
|
commands = configuredParties.map(
|
||||||
|
p =>
|
||||||
|
Ctx(
|
||||||
|
p,
|
||||||
|
ctx.command(
|
||||||
|
p,
|
||||||
|
p,
|
||||||
|
List(
|
||||||
|
ProtoCreateCommand(
|
||||||
|
Some(templateIds.dummy),
|
||||||
|
Some(Record(
|
||||||
|
Some(templateIds.dummy),
|
||||||
|
Seq(RecordField("operator", Option(Value(Value.Sum.Party(p)))))))).wrap)
|
||||||
|
)
|
||||||
|
))
|
||||||
result <- Source(commands).via(tracker).runWith(Sink.seq)
|
result <- Source(commands).via(tracker).runWith(Sink.seq)
|
||||||
} yield {
|
} yield {
|
||||||
val expected = configuredParties.map(p => (p, 0))
|
val expected = configuredParties.map(p => (p, 0))
|
||||||
@ -132,7 +148,17 @@ class CommandCompletionServiceIT
|
|||||||
startingOffset = startingOffsetResponse.getOffset
|
startingOffset = startingOffsetResponse.getOffset
|
||||||
commandClient <- ctx.commandClient(ctx.ledgerId)
|
commandClient <- ctx.commandClient(ctx.ledgerId)
|
||||||
commands = configuredParties
|
commands = configuredParties
|
||||||
.map(p => ctx.command(p, p, Nil))
|
.map(p =>
|
||||||
|
ctx.command(
|
||||||
|
p,
|
||||||
|
p,
|
||||||
|
List(
|
||||||
|
ProtoCreateCommand(
|
||||||
|
Some(templateIds.dummy),
|
||||||
|
Some(Record(
|
||||||
|
Some(templateIds.dummy),
|
||||||
|
Seq(RecordField("operator", Option(Value(Value.Sum.Party(p)))))))).wrap)
|
||||||
|
))
|
||||||
.zipWithIndex
|
.zipWithIndex
|
||||||
.map { case (req, i) => req.update(_.commands.commandId := s"command-id-$i") }
|
.map { case (req, i) => req.update(_.commands.commandId := s"command-id-$i") }
|
||||||
_ <- Future.sequence(
|
_ <- Future.sequence(
|
||||||
|
@ -12,7 +12,10 @@ import com.digitalasset.ledger.api.testing.utils.{
|
|||||||
MockMessages,
|
MockMessages,
|
||||||
SuiteResourceManagementAroundAll
|
SuiteResourceManagementAroundAll
|
||||||
}
|
}
|
||||||
import com.digitalasset.platform.apitesting.{LedgerContext, MultiLedgerFixture}
|
import com.digitalasset.ledger.api.v1.commands.CreateCommand
|
||||||
|
import com.digitalasset.ledger.api.v1.value.{Record, RecordField, Value}
|
||||||
|
import com.digitalasset.platform.apitesting.{LedgerContext, MultiLedgerFixture, TestTemplateIds}
|
||||||
|
import com.digitalasset.platform.participant.util.ValueConversions._
|
||||||
import com.digitalasset.platform.sandbox.config.SandboxConfig
|
import com.digitalasset.platform.sandbox.config.SandboxConfig
|
||||||
import com.google.protobuf.empty.Empty
|
import com.google.protobuf.empty.Empty
|
||||||
import io.grpc.Status
|
import io.grpc.Status
|
||||||
@ -32,19 +35,46 @@ class CommandServiceBackPressureIT
|
|||||||
with MultiLedgerFixture
|
with MultiLedgerFixture
|
||||||
with SuiteResourceManagementAroundAll {
|
with SuiteResourceManagementAroundAll {
|
||||||
|
|
||||||
|
private[this] val testTemplateIds = new TestTemplateIds(config)
|
||||||
|
private[this] val templateIds = testTemplateIds.templateIds
|
||||||
|
|
||||||
private def submitAndWaitRequest(ctx: LedgerContext, id: String = UUID.randomUUID().toString) =
|
private def submitAndWaitRequest(ctx: LedgerContext, id: String = UUID.randomUUID().toString) =
|
||||||
MockMessages.submitAndWaitRequest
|
MockMessages.submitAndWaitRequest
|
||||||
.update(
|
.update(
|
||||||
|
_.commands.commands := List(
|
||||||
|
CreateCommand(
|
||||||
|
Some(templateIds.dummy),
|
||||||
|
Some(
|
||||||
|
Record(
|
||||||
|
Some(templateIds.dummy),
|
||||||
|
Seq(
|
||||||
|
RecordField(
|
||||||
|
"operator",
|
||||||
|
Option(Value(
|
||||||
|
Value.Sum.Party(MockMessages.submitAndWaitRequest.commands.get.party)))))))
|
||||||
|
).wrap),
|
||||||
_.commands.ledgerId := ctx.ledgerId.unwrap,
|
_.commands.ledgerId := ctx.ledgerId.unwrap,
|
||||||
_.commands.commandId := id,
|
_.commands.commandId := id,
|
||||||
_.optionalTraceContext := None)
|
_.optionalTraceContext := None
|
||||||
|
)
|
||||||
|
|
||||||
private def submitRequest(ctx: LedgerContext, id: String = UUID.randomUUID().toString) =
|
private def submitRequest(ctx: LedgerContext, id: String = UUID.randomUUID().toString) =
|
||||||
MockMessages.submitRequest
|
MockMessages.submitRequest
|
||||||
.update(
|
.update(
|
||||||
|
_.commands.commands := List(
|
||||||
|
CreateCommand(
|
||||||
|
Some(templateIds.dummy),
|
||||||
|
Some(
|
||||||
|
Record(
|
||||||
|
Some(templateIds.dummy),
|
||||||
|
Seq(RecordField(
|
||||||
|
"operator",
|
||||||
|
Option(Value(Value.Sum.Party(MockMessages.submitRequest.commands.get.party)))))))
|
||||||
|
).wrap),
|
||||||
_.commands.ledgerId := ctx.ledgerId.unwrap,
|
_.commands.ledgerId := ctx.ledgerId.unwrap,
|
||||||
_.commands.commandId := id,
|
_.commands.commandId := id,
|
||||||
_.optionalTraceContext := None)
|
_.optionalTraceContext := None
|
||||||
|
)
|
||||||
|
|
||||||
"Commands Submission Service" when {
|
"Commands Submission Service" when {
|
||||||
"overloaded with commands" should {
|
"overloaded with commands" should {
|
||||||
|
@ -26,7 +26,7 @@ import com.digitalasset.ledger.api.v1.value.Value.Sum
|
|||||||
import com.digitalasset.ledger.api.v1.value.Value.Sum.Party
|
import com.digitalasset.ledger.api.v1.value.Value.Sum.Party
|
||||||
import com.digitalasset.ledger.api.v1.value.{Identifier, Record, RecordField, Value}
|
import com.digitalasset.ledger.api.v1.value.{Identifier, Record, RecordField, Value}
|
||||||
import com.digitalasset.ledger.client.services.commands.CommandClient
|
import com.digitalasset.ledger.client.services.commands.CommandClient
|
||||||
import com.digitalasset.platform.apitesting.{LedgerContext, TestTemplateIds}
|
import com.digitalasset.platform.apitesting.LedgerContext
|
||||||
import io.grpc.Status
|
import io.grpc.Status
|
||||||
import org.scalatest.concurrent.ScalaFutures
|
import org.scalatest.concurrent.ScalaFutures
|
||||||
import org.scalatest.time.Span
|
import org.scalatest.time.Span
|
||||||
@ -48,9 +48,6 @@ class CommandStaticTimeIT
|
|||||||
with SuiteResourceManagementAroundAll
|
with SuiteResourceManagementAroundAll
|
||||||
with OptionValues {
|
with OptionValues {
|
||||||
|
|
||||||
protected val testTemplateIds = new TestTemplateIds(config)
|
|
||||||
protected val templateIds = testTemplateIds.templateIds
|
|
||||||
|
|
||||||
override def timeLimit: Span = scaled(15.seconds)
|
override def timeLimit: Span = scaled(15.seconds)
|
||||||
|
|
||||||
private val tenDays: time.Duration = java.time.Duration.ofDays(10L)
|
private val tenDays: time.Duration = java.time.Duration.ofDays(10L)
|
||||||
|
@ -45,8 +45,6 @@ class FailingCommandsIT
|
|||||||
|
|
||||||
"fail with the expected status on a ledger Id mismatch via sync service (multiple reqs)" in allFixtures {
|
"fail with the expected status on a ledger Id mismatch via sync service (multiple reqs)" in allFixtures {
|
||||||
ctx =>
|
ctx =>
|
||||||
val contexts = 1 to 10
|
|
||||||
|
|
||||||
val cmd1 = SubmitAndWaitRequest(
|
val cmd1 = SubmitAndWaitRequest(
|
||||||
failingRequest.commands.map(
|
failingRequest.commands.map(
|
||||||
_.update(_.ledgerId := testNotLedgerId.unwrap, _.commandId := "sync ledgerId 1")))
|
_.update(_.ledgerId := testNotLedgerId.unwrap, _.commandId := "sync ledgerId 1")))
|
||||||
|
@ -8,13 +8,14 @@ import com.digitalasset.ledger.api.testing.utils.MockMessages
|
|||||||
import com.digitalasset.ledger.api.testing.utils.MockMessages.{applicationId, workflowId}
|
import com.digitalasset.ledger.api.testing.utils.MockMessages.{applicationId, workflowId}
|
||||||
import com.digitalasset.ledger.api.v1.command_service.SubmitAndWaitRequest
|
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.command_submission_service.SubmitRequest
|
||||||
import com.digitalasset.ledger.api.v1.commands.Commands
|
import com.digitalasset.ledger.api.v1.commands.{Commands, CreateCommand}
|
||||||
|
import com.digitalasset.ledger.api.v1.value.{Record, RecordField, Value}
|
||||||
import com.digitalasset.ledger.client.services.commands.SynchronousCommandClient
|
import com.digitalasset.ledger.client.services.commands.SynchronousCommandClient
|
||||||
import com.digitalasset.platform.apitesting.{LedgerContext, MultiLedgerFixture}
|
import com.digitalasset.platform.apitesting.{LedgerContext, MultiLedgerFixture, TestTemplateIds}
|
||||||
import com.digitalasset.platform.common.LedgerIdMode
|
import com.digitalasset.platform.common.LedgerIdMode
|
||||||
|
import com.digitalasset.platform.participant.util.ValueConversions._
|
||||||
import com.digitalasset.platform.tests.integration.ledger.api.TransactionServiceHelpers
|
import com.digitalasset.platform.tests.integration.ledger.api.TransactionServiceHelpers
|
||||||
import org.scalatest.AsyncTestSuite
|
import org.scalatest.AsyncTestSuite
|
||||||
|
|
||||||
import scalaz.syntax.tag._
|
import scalaz.syntax.tag._
|
||||||
|
|
||||||
@SuppressWarnings(
|
@SuppressWarnings(
|
||||||
@ -24,6 +25,9 @@ import scalaz.syntax.tag._
|
|||||||
trait MultiLedgerCommandUtils extends MultiLedgerFixture {
|
trait MultiLedgerCommandUtils extends MultiLedgerFixture {
|
||||||
self: AsyncTestSuite =>
|
self: AsyncTestSuite =>
|
||||||
|
|
||||||
|
protected val testTemplateIds = new TestTemplateIds(config)
|
||||||
|
protected val templateIds = testTemplateIds.templateIds
|
||||||
|
|
||||||
protected final def newSynchronousCommandClient(ctx: LedgerContext): SynchronousCommandClient =
|
protected final def newSynchronousCommandClient(ctx: LedgerContext): SynchronousCommandClient =
|
||||||
new SynchronousCommandClient(ctx.commandService)
|
new SynchronousCommandClient(ctx.commandService)
|
||||||
|
|
||||||
@ -32,7 +36,20 @@ trait MultiLedgerCommandUtils extends MultiLedgerFixture {
|
|||||||
protected val testLedgerId = domain.LedgerId("ledgerId")
|
protected val testLedgerId = domain.LedgerId("ledgerId")
|
||||||
protected val testNotLedgerId = domain.LedgerId("hotdog")
|
protected val testNotLedgerId = domain.LedgerId("hotdog")
|
||||||
protected val submitRequest: SubmitRequest =
|
protected val submitRequest: SubmitRequest =
|
||||||
MockMessages.submitRequest.update(_.commands.ledgerId := testLedgerId.unwrap)
|
MockMessages.submitRequest.update(
|
||||||
|
_.commands.ledgerId := testLedgerId.unwrap,
|
||||||
|
_.commands.commands := List(
|
||||||
|
CreateCommand(
|
||||||
|
Some(templateIds.dummy),
|
||||||
|
Some(
|
||||||
|
Record(
|
||||||
|
Some(templateIds.dummy),
|
||||||
|
Seq(RecordField(
|
||||||
|
"operator",
|
||||||
|
Option(
|
||||||
|
Value(Value.Sum.Party(MockMessages.submitAndWaitRequest.commands.get.party)))))))
|
||||||
|
).wrap)
|
||||||
|
)
|
||||||
|
|
||||||
protected val failingRequest: SubmitRequest =
|
protected val failingRequest: SubmitRequest =
|
||||||
submitRequest.copy(
|
submitRequest.copy(
|
||||||
|
@ -248,6 +248,20 @@ final class CommandService(session: LedgerSession) extends LedgerTestSuite(sessi
|
|||||||
assertGrpcError(failure, Status.Code.NOT_FOUND, s"Ledger ID '$invalidLedgerId' not found.")
|
assertGrpcError(failure, Status.Code.NOT_FOUND, s"Ledger ID '$invalidLedgerId' not found.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private[this] val disallowEmptyCommandSubmission = LedgerTest(
|
||||||
|
"CSDisallowEmptyTransactionsSubmission",
|
||||||
|
"The submission of an empty command should be rejected with INVALID_ARGUMENT"
|
||||||
|
) { context =>
|
||||||
|
for {
|
||||||
|
ledger <- context.participant()
|
||||||
|
party <- ledger.allocateParty()
|
||||||
|
emptyRequest <- ledger.submitRequest(party)
|
||||||
|
failure <- ledger.submit(emptyRequest).failed
|
||||||
|
} yield {
|
||||||
|
assertGrpcError(failure, Status.Code.INVALID_ARGUMENT, "Missing field: commands")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override val tests: Vector[LedgerTest] = Vector(
|
override val tests: Vector[LedgerTest] = Vector(
|
||||||
submitAndWaitTest,
|
submitAndWaitTest,
|
||||||
submitAndWaitForTransactionTest,
|
submitAndWaitForTransactionTest,
|
||||||
@ -260,6 +274,7 @@ final class CommandService(session: LedgerSession) extends LedgerTestSuite(sessi
|
|||||||
submitAndWaitWithInvalidLedgerIdTest,
|
submitAndWaitWithInvalidLedgerIdTest,
|
||||||
submitAndWaitForTransactionIdWithInvalidLedgerIdTest,
|
submitAndWaitForTransactionIdWithInvalidLedgerIdTest,
|
||||||
submitAndWaitForTransactionWithInvalidLedgerIdTest,
|
submitAndWaitForTransactionWithInvalidLedgerIdTest,
|
||||||
submitAndWaitForTransactionTreeWithInvalidLedgerIdTest
|
submitAndWaitForTransactionTreeWithInvalidLedgerIdTest,
|
||||||
|
disallowEmptyCommandSubmission
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -14,3 +14,4 @@ HEAD — ongoing
|
|||||||
commands if they are not already in flight.
|
commands if they are not already in flight.
|
||||||
- [Sandbox] Fixed a bug a database migration script for Sandbox on Postgres introduced in SDK 0.13.32. See `issue #3284 <https://github.com/digital-asset/daml/issues/3284>`__.
|
- [Sandbox] Fixed a bug a database migration script for Sandbox on Postgres introduced in SDK 0.13.32. See `issue #3284 <https://github.com/digital-asset/daml/issues/3284>`__.
|
||||||
- [DAML Integration Kit] Re-add :doc:`integration kit documentation </daml-integration-kit/index>` that got accidentally deleted.
|
- [DAML Integration Kit] Re-add :doc:`integration kit documentation </daml-integration-kit/index>` that got accidentally deleted.
|
||||||
|
- [Ledger API] Disallow empty commands. See `issue #592 <https://github.com/digital-asset/daml/issues/592>`__.
|
Loading…
Reference in New Issue
Block a user