Table of Contents

Class LockTableTesting

Namespace
DynaSharp.Coordination.Testing
Assembly
DynaSharp.Coordination.dll

What other processes do to a lock, for tests: hold it, release it, delete its item; and what a test looks at: the state of a lock, and a contender that was turned away.

public static class LockTableTesting
Inheritance
LockTableTesting
Inherited Members

Remarks

Through the table. They read and write the item of the lock through the table of the LockTable, as those processes would, so a test sets up and checks a situation without knowing the format of the item. They work on any table, a FakeDynamoDb or an emulator, and are not meant for a table in production: they write without a condition.

A takeover in a test. A contender takes a lock over only after it has seen the same holder for a whole lease on its own clock, so a test that wants a takeover holds the lock with SimulateHolderAsync(LockTable, string, TimeSpan, string?, CancellationToken), lets the LockTable see it, and then moves the fake clock of the client by the lease.

Methods

GetStateAsync(LockTable, string, CancellationToken)

Reads the item of a lock with a strongly consistent GetItem and says what it holds: whether a lease holds the lock, the holder label, the lease duration and the fencing token. A test asserts on this instead of on the attributes of the item.

public static Task<LockState?> GetStateAsync(this LockTable locks, string name, CancellationToken cancellationToken = default)

Parameters

locks LockTable

The lock table.

name string

The name of the lock.

cancellationToken CancellationToken

Cancels the request.

Returns

Task<LockState>

The state, or null if the lock has no item: never acquired, or deleted.

Exceptions

ArgumentNullException

locks is null.

ArgumentException

name is null or empty.

InvalidOperationException

The item at the key of the lock has an owner but is not a lock item written by LockTable.

SimulateDeleteAsync(LockTable, string, CancellationToken)

Deletes the item of the lock, as time to live or an operator would. A lease of this process on the lock is lost at its next renewal, as deleted, and the next acquire starts the fencing token at 1 again. A lock without an item stays without one.

public static Task SimulateDeleteAsync(this LockTable locks, string name, CancellationToken cancellationToken = default)

Parameters

locks LockTable

The lock table.

name string

The name of the lock.

cancellationToken CancellationToken

Cancels the request.

Returns

Task

A task that completes when the item is gone.

Exceptions

ArgumentNullException

locks is null.

ArgumentException

name is null or empty.

SimulateHolderAsync(LockTable, string, TimeSpan, string?, CancellationToken)

Makes another process hold the lock, as if it had just acquired it and then never renewed it, as a holder that crashed: a new owner and record version, the fencing token raised by one, the lease duration, and the label, if one is given. A lease of this process on the lock is lost at its next renewal, as taken_over, and a contender takes the lock over once it has seen this holder for a whole lease.

public static Task<long> SimulateHolderAsync(this LockTable locks, string name, TimeSpan leaseDuration, string? holderLabel = null, CancellationToken cancellationToken = default)

Parameters

locks LockTable

The lock table.

name string

The name of the lock.

leaseDuration TimeSpan

The lease of the other holder, from MinLeaseDuration to MaxLeaseDuration.

holderLabel string

The label of the other holder, as HolderLabel would write it, or null for none.

cancellationToken CancellationToken

Cancels the request.

Returns

Task<long>

The fencing token of the other holder.

Exceptions

ArgumentNullException

locks is null.

ArgumentException

name is null or empty.

ArgumentOutOfRangeException

leaseDuration is below MinLeaseDuration or above MaxLeaseDuration.

SimulateReleaseAsync(LockTable, string, CancellationToken)

Releases the lock as its holder would, whoever holds it: the owner, the lease and the label are removed, the fencing token stays. A lease of this process on the lock is lost at its next renewal, as taken_over, and the next acquire finds the lock free. A lock without an item gets a free one.

public static Task SimulateReleaseAsync(this LockTable locks, string name, CancellationToken cancellationToken = default)

Parameters

locks LockTable

The lock table.

name string

The name of the lock.

cancellationToken CancellationToken

Cancels the request.

Returns

Task

A task that completes when the lock is free.

Exceptions

ArgumentNullException

locks is null.

ArgumentException

name is null or empty.

WaitForRefusalAsync(LockTable, string, CancellationToken)

Waits until a try of this LockTable to acquire the lock finds it held by another lease and is turned away: a TryAcquireAsync that returns null, or a poll of AcquireAsync or RunAsLeaderAsync that waits on. A test sees that a contender tried and was refused without counting its requests, which change with how the contender polls.

public static Task WaitForRefusalAsync(this LockTable locks, string name, CancellationToken cancellationToken = default)

Parameters

locks LockTable

The lock table of the contender.

name string

The name of the lock.

cancellationToken CancellationToken

Ends the wait with an OperationCanceledException.

Returns

Task

A task that completes at the next refusal.

Remarks

The task waits for the next refusal after this call, so take it before the contender starts: a refusal that came before is not counted, and the task then completes at the contender's next poll, which on a fake clock needs the clock to move.

Exceptions

ArgumentNullException

locks is null.

ArgumentException

name is null or empty.