@HapiTests would be stronger as a regression suite if they could be run in a completely deterministic mode.
A developer could then take a snapshot of records produced by, say, running all ScheduleService tests; do a refactor; and then verify no unintentional side effects of the change by repeating those tests and looking at the record running hash.
But there are several non-repeatable ingredients in the current @HapiTests:
They choose TransactionID valid start times based on wall clock time. (This is, of course, necessary when running against a SubProcessNetwork; but not for an EmbeddedNetwork.)
They always generate new cryptographic keys.
(Occasionally) They use additional concurrency not controlled by JUnit Jupiter execution modes.
Solution
1️⃣ Use synthetic time
[x] Switch EmbeddedNetwork to assign "consensus times" based on a synthetic clock.
[x] Inject the synthetic InstantSource to Hedera; provide to all ingest components via Dagger.
[x] Define an interface for HapiSpec operations to use when choosing TransactionID valid start times.
[x] Update the NetworkTargetingExtension to further customize HapiSpec to use time backed by the same synthetic clock advanced by EmbeddedNetwork when appropriate.
[x] Change HapiSpecSleep and HapiSpecWaitUntil behavior to simply "push forward" the global synthetic clock instead of actually sleeping in embedded mode.
2️⃣ Use well-known keys
[x] Add a KeyFactory variant that cycles through a few dozen primitive keys (i.e., plenty to avoid repetition within a single @HapiTest) instead of using key generators.
[x] Again use NetworkTargetingExtension to further customize HapiSpec to make this the default key generator when targeting an embedded network.
3️⃣ Switch inParallel to blocking order in embedded mode
[x] Unless some spec will actually lose its intended effect, switch inParallel() to submit all sub-operations on the main thread instead of using an executor in embedded mode.
4️⃣ Add a testRepeatable task that is analogous to testEmbedded but disables all JUnit Jupiter parallelism.
Problem
@HapiTest
s would be stronger as a regression suite if they could be run in a completely deterministic mode.A developer could then take a snapshot of records produced by, say, running all
ScheduleService
tests; do a refactor; and then verify no unintentional side effects of the change by repeating those tests and looking at the record running hash.But there are several non-repeatable ingredients in the current
@HapiTest
s:TransactionID
valid start times based on wall clock time. (This is, of course, necessary when running against aSubProcessNetwork
; but not for anEmbeddedNetwork
.)Solution
1️⃣ Use synthetic time
EmbeddedNetwork
to assign "consensus times" based on a synthetic clock.InstantSource
to Hedera; provide to all ingest components via Dagger.HapiSpec
operations to use when choosingTransactionID
valid start times.NetworkTargetingExtension
to further customizeHapiSpec
to use time backed by the same synthetic clock advanced byEmbeddedNetwork
when appropriate.HapiSpecSleep
andHapiSpecWaitUntil
behavior to simply "push forward" the global synthetic clock instead of actually sleeping in embedded mode.2️⃣ Use well-known keys
KeyFactory
variant that cycles through a few dozen primitive keys (i.e., plenty to avoid repetition within a single@HapiTest
) instead of using key generators.NetworkTargetingExtension
to further customizeHapiSpec
to make this the default key generator when targeting an embedded network.3️⃣ Switch
inParallel
to blocking order in embedded modeinParallel()
to submit all sub-operations on the main thread instead of using an executor in embedded mode.4️⃣ Add a
testRepeatable
task that is analogous totestEmbedded
but disables all JUnit Jupiter parallelism.Alternatives
No response