Documentation
¶
Overview ¶
Package testutil provides common test helper utilities for the Dingo project. It replaces ad-hoc time.Sleep patterns with deterministic synchronization helpers that make tests faster and more reliable.
Index ¶
- Constants
- func AllGoroutineStacks() string
- func BadgerBlobConfig() map[string]any
- func BuildBlockBytesFromComponents(t *testing.T, blockType uint, slot, blockNumber uint64, components ...[]byte) []byte
- func BuildConwayBlockBytesWithTx(t *testing.T, body map[uint]any, isValid bool) []byte
- func BuildDecodableConwayBlockBytes(t *testing.T, slot, blockNumber uint64) []byte
- func BuildDijkstraBlockBytesWithTx(t testing.TB, txBytes []byte) []byte
- func CheckUnixSocketPathLen(path string) error
- func CompleteShelleyGenesisJSON(t testing.TB, overrides map[string]any, protocolParamOverrides map[string]any) string
- func ConfigureBlockTracing(t testing.TB, cfg tracing.Config)
- func ConwayEmptyBodyHash(t testing.TB) lcommon.Blake2b256
- func ConwayEmptyBodySize(t testing.TB) uint64
- func ConwayShapeTxBytes(t testing.TB, body map[uint]any, isValid bool) []byte
- func DijkstraShapeMempoolTxBytes(t testing.TB, body map[uint]any) []byte
- func DijkstraShapeTxBytes(t testing.TB, body map[uint]any, isValid bool) []byte
- func DijkstraSubTransactionBytes(t testing.TB, extra map[uint]any) []byte
- func ExtendConwayHeaderBody(t *testing.T, standardRaw []byte, extraFields ...cbor.RawMessage) []byte
- func ExtendConwayHeaderWithLeios(t *testing.T, standardRaw []byte) []byte
- func FreePort(t *testing.T) string
- func GenerateTestTLSCertKey(t *testing.T) (certPath, keyPath string)
- func GoroutineParkedIn(frames ...string) bool
- func InsecureHTTPClient() *http.Client
- func InstallUnsampledTracing(tb testing.TB)
- func MakeDirectoryUnwritable(t testing.TB, path string)
- func OwnerOnlyTempDir(t testing.TB) string
- func ParameterChangeTxCbor(t testing.TB, ppu map[uint]any, anchorURL string) []byte
- func RecordSpans(t *testing.T) *tracetest.SpanRecorder
- func RequireNever(t testing.TB, condition func() bool, waitFor time.Duration, tick time.Duration, ...)
- func RequireNoReceive[T any](t *testing.T, ch <-chan T, duration time.Duration, msg string)
- func RequireReceive[T any](t *testing.T, ch <-chan T, timeout time.Duration, msg string) T
- func RestrictFileToCurrentUser(t testing.TB, path string)
- func ShapeHash(n int, fill byte) []byte
- func ShapeTxBody(extra map[uint]any) map[uint]any
- func SkipIfBlockProducerUnsupported(t testing.TB)
- func SkipUnderRace(t testing.TB, reason string)
- func UnixSocketPath(t testing.TB) string
- func WaitForCondition(t *testing.T, condition func() bool, timeout time.Duration, msg string)
- func WaitForConditionWithInterval(t *testing.T, condition func() bool, timeout time.Duration, ...)
- type BodyShapeCase
- type CompleteShelleyGenesisLoader
- type MockInput
- type ValidatedConwayBlock
- func BuildValidatedConwayBlockBytes(t *testing.T, seed [32]byte, nonceSeed byte, slotRangeStart uint64, ...) ValidatedConwayBlock
- func BuildValidatedConwayBlockBytesWithInvalidOpCert(t *testing.T, seed [32]byte, nonceSeed byte, slotRangeStart uint64, ...) ValidatedConwayBlock
- func BuildValidatedConwayBlockBytesWithTransaction(t *testing.T, seed [32]byte, nonceSeed byte, slotRangeStart uint64, ...) ValidatedConwayBlock
Constants ¶
const ( // TestBadgerValueLogFileSize and TestBadgerMemTableSize are the file // sizes a test's badger blob store should ask for, well below the // production defaults (1 GiB and 128 MiB). // // badger sizes both files up front when it opens an on-disk store: the // value log is truncated to ValueLogFileSize and the memtable WAL to // MemTableSize. On Linux and macOS those are sparse, so the space is // only charged as it is written and the production sizes cost a test // nothing. On Windows the space is really reserved the moment the // store opens -- and badger maps the value log at twice // ValueLogFileSize so the last entry always fits (badger/v4 // value.go:536), making that 2 GiB per store at the default rather // than 1 -- so enough concurrent stores fill a CI runner's disk. // badger then fails every open with "There is not enough space on the // disk" out of valueLog.open, and the affected t.TempDir cleanup fails // behind it because the mapping is still held. // // A test writes kilobytes to a few megabytes, so it asks for files it // can actually fill. Anything larger only reserves space. TestBadgerValueLogFileSize = 16 * 1024 * 1024 TestBadgerMemTableSize = 8 * 1024 * 1024 )
const ( PParamUpdateKeyMaxTxSize = 3 PParamUpdateKeyPoolDeposit = 6 PParamUpdateKeyNOpt = 8 PParamUpdateKeyAdaPerUtxoByte = 17 PParamUpdateKeyCostModels = 18 PParamUpdateKeyCollateralPercent = 23 PParamUpdateKeyGovActionDeposit = 30 PParamUpdateKeyDRepDeposit = 31 PParamUpdateKeyCommitteeTermLimit = 28 PParamUpdateKeyGovActionPeriod = 29 )
Protocol-parameter update keys from the Conway CDDL, shared by Dijkstra.
const AsyncWait = 2 * time.Minute
AsyncWait is the deadline a test should give a wait on asynchronous progress -- a goroutine the code under test started, a background manager reacting to an event, a commit draining its after-commit callbacks -- when the test has no way to observe that work other than polling for its result.
It is a failure deadline, not a delay. WaitForCondition and RequireReceive return the moment the condition holds, so a larger value costs a passing run nothing; it only changes how long a genuinely stuck test takes to report, and the per-package -timeout still backstops that.
The value is deliberately far above the time the work takes on an idle machine, because that time is not what the deadline has to cover. `go test` defaults -parallel to GOMAXPROCS, so on a large host dozens of race-instrumented tests run at once, each with its own SQLite database, and a wait that completes in milliseconds standalone takes tens of seconds under that load. Slow single-core runners produce the same effect for the opposite reason.
Use one value rather than a per-site guess: a spread of 1s/2s/5s deadlines across a package encodes no information about the work being waited on, and the short end of the spread is where the flakes are.
const BindAttempts = 8
BindAttempts bounds how many ports a test tries before giving up when racing another process for a loopback port (see FreePort). Shared by every built-in API provider's TLS test suite (Blockfrost, Kupo, Mesh, UTxO RPC).
const MaxPortableUnixSocketPathLen = 103
MaxPortableUnixSocketPathLen is the longest Unix-domain socket path that binds on every platform this project's tests run on.
The address a bind() takes is a fixed-size struct, not a pointer, so the path has to fit in its sun_path field with room for a NUL terminator. That field is 104 bytes on Darwin and 108 on Linux and on Windows (UNIX_PATH_MAX in afunix.h), so 103 is the portable budget. Over it, the bind fails immediately with EINVAL -- surfaced by Go as "bind: invalid argument" -- which reads like a permissions or support problem rather than a length one.
t.TempDir() is what makes this easy to hit by accident: it derives a directory name from the test's own name and appends a numbered subdirectory, so a descriptive test name silently costs 60 or more bytes on top of a temp root that is already 49 bytes on Darwin (/var/folders/<2>/<30>/T/) and 36 on a Windows runner, against 5 for Linux's /tmp. That is why a socket test can pass on Linux and fail on nothing else.
Variables ¶
This section is empty.
Functions ¶
func AllGoroutineStacks ¶ added in v0.77.0
func AllGoroutineStacks() string
AllGoroutineStacks returns the runtime's complete dump of every goroutine stack.
runtime.Stack silently truncates to the buffer it is given, so a fixed-size buffer makes a stack-scanning assertion depend on how many goroutines happen to be alive. A test that passes under -run and fails in a full parallel package run is the usual symptom: the frame the condition looks for is past the cut. Sizing the buffer by hand only moves the threshold, so this grows until runtime.Stack reports it wrote less than the buffer holds, which is how it signals a complete dump.
func BadgerBlobConfig ¶ added in v0.70.8
BadgerBlobConfig returns the badger blob provider config a test should use, sized by TestBadgerValueLogFileSize and TestBadgerMemTableSize. Pass it as the provider config to plugin.Resolve wherever a test opens an on-disk badger store; dbtest.NewDatabase applies it for you.
func BuildBlockBytesFromComponents ¶ added in v0.74.1
func BuildBlockBytesFromComponents( t *testing.T, blockType uint, slot, blockNumber uint64, components ...[]byte, ) []byte
BuildBlockBytesFromComponents builds a Shelley-through-Conway block whose body components are the caller's exact CBOR items, with a header carrying the matching block body hash. The components are not re-encoded, so a test can place bytes that gouroboros' own encoders would never emit (an auxiliary-data entry at an index past the transaction list, a tagged map with an unknown field) and still get past the decoder's body-hash check.
components must be complete CBOR items in wire order: the array of transaction bodies, the array of witness sets, the index-to-auxiliary-data map, and, from Alonzo on, the array of invalid transaction indexes. The header carries the era's protocol major version but no valid VRF, KES or operational-certificate material, so the block only suits decode tests.
func BuildConwayBlockBytesWithTx ¶ added in v0.81.0
BuildConwayBlockBytesWithTx wraps one transaction body in a Conway block whose header carries the matching block body hash. The header has no valid VRF, KES or operational-certificate material, so the block only suits decode tests. When isValid is false the transaction is listed as invalid.
func BuildDecodableConwayBlockBytes ¶ added in v0.70.0
BuildDecodableConwayBlockBytes constructs a minimal, valid (10-field header), individually decodable Conway block with a correct block body hash and empty transaction components, for the given slot and block number. It is shared by tests across packages (database/models, ledger) that need a cheap, uniquely-identifiable, real Conway block rather than a hand-rolled mock.
func BuildDijkstraBlockBytesWithTx ¶ added in v0.81.0
BuildDijkstraBlockBytesWithTx wraps one Dijkstra block_transaction in a Dijkstra block whose header carries the matching block body hash.
func CheckUnixSocketPathLen ¶ added in v0.71.0
CheckUnixSocketPathLen reports whether path is short enough to bind on every supported platform. It is separate from UnixSocketPath so a test can prove the guard rejects an over-long path without needing a platform that would actually refuse to bind it.
func CompleteShelleyGenesisJSON ¶ added in v0.92.1
func CompleteShelleyGenesisJSON( t testing.TB, overrides map[string]any, protocolParamOverrides map[string]any, ) string
CompleteShelleyGenesisJSON returns a complete Shelley genesis document with the supplied top-level and protocol-parameter overrides.
func ConfigureBlockTracing ¶ added in v0.91.0
ConfigureBlockTracing enables block tracing with cfg, marks the node near the tip so every stage is traced, and disables it again when t ends.
func ConwayEmptyBodyHash ¶ added in v0.70.9
func ConwayEmptyBodyHash(t testing.TB) lcommon.Blake2b256
ConwayEmptyBodyHash returns the block body hash for a Conway block with empty transaction components (bodies, witness sets, metadata set, invalid transactions), which is independent of the header. Computed once via the same technique as BuildDecodableConwayBlockBytes (blake2b256 over the concatenation of the per-component blake2b256 hashes). Exported so callers building their own Conway headers with genuine crypto (e.g. a package-local competing-fork generator) share this computation instead of duplicating it, which would let the two drift apart.
func ConwayEmptyBodySize ¶ added in v0.89.0
ConwayEmptyBodySize returns the serialized size of the body components ConwayEmptyBodyHash commits to. A header's declared body size must equal it, or header validation rejects the block.
func ConwayShapeTxBytes ¶ added in v0.81.0
ConwayShapeTxBytes returns a Conway transaction carrying body, in the four-element form a mempool submission and a block both use.
func DijkstraShapeMempoolTxBytes ¶ added in v0.81.0
DijkstraShapeMempoolTxBytes returns a Dijkstra mempool_transaction carrying body, which has no is_valid flag.
func DijkstraShapeTxBytes ¶ added in v0.81.0
DijkstraShapeTxBytes returns a Dijkstra block_transaction carrying body.
func DijkstraSubTransactionBytes ¶ added in v0.81.0
DijkstraSubTransactionBytes returns a Dijkstra sub-transaction whose body carries extra keys. A sub-transaction body has no fee field.
func ExtendConwayHeaderBody ¶ added in v0.70.8
func ExtendConwayHeaderBody( t *testing.T, standardRaw []byte, extraFields ...cbor.RawMessage, ) []byte
ExtendConwayHeaderBody rewrites a standard (10-field header) Conway block so its header body carries extraFields appended after the 10 standard Babbage fields, for constructing malformed-extension fixtures (a field count other than the real 12-field Musashi/Leios extension) as well as the genuine extension itself.
func ExtendConwayHeaderWithLeios ¶ added in v0.70.8
ExtendConwayHeaderWithLeios rewrites a standard (10-field header) Conway block so its header body carries the two trailing Musashi/Leios fields (leios_certified = false, leios_announcement = nil), producing a 12-field header body. The transaction components (and therefore the block body hash) are left untouched.
func FreePort ¶ added in v0.70.0
FreePort draws a loopback port no other process is using and returns its address ("host:port"). The port is not guaranteed to still be free when the caller binds it -- retry up to BindAttempts times instead of treating one bind failure as a test failure.
The port comes from below the host's ephemeral range rather than from the kernel's port-0 assignment. Every process on the host draws ports from the ephemeral range for its outgoing connections and port-0 listeners, so a port from there can be taken the moment it is released: a test that stops a server and then rebinds or probes the same port would fail on another package's traffic rather than on its own code.
func GenerateTestTLSCertKey ¶ added in v0.70.0
GenerateTestTLSCertKey generates a throwaway self-signed certificate/key pair valid for 127.0.0.1 and writes them as PEM files under a fresh t.TempDir(), returning their paths. Used to exercise a listener's TLS startup path (Blockfrost, Kupo, Mesh, UTxORPC, Bark) without depending on any fixed certificate checked into the repo.
func GoroutineParkedIn ¶ added in v0.77.0
GoroutineParkedIn reports whether some goroutine's stack contains every one of frames. All frames must appear in the same goroutine's stack, so callers can pin both the parking primitive and the call path that reached it rather than matching either alone anywhere in the process.
func InsecureHTTPClient ¶ added in v0.70.0
InsecureHTTPClient returns an *http.Client that skips TLS certificate verification, for exercising a listener's throwaway self-signed test certificate (see GenerateTestTLSCertKey).
func InstallUnsampledTracing ¶ added in v0.91.0
InstallUnsampledTracing installs an SDK tracer provider that samples nothing and enables block tracing at a zero ratio, restoring both when tb ends. Benchmarks use it to measure the cost tracing adds to a path whose spans are all dropped.
func MakeDirectoryUnwritable ¶ added in v0.70.1
MakeDirectoryUnwritable removes write permission from a test directory and restores it before the test's temporary-directory cleanup runs.
Both modes are derived from what the directory already has rather than written literally, so restoring a fixed mode could hand the caller a more permissive directory than it passed in.
func OwnerOnlyTempDir ¶ added in v0.90.3
OwnerOnlyTempDir returns a test temporary directory with permissions that do not depend on the process umask.
func ParameterChangeTxCbor ¶ added in v0.82.0
ParameterChangeTxCbor returns transaction CBOR carrying one ParameterChange governance proposal whose update map is ppu. The transaction is otherwise minimal: it is meant for tests that assert how a proposal is judged, not for tests that need an otherwise valid transaction. The anchor URL is part of the transaction body, so distinct urls yield distinct transaction ids.
func RecordSpans ¶ added in v0.82.0
func RecordSpans(t *testing.T) *tracetest.SpanRecorder
RecordSpans installs a recording tracer provider as the process-wide OpenTelemetry provider for the rest of the test and returns the recorder. The provider is a process global, so a test that calls this must stay sequential.
func RequireNever ¶ added in v0.87.1
func RequireNever( t testing.TB, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...any, )
RequireNever fails t if condition returns true at any check made during waitFor, checking every tick. Unlike require.Never it runs condition on the calling goroutine, so no check is still running when it returns: testify starts each check on a goroutine of its own and returns at the deadline without waiting for the last one, which then races whatever the test does next. Use it for a condition that does more than read, such as one that takes a lock or a database transaction or receives from a channel.
func RequireNoReceive ¶
RequireNoReceive verifies that no value is received on the given channel within the specified duration. This replaces the pattern of time.Sleep followed by a non-blocking channel read to confirm that nothing was sent.
func RequireReceive ¶
RequireReceive waits for a value on the given channel or fails the test if the timeout expires. This replaces the common pattern of time.Sleep followed by reading a channel.
func RestrictFileToCurrentUser ¶ added in v0.70.0
RestrictFileToCurrentUser makes a test fixture acceptable to secret-key permission checks on Unix.
func ShapeTxBody ¶ added in v0.81.0
ShapeTxBody returns a minimal Conway or Dijkstra transaction body map with extra keys merged over it.
func SkipIfBlockProducerUnsupported ¶ added in v0.71.0
SkipIfBlockProducerUnsupported skips a test that exercises the block production path on a platform where Blink Labs does not support running a block producer.
This is a product boundary, not a technical one: Windows can open the AF_UNIX sockets the KES agent uses, and Go supports them there. Block production is simply not a supported configuration on Windows, and the KES agent exists only to serve a block producer, so none of it applies. Anyone changing this should change the product decision first, not the skip.
func SkipUnderRace ¶ added in v0.85.0
SkipUnderRace skips t when the binary is built with -race. Use it only for a test whose cost is single-goroutine computation or SQLite query planning, where the detector has nothing to observe and multiplies the runtime several times over. The same test must still run un-instrumented in CI's check job (and, for a service-backed package, gate (services)), and reason must say what that test covers, so a reader can tell the skip is not hiding a concurrency check.
func UnixSocketPath ¶ added in v0.71.0
UnixSocketPath returns a path for a Unix-domain socket inside a temporary directory that is removed when the test ends, and fails the test loudly if the result would be too long to bind on any supported platform.
It deliberately does not use t.TempDir(): that encodes the test name in the path, which is exactly what pushes these paths past sun_path on Darwin and Windows. The name here is a fixed short stem for the same reason -- a caller does not get to make it descriptive.
func WaitForCondition ¶
WaitForCondition polls the given condition function until it returns true or the timeout expires. This replaces the common pattern of time.Sleep followed by an assertion check.
Types ¶
type BodyShapeCase ¶ added in v0.81.0
BodyShapeCase is one transaction body whose Conway or Dijkstra wire shape is either legal (WantErr empty) or violates a body constraint, in which case WantErr is a substring of the error that names the violated constraint. Extra holds the body keys added to a minimal valid body.
func ConwayBodyShapeCases ¶ added in v0.81.0
func ConwayBodyShapeCases(t testing.TB) []BodyShapeCase
ConwayBodyShapeCases returns the Conway body shapes that CDDL, or a reference-implementation body constraint, rejects, each paired with the legal neighbour on either side of the boundary it crosses.
func DijkstraBodyShapeCases ¶ added in v0.81.0
func DijkstraBodyShapeCases(t testing.TB) []BodyShapeCase
DijkstraBodyShapeCases returns Dijkstra top-level bodies, and bodies nesting a sub-transaction, that differ only in the donation (body key 22) value.
type CompleteShelleyGenesisLoader ¶ added in v0.92.1
type CompleteShelleyGenesisLoader struct {
// contains filtered or unexported fields
}
CompleteShelleyGenesisLoader loads Shelley genesis overrides on top of the embedded preview fixture.
func CompleteShelleyGenesis ¶ added in v0.92.1
func CompleteShelleyGenesis( cfg *cardano.CardanoNodeConfig, ) CompleteShelleyGenesisLoader
CompleteShelleyGenesis returns a loader that lets tests supply only the genesis fields relevant to the behavior they exercise while still passing production genesis validation.
func (CompleteShelleyGenesisLoader) LoadShelleyGenesisFromReader ¶ added in v0.92.1
func (l CompleteShelleyGenesisLoader) LoadShelleyGenesisFromReader( overrides io.Reader, ) error
LoadShelleyGenesisFromReader merges overrides with the complete embedded fixture and loads the result into the configured node configuration.
type MockInput ¶ added in v0.37.0
MockInput is a reusable transaction input for database tests.
func NewMockInput ¶ added in v0.37.0
func (*MockInput) Id ¶ added in v0.37.0
func (m *MockInput) Id() lcommon.Blake2b256
func (*MockInput) ToPlutusData ¶ added in v0.37.0
func (m *MockInput) ToPlutusData() pdata.PlutusData
type ValidatedConwayBlock ¶ added in v0.70.1
type ValidatedConwayBlock struct {
Cbor []byte
Hash []byte
Slot uint64
BlockNumber uint64
EpochNonceHex string
SlotsPerKesPeriod uint64
}
ValidatedConwayBlock holds a genuinely VRF/KES-valid Conway block's raw CBOR alongside the parameters a caller needs to independently re-verify it (e.g. via gouroboros' ledger.VerifyBlock or pipeline.ValidateStage).
func BuildValidatedConwayBlockBytes ¶ added in v0.70.1
func BuildValidatedConwayBlockBytes( t *testing.T, seed [32]byte, nonceSeed byte, slotRangeStart uint64, blockNumber uint64, ) ValidatedConwayBlock
BuildValidatedConwayBlockBytes generates real VRF, KES, and cold keys, searches slots in [slotRangeStart, slotRangeStart+199] for one where the generated VRF key wins leadership (99% active slot coefficient, pool stake == total stake), and returns a genuinely decodable, VRF/KES-valid Conway block at that slot with an empty transaction body.
Unlike BuildDecodableConwayBlockBytes (which zeroes out the VRF/KES/OpCert fields for tests that only need a decodable block), this is for tests that need actual cryptographic validation -- gouroboros' pipeline.ValidateStage / ledger.VerifyBlock -- to genuinely pass, not merely decode. seed must be 32 bytes and should differ between blocks needing distinct producer keys; nonceSeed derives the epoch nonce the block is proven against (use the same nonceSeed for blocks meant to share an epoch).
func BuildValidatedConwayBlockBytesWithInvalidOpCert ¶ added in v0.70.1
func BuildValidatedConwayBlockBytesWithInvalidOpCert( t *testing.T, seed [32]byte, nonceSeed byte, slotRangeStart uint64, blockNumber uint64, ) ValidatedConwayBlock
BuildValidatedConwayBlockBytesWithInvalidOpCert generates a block whose VRF proof and KES signature are genuine but whose operational certificate was signed by an unrelated cold key. The KES signature is computed after substituting the unrelated signature, so rejecting this block specifically exercises the cold-key OpCert check rather than failing KES verification.
func BuildValidatedConwayBlockBytesWithTransaction ¶ added in v0.81.0
func BuildValidatedConwayBlockBytesWithTransaction( t *testing.T, seed [32]byte, nonceSeed byte, slotRangeStart uint64, blockNumber uint64, ) ValidatedConwayBlock
BuildValidatedConwayBlockBytesWithTransaction is BuildValidatedConwayBlockBytes with one minimal transaction in the body: a single input, no outputs, and an empty witness set. The header commits to that body's hash and size, so the block decodes and its VRF and KES verify. The transaction itself is not ledger-valid.