Skip to content

Commit

Permalink
Added tests for LeaseConsumer
Browse files Browse the repository at this point in the history
  • Loading branch information
sakno committed Jun 16, 2024
1 parent c5c54e5 commit 8f111ac
Showing 1 changed file with 111 additions and 3 deletions.
114 changes: 111 additions & 3 deletions src/DotNext.Tests/Threading/Leases/LeaseTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public sealed class LeaseTests : Test
public static async Task AcquireOrRenewInitialState()
{
using var provider = new TestLeaseProvider(DefaultTimeout);
Equal(DefaultTimeout, provider.TimeToLive);
Null(await provider.TryRenewAsync(default, true));
Null(await provider.TryRenewAsync(default, false));
Null(await provider.ReleaseAsync(default));
Expand All @@ -16,14 +17,37 @@ public static async Task AcquireOrRenewInitialState()
}

[Fact]
public static async Task Acquisition()
public static async Task AcquireRelease()
{
using var provider = new TestLeaseProvider(DefaultTimeout);
NotNull(await provider.TryAcquireAsync());
var result = NotNull(await provider.TryAcquireAsync());
NotNull(await provider.ReleaseAsync(result.State.Identity));

await provider.AcquireAsync();
Null(await provider.TryAcquireAsync());
NotNull(await provider.UnsafeTryReleaseAsync());
}

[Fact]
public static async Task RenewOrAcquire()
{
using var provider = new TestLeaseProvider(DefaultTimeout);
var result = NotNull(await provider.TryAcquireOrRenewAsync(default));
var result2 = NotNull(await provider.TryAcquireOrRenewAsync(result.State.Identity));
True(result.State.Identity << result2.State.Identity);
}

[Fact]
public static void Preceding()
public static async Task RenewAfterRelease()
{
using var provider = new TestLeaseProvider(DefaultTimeout);
var result = await provider.AcquireAsync();
await provider.UnsafeReleaseAsync();
Null(await provider.TryRenewAsync(result.State.Identity, reacquire: false));
}

[Fact]
public static void Precedence()
{
True(default(LeaseIdentity) << new LeaseIdentity { Version = 1UL });
False(default(LeaseIdentity) >> new LeaseIdentity { Version = 1UL });
Expand All @@ -43,6 +67,62 @@ public static async Task FightForLease()
True(tasks is [null, not null] or [not null, null]);
}

[Fact]
public static async Task FightForLeaseUsingConsumer()
{
using var provider = new TestLeaseProvider(DefaultTimeout);
await using var consumer1 = new TestLeaseConsumer(provider);
await using var consumer2 = new TestLeaseConsumer(provider);

var acquisition1 = Task.Run(async () => await consumer1.TryAcquireAsync());
var acquisition2 = Task.Run(async () => await consumer1.TryAcquireAsync());

var tasks = await Task.WhenAll(acquisition1, acquisition2);

True(tasks is [{ IsExpired: false }, { IsExpired: true }] or [{ IsExpired: true }, { IsExpired: false }]);
}

[Fact]
public static async Task ConsumerTokenState()
{
using var provider = new TestLeaseProvider(TimeSpan.FromMilliseconds(100));
await using var consumer = new TestLeaseConsumer(provider);
True(consumer.Token.IsCancellationRequested);

False((await consumer.TryAcquireAsync()).IsExpired);
False(consumer.Token.IsCancellationRequested);

await Task.Delay(150);
True(consumer.Token.IsCancellationRequested);
False(await consumer.ReleaseAsync());
}

[Fact]
public static async Task ConsumerRenew()
{
using var provider = new TestLeaseProvider(DefaultTimeout);
await using var consumer = new TestLeaseConsumer(provider);
await consumer.TryAcquireAsync();
var expected = consumer.Token;

await consumer.TryRenewAsync();
Equal(consumer.Token, expected);
}

[Fact]
public static async Task DisposeConcurrently()
{
Task task;
using (var provider = new TestLeaseProvider(DefaultTimeout))
{
await provider.AcquireAsync();
task = provider.AcquireAsync().AsTask();
False(task.IsCompleted);
}

await ThrowsAsync<ObjectDisposedException>(Func.Constant(task));
}

private sealed class TestLeaseProvider(TimeSpan ttl) : LeaseProvider<int>(ttl)
{
private readonly AsyncReaderWriterLock syncRoot = new();
Expand Down Expand Up @@ -90,4 +170,32 @@ protected override void Dispose(bool disposing)
base.Dispose(disposing);
}
}

private sealed class TestLeaseConsumer(TestLeaseProvider provider) : LeaseConsumer
{
protected override async ValueTask<AcquisitionResult?> TryAcquireCoreAsync(CancellationToken token = default)
{
return await provider.TryAcquireAsync(token) is { } result
? new AcquisitionResult { Identity = result.State.Identity, TimeToLive = result.Lifetime.Value }
: null;
}

protected override async ValueTask<AcquisitionResult?> TryRenewCoreAsync(LeaseIdentity identity,
CancellationToken token)
{
return await provider.TryAcquireOrRenewAsync(identity, token) is { } result
? new AcquisitionResult { Identity = result.State.Identity, TimeToLive = result.Lifetime.Value }
: null;
}

protected override ValueTask<LeaseIdentity?> ReleaseCoreAsync(LeaseIdentity identity,
CancellationToken token)
=> provider.ReleaseAsync(identity, token);

protected override ValueTask DisposeAsyncCore()
{
provider.Dispose();
return base.DisposeAsyncCore();
}
}
}

0 comments on commit 8f111ac

Please sign in to comment.