mirror of
https://github.com/digital-asset/daml.git
synced 2024-11-10 10:46:11 +03:00
Add ledger API test tool tests for rollback projections (#9778)
* Add ledger API test tool tests for rollback projections This adds 3 tests for projections under rollback nodes. The first one is relatively clear hopefully and tests divulgence. The other two are a bit more intricate. For both of those we can also not test too much via the ledger API since we don’t actually get access to rollback nodes. However, it still seems useful to at least exercise those code paths and make sure they don’t do anything horribbly wrong. The second test tests the normalization rules from https://github.com/digital-asset/daml/blob/main/docs/source/concepts/ledger-model/ledger-exceptions.rst#privacy The last one tests a more complex structure with deeply nested rollback nodes and different informees. changelog_begin changelog_end * Update ledger/test-common/src/main/daml/semantic/Exceptions.daml Co-authored-by: Sofia Faro <sofia.faro@digitalasset.com> Co-authored-by: Sofia Faro <sofia.faro@digitalasset.com>
This commit is contained in:
parent
fb6f72c81d
commit
1b428be7d2
@ -8,7 +8,16 @@ import com.daml.ledger.api.testtool.infrastructure.Assertions._
|
||||
import com.daml.ledger.api.testtool.infrastructure.LedgerTestSuite
|
||||
import com.daml.ledger.api.testtool.infrastructure.TransactionHelpers._
|
||||
import com.daml.ledger.api.testtool.infrastructure.Synchronize.synchronize
|
||||
import com.daml.ledger.test.semantic.Exceptions.{Divulger, ExceptionTester, Fetcher, WithKey}
|
||||
import com.daml.ledger.test.semantic.Exceptions.{
|
||||
Divulger,
|
||||
ExceptionTester,
|
||||
Fetcher,
|
||||
WithSimpleKey,
|
||||
Informer,
|
||||
WithKey,
|
||||
WithKeyDelegate,
|
||||
RollbackNestingHelper,
|
||||
}
|
||||
import io.grpc.Status
|
||||
|
||||
final class ExceptionsIT extends LedgerTestSuite {
|
||||
@ -114,7 +123,7 @@ final class ExceptionsIT extends LedgerTestSuite {
|
||||
)(implicit ec => { case Participants(Participant(ledger, party)) =>
|
||||
for {
|
||||
t <- ledger.create(party, ExceptionTester(party))
|
||||
withKey <- ledger.create(party, WithKey(party))
|
||||
withKey <- ledger.create(party, WithSimpleKey(party))
|
||||
_ <- ledger.exercise(party, t.exerciseRolledbackArchiveConsuming(_, withKey))
|
||||
} yield ()
|
||||
})
|
||||
@ -126,7 +135,7 @@ final class ExceptionsIT extends LedgerTestSuite {
|
||||
)(implicit ec => { case Participants(Participant(ledger, party)) =>
|
||||
for {
|
||||
t <- ledger.create(party, ExceptionTester(party))
|
||||
withKey <- ledger.create(party, WithKey(party))
|
||||
withKey <- ledger.create(party, WithSimpleKey(party))
|
||||
_ <- ledger.exercise(party, t.exerciseRolledbackArchiveNonConsuming(_, withKey))
|
||||
} yield ()
|
||||
})
|
||||
@ -150,7 +159,7 @@ final class ExceptionsIT extends LedgerTestSuite {
|
||||
for {
|
||||
t <- ledger.create(party, ExceptionTester(party))
|
||||
_ <- ledger.exercise(party, t.exerciseDuplicateKey(_))
|
||||
_ <- ledger.create(party, WithKey(party))
|
||||
_ <- ledger.create(party, WithSimpleKey(party))
|
||||
failure <- ledger.exercise(party, t.exerciseDuplicateKey(_)).mustFail("duplicate key")
|
||||
} yield {
|
||||
assertGrpcError(failure, Status.Code.ABORTED, "DuplicateKey")
|
||||
@ -164,7 +173,7 @@ final class ExceptionsIT extends LedgerTestSuite {
|
||||
)(implicit ec => { case Participants(Participant(ledger, party)) =>
|
||||
for {
|
||||
t <- ledger.create(party, ExceptionTester(party))
|
||||
withKey <- ledger.create(party, WithKey(party))
|
||||
withKey <- ledger.create(party, WithSimpleKey(party))
|
||||
failure <- ledger.exercise(party, t.exerciseDuplicateKey(_)).mustFail("duplicate key")
|
||||
_ = assertGrpcError(failure, Status.Code.ABORTED, "DuplicateKey")
|
||||
_ <- ledger.exercise(party, withKey.exerciseArchive(_))
|
||||
@ -179,7 +188,7 @@ final class ExceptionsIT extends LedgerTestSuite {
|
||||
)(implicit ec => { case Participants(Participant(ledger, party)) =>
|
||||
for {
|
||||
t <- ledger.create(party, ExceptionTester(party))
|
||||
withKey <- ledger.create(party, WithKey(party))
|
||||
withKey <- ledger.create(party, WithSimpleKey(party))
|
||||
_ <- ledger.exercise(party, t.exerciseFetchKey(_))
|
||||
_ <- ledger.exercise(party, withKey.exerciseArchive(_))
|
||||
failure <- ledger.exercise(party, t.exerciseFetchKey(_)).mustFail("couldn't find key")
|
||||
@ -198,7 +207,7 @@ final class ExceptionsIT extends LedgerTestSuite {
|
||||
t <- ledger.create(party, ExceptionTester(party))
|
||||
failure <- ledger.exercise(party, t.exerciseFetchKey(_)).mustFail("contract not found")
|
||||
_ = assertGrpcError(failure, Status.Code.INVALID_ARGUMENT, "couldn't find key")
|
||||
_ <- ledger.create(party, WithKey(party))
|
||||
_ <- ledger.create(party, WithSimpleKey(party))
|
||||
_ <- ledger.exercise(party, t.exerciseFetchKey(_))
|
||||
} yield ()
|
||||
})
|
||||
@ -230,7 +239,7 @@ final class ExceptionsIT extends LedgerTestSuite {
|
||||
for {
|
||||
divulger <- aLedger.create(aParty, Divulger(aParty, bParty))
|
||||
fetcher <- bLedger.create(bParty, Fetcher(bParty, aParty))
|
||||
t <- bLedger.create(bParty, WithKey(bParty))
|
||||
t <- bLedger.create(bParty, WithSimpleKey(bParty))
|
||||
_ <- synchronize(aLedger, bLedger)
|
||||
fetchFailure <- aLedger
|
||||
.exercise(aParty, fetcher.exerciseFetch(_, t))
|
||||
@ -242,4 +251,96 @@ final class ExceptionsIT extends LedgerTestSuite {
|
||||
.exercise(aParty, fetcher.exerciseFetch(_, t))
|
||||
} yield ()
|
||||
})
|
||||
|
||||
test(
|
||||
"ExRollbackProjectionDivulgence",
|
||||
"Fetch and fetchbykey in projection divulge",
|
||||
allocate(SingleParty, SingleParty),
|
||||
)(implicit ec => {
|
||||
case Participants(Participant(aLedger, aParty), Participant(bLedger, bParty)) =>
|
||||
for {
|
||||
fetcher <- bLedger.create(aParty, Fetcher(aParty, bParty))
|
||||
withKey0 <- bLedger.create(aParty, WithKey(aParty, 0, List.empty))
|
||||
withKey1 <- bLedger.create(aParty, WithKey(aParty, 1, List.empty))
|
||||
_ <- synchronize(aLedger, bLedger)
|
||||
fetchFailure <- bLedger
|
||||
.exercise(bParty, fetcher.exerciseFetch_(_, withKey0))
|
||||
.mustFail("contract could not be found")
|
||||
_ = assertGrpcError(fetchFailure, Status.Code.ABORTED, "Contract could not be found")
|
||||
fetchFailure <- bLedger
|
||||
.exercise(bParty, fetcher.exerciseFetch_(_, withKey1))
|
||||
.mustFail("contract could not be found")
|
||||
_ = assertGrpcError(fetchFailure, Status.Code.ABORTED, "Contract could not be found")
|
||||
tester <- aLedger.create(aParty, ExceptionTester(aParty))
|
||||
_ <- aLedger.exercise(aParty, tester.exerciseProjectionDivulgence(_, bParty, withKey0))
|
||||
_ <- synchronize(aLedger, bLedger)
|
||||
_ <- bLedger
|
||||
.exercise(bParty, fetcher.exerciseFetch_(_, withKey0))
|
||||
_ <- bLedger
|
||||
.exercise(bParty, fetcher.exerciseFetch_(_, withKey1))
|
||||
} yield ()
|
||||
})
|
||||
|
||||
test(
|
||||
"ExRollbackProjectionNormalization",
|
||||
"Projection normalization is correctly applied",
|
||||
allocate(SingleParty, SingleParty, SingleParty),
|
||||
)(implicit ec => {
|
||||
// We cannot test projection & normalization directly via the ledger API
|
||||
// since rollback nodes are erased so this test only ensures
|
||||
// that the code paths for this are exercised and do not
|
||||
// throw errors.
|
||||
case Participants(
|
||||
Participant(aLedger, aParty),
|
||||
Participant(bLedger, bParty),
|
||||
Participant(cLedger, cParty),
|
||||
) =>
|
||||
for {
|
||||
abInformer <- aLedger.create(aParty, Informer(aParty, List(bParty)))
|
||||
acInformer <- aLedger.create(aParty, Informer(aParty, List(cParty)))
|
||||
abcInformer <- aLedger.create(aParty, Informer(aParty, List(bParty, cParty)))
|
||||
keyDelegate <- bLedger.create(bParty, WithKeyDelegate(aParty, bParty))
|
||||
_ <- synchronize(aLedger, bLedger)
|
||||
_ <- synchronize(aLedger, cLedger)
|
||||
tester <- aLedger.create(aParty, ExceptionTester(aParty))
|
||||
_ <- aLedger.exercise(
|
||||
aParty,
|
||||
tester.exerciseProjectionNormalization(
|
||||
_,
|
||||
bParty,
|
||||
keyDelegate,
|
||||
abInformer,
|
||||
acInformer,
|
||||
abcInformer,
|
||||
),
|
||||
)
|
||||
} yield ()
|
||||
})
|
||||
|
||||
test(
|
||||
"ExRollbackProjectionNesting",
|
||||
"Nested rollback nodes are handled properly",
|
||||
allocate(SingleParty, SingleParty, SingleParty),
|
||||
)(implicit ec => {
|
||||
// We cannot test projection & normalization directly via the ledger API
|
||||
// since rollback nodes are erased so this test only ensures
|
||||
// that the code paths for this are exercised and do not
|
||||
// throw errors.
|
||||
case Participants(
|
||||
Participant(aLedger, aParty),
|
||||
Participant(bLedger, bParty),
|
||||
Participant(cLedger, cParty),
|
||||
) =>
|
||||
for {
|
||||
keyDelegate <- bLedger.create(bParty, WithKeyDelegate(aParty, bParty))
|
||||
nestingHelper <- cLedger.create(cParty, RollbackNestingHelper(aParty, bParty, cParty))
|
||||
_ <- synchronize(aLedger, bLedger)
|
||||
_ <- synchronize(aLedger, cLedger)
|
||||
tester <- aLedger.create(aParty, ExceptionTester(aParty))
|
||||
_ <- aLedger.exercise(
|
||||
aParty,
|
||||
tester.exerciseProjectionNesting(_, bParty, keyDelegate, nestingHelper),
|
||||
)
|
||||
} yield ()
|
||||
})
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ module Exceptions where
|
||||
|
||||
#ifdef DAML_EXCEPTIONS
|
||||
|
||||
import DA.Assert
|
||||
import DA.Exception
|
||||
|
||||
exception E
|
||||
@ -20,7 +21,7 @@ exception E2
|
||||
where
|
||||
message t
|
||||
|
||||
template WithKey
|
||||
template WithSimpleKey
|
||||
with
|
||||
p : Party
|
||||
where
|
||||
@ -31,6 +32,22 @@ template WithKey
|
||||
controller p
|
||||
do pure ()
|
||||
|
||||
template WithKey
|
||||
with
|
||||
p : Party
|
||||
v : Int
|
||||
obs: [Party]
|
||||
where
|
||||
signatory p
|
||||
observer obs
|
||||
key (p, v) : (Party, Int)
|
||||
maintainer key._1
|
||||
choice Consume : ()
|
||||
with
|
||||
a : Party
|
||||
controller a
|
||||
do pure ()
|
||||
|
||||
template Divulger
|
||||
with
|
||||
sig : Party
|
||||
@ -40,7 +57,7 @@ template Divulger
|
||||
observer obs
|
||||
nonconsuming choice Divulge : ()
|
||||
with
|
||||
cid : ContractId WithKey
|
||||
cid : ContractId WithSimpleKey
|
||||
controller obs
|
||||
do try (fetch cid >> throw (E ""))
|
||||
catch
|
||||
@ -53,12 +70,82 @@ template Fetcher
|
||||
where
|
||||
signatory sig
|
||||
observer obs
|
||||
nonconsuming choice Fetch : WithKey
|
||||
nonconsuming choice Fetch : WithSimpleKey
|
||||
with
|
||||
cid : ContractId WithSimpleKey
|
||||
controller obs
|
||||
do fetch cid
|
||||
|
||||
nonconsuming choice Fetch_ : WithKey
|
||||
with
|
||||
cid : ContractId WithKey
|
||||
controller obs
|
||||
do fetch cid
|
||||
|
||||
template ProjectionDivulgenceHelper
|
||||
with
|
||||
a : Party
|
||||
b : Party
|
||||
where
|
||||
signatory a
|
||||
observer b
|
||||
choice DivulgeProjection : ()
|
||||
with
|
||||
cid : ContractId WithKey
|
||||
controller a
|
||||
do -- Both the fetch and the fetchByKey
|
||||
-- will be divulged to B.
|
||||
c <- fetch cid
|
||||
c.v === 0
|
||||
_ <- fetchByKey @WithKey (a, 1)
|
||||
throw (E "")
|
||||
|
||||
template RollbackNestingHelper
|
||||
with
|
||||
a : Party
|
||||
b : Party
|
||||
c : Party
|
||||
where
|
||||
signatory c
|
||||
observer a
|
||||
choice Rollback : ()
|
||||
controller a
|
||||
do try do
|
||||
create (WithSimpleKey a)
|
||||
try do
|
||||
exerciseByKey @WithKey (b, 1) (Consume a)
|
||||
throw (E "")
|
||||
catch
|
||||
E{} -> pure ()
|
||||
exerciseByKey @WithKey (b, 1) (Consume a)
|
||||
catch
|
||||
E{} -> pure ()
|
||||
|
||||
template WithKeyDelegate
|
||||
with
|
||||
a : Party
|
||||
b : Party
|
||||
where
|
||||
signatory b
|
||||
observer a
|
||||
nonconsuming choice CreateWithKey : ContractId WithKey
|
||||
with
|
||||
v : Int
|
||||
controller a
|
||||
do create (WithKey b v [a])
|
||||
|
||||
template Informer
|
||||
with
|
||||
a : Party
|
||||
obs : [Party]
|
||||
where
|
||||
signatory a
|
||||
observer obs
|
||||
nonconsuming choice Inform : ()
|
||||
observer obs
|
||||
controller a
|
||||
do pure ()
|
||||
|
||||
template ExceptionTester
|
||||
with
|
||||
p : Party
|
||||
@ -106,13 +193,13 @@ template ExceptionTester
|
||||
E _ -> pure ()
|
||||
nonconsuming choice DuplicateKey : ()
|
||||
controller p
|
||||
do try (create (WithKey p) >> throw (E ""))
|
||||
do try (create (WithSimpleKey p) >> throw (E ""))
|
||||
catch
|
||||
E _ -> pure ()
|
||||
|
||||
nonconsuming choice FetchKey : ()
|
||||
controller p
|
||||
do try (fetchByKey @WithKey p >> throw (E ""))
|
||||
do try (fetchByKey @WithSimpleKey p >> throw (E ""))
|
||||
catch
|
||||
E _ -> pure ()
|
||||
|
||||
@ -130,7 +217,7 @@ template ExceptionTester
|
||||
|
||||
nonconsuming choice RolledbackArchiveConsuming : ()
|
||||
with
|
||||
cid : ContractId WithKey
|
||||
cid : ContractId WithSimpleKey
|
||||
controller p
|
||||
do try (archive cid >> throw (E ""))
|
||||
catch
|
||||
@ -138,7 +225,7 @@ template ExceptionTester
|
||||
|
||||
nonconsuming choice RolledbackArchiveNonConsuming : ()
|
||||
with
|
||||
cid : ContractId WithKey
|
||||
cid : ContractId WithSimpleKey
|
||||
controller p
|
||||
do try (archive cid >> throw (E ""))
|
||||
catch
|
||||
@ -146,8 +233,98 @@ template ExceptionTester
|
||||
|
||||
nonconsuming choice RolledbackDuplicateKey : ()
|
||||
controller p
|
||||
do try (create (WithKey p) >> throw (E ""))
|
||||
do try (create (WithSimpleKey p) >> throw (E ""))
|
||||
catch
|
||||
E _ -> create (WithKey p) >> pure ()
|
||||
E _ -> create (WithSimpleKey p) >> pure ()
|
||||
|
||||
nonconsuming choice ProjectionDivulgence : ()
|
||||
with
|
||||
b : Party
|
||||
keyCid : ContractId WithKey
|
||||
controller p
|
||||
do -- b sees all 3 childs of this exercise but not the exercise itself.
|
||||
cid <- create (ProjectionDivulgenceHelper p b)
|
||||
try (exercise cid (DivulgeProjection keyCid))
|
||||
catch
|
||||
E{} -> pure ()
|
||||
archive cid
|
||||
|
||||
nonconsuming choice ProjectionNormalization : ()
|
||||
with
|
||||
b : Party
|
||||
keyDelegate : ContractId WithKeyDelegate
|
||||
pbInformer : ContractId Informer
|
||||
pcInformer : ContractId Informer
|
||||
pbcInformer : ContractId Informer
|
||||
controller p
|
||||
do -- Projection to B:
|
||||
-- Normalization rule #3 folds R3 into R1
|
||||
-- R2 and R3 must sit under R1 for key checks to pass
|
||||
-- Projection to C:
|
||||
-- Normalization rule #2 pulls R2 out of R1.
|
||||
-- Normalization rule #1 drops R3.
|
||||
|
||||
|
||||
try do -- R1
|
||||
exercise keyDelegate (CreateWithKey 1) -- informees: p b
|
||||
|
||||
try do -- R2
|
||||
exercise pbcInformer Inform -- informees: p b c
|
||||
exerciseByKey @WithKey (b, 1) (Consume p) -- informees: p b
|
||||
exercise keyDelegate (CreateWithKey 2) -- informees: p b
|
||||
throw (E "")
|
||||
catch
|
||||
E{} -> pure ()
|
||||
|
||||
exercise pbInformer Inform -- informees: p b
|
||||
|
||||
try do -- R3
|
||||
exerciseByKey @WithKey (b, 1) (Consume p) -- informees: p b
|
||||
exercise keyDelegate (CreateWithKey 2) -- informees: p b
|
||||
throw (E "")
|
||||
catch
|
||||
E{} -> pure()
|
||||
|
||||
exercise pcInformer Inform -- informees: p c
|
||||
throw (E "")
|
||||
|
||||
catch
|
||||
E{} -> pure ()
|
||||
|
||||
exercise keyDelegate (CreateWithKey 1)
|
||||
pure ()
|
||||
|
||||
nonconsuming choice ProjectionNesting : ()
|
||||
with
|
||||
b : Party
|
||||
keyDelegate : ContractId WithKeyDelegate
|
||||
cid : ContractId RollbackNestingHelper
|
||||
controller p
|
||||
do exercise keyDelegate (CreateWithKey 1)
|
||||
|
||||
exercise self (ProjectionNestingInner b cid)
|
||||
|
||||
exerciseByKey @WithKey (b, 1) (Consume p)
|
||||
pure ()
|
||||
|
||||
nonconsuming choice ProjectionNestingInner : ()
|
||||
with
|
||||
b : Party
|
||||
cid : ContractId RollbackNestingHelper
|
||||
controller p
|
||||
do try do
|
||||
_ <- create (Informer p [b])
|
||||
|
||||
try do
|
||||
exerciseByKey @WithKey (b, 1) (Consume p)
|
||||
throw (E "")
|
||||
catch
|
||||
E{} -> pure ()
|
||||
|
||||
exercise cid Rollback
|
||||
|
||||
throw (E "")
|
||||
|
||||
catch
|
||||
E{} -> pure ()
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user