blob: dc76afdd14855a78a82db059eac4a4800deab18c [file] [log] [blame]
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace DotPulsar.Tests.Extensions;
using AutoFixture.Xunit2;
using DotPulsar.Abstractions;
using DotPulsar.Extensions;
using NSubstitute.ExceptionExtensions;
using System;
[Trait("Category", "Unit")]
public class StateExtensionsTests
{
[Theory, Tests.AutoData]
public async Task OnStateChangeTo_WhenChangingToFinalStateInitially_ShouldReturnFinalState([Frozen] IState<ProducerState> uut)
{
// Arrange
const ProducerState expected = ProducerState.Faulted;
uut.OnStateChangeTo(ProducerState.Disconnected, Arg.Any<CancellationToken>()).Returns(expected);
uut.IsFinalState(expected).Returns(true);
// Act
var actual = await uut.OnStateChangeTo(ProducerState.Disconnected, TimeSpan.FromSeconds(1));
// Assert
actual.Should().Be(expected);
}
[Theory, Tests.AutoData]
public async Task OnStateChangeTo_WhenChangingToFinalStateWhileWaitingForDelay_ShouldReturnFinalState([Frozen] IState<ProducerState> uut)
{
// Arrange
const ProducerState expected = ProducerState.Faulted;
uut.OnStateChangeTo(ProducerState.Disconnected, Arg.Any<CancellationToken>()).Returns(ProducerState.Disconnected);
uut.IsFinalState(ProducerState.Disconnected).Returns(false);
uut.OnStateChangeFrom(ProducerState.Disconnected, Arg.Any<CancellationToken>()).Returns(expected);
uut.IsFinalState(expected).Returns(true);
// Act
var actual = await uut.OnStateChangeTo(ProducerState.Disconnected, TimeSpan.FromSeconds(1));
// Assert
actual.Should().Be(expected);
}
[Theory, Tests.AutoData]
public async Task OnStateChangeTo_WhenTheDelayIsExceeded_ShouldReturnState([Frozen] IState<ProducerState> uut)
{
// Arrange
const ProducerState expected = ProducerState.Disconnected;
uut.OnStateChangeTo(expected, Arg.Any<CancellationToken>()).Returns(expected);
uut.IsFinalState(expected).Returns(false);
uut.OnStateChangeFrom(expected, Arg.Any<CancellationToken>()).Throws<OperationCanceledException>();
// Act
var actual = await uut.OnStateChangeTo(expected, TimeSpan.FromSeconds(1));
// Assert
actual.Should().Be(expected);
}
[Theory, Tests.AutoData]
public async Task OnStateChangeTo_WhenCancellationTokenIsCancelledInitially_ShouldThrowException([Frozen] IState<ProducerState> uut)
{
// Arrange
var cts = new CancellationTokenSource();
cts.Cancel();
uut.OnStateChangeTo(ProducerState.Disconnected, cts.Token).Throws<OperationCanceledException>();
// Act
var exception = await Record.ExceptionAsync(() => uut.OnStateChangeTo(ProducerState.Disconnected, TimeSpan.FromSeconds(1), cts.Token).AsTask());
// Assert
exception.Should().BeOfType<OperationCanceledException>();
}
[Theory, Tests.AutoData]
public async Task OnStateChangeTo_WhenCancellationTokenIsCancelledWhileWaitingForDelay_ShouldThrowException([Frozen] IState<ProducerState> uut)
{
// Arrange
var cts = new CancellationTokenSource();
cts.Cancel();
uut.OnStateChangeTo(ProducerState.Disconnected, cts.Token).Returns(ProducerState.Disconnected);
uut.IsFinalState(ProducerState.Disconnected).Returns(false);
uut.OnStateChangeFrom(ProducerState.Disconnected, Arg.Any<CancellationToken>()).Throws<OperationCanceledException>();
// Act
var exception = await Record.ExceptionAsync(() => uut.OnStateChangeTo(ProducerState.Disconnected, TimeSpan.FromSeconds(1), cts.Token).AsTask());
// Assert
exception.Should().BeOfType<OperationCanceledException>();
}
[Theory, Tests.AutoData]
public async Task OnStateChangeFrom_WhenChangingToFinalStateInitially_ShouldReturnFinalState([Frozen] IState<ProducerState> uut)
{
// Arrange
const ProducerState expected = ProducerState.Faulted;
uut.OnStateChangeFrom(ProducerState.Disconnected, Arg.Any<CancellationToken>()).Returns(expected);
uut.IsFinalState(expected).Returns(true);
// Act
var actual = await uut.OnStateChangeFrom(ProducerState.Disconnected, TimeSpan.FromSeconds(1));
// Assert
actual.Should().Be(expected);
}
[Theory, Tests.AutoData]
public async Task OnStateChangeFrom_WhenChangingToFinalStateWhileWaitingForDelay_ShouldReturnFinalState([Frozen] IState<ProducerState> uut)
{
// Arrange
const ProducerState expected = ProducerState.Faulted;
uut.OnStateChangeFrom(ProducerState.Disconnected, Arg.Any<CancellationToken>()).Returns(ProducerState.Disconnected);
uut.IsFinalState(ProducerState.Disconnected).Returns(false);
uut.OnStateChangeTo(ProducerState.Disconnected, Arg.Any<CancellationToken>()).Returns(expected);
uut.IsFinalState(expected).Returns(true);
// Act
var actual = await uut.OnStateChangeFrom(ProducerState.Disconnected, TimeSpan.FromSeconds(1));
// Assert
actual.Should().Be(expected);
}
[Theory, Tests.AutoData]
public async Task OnStateChangeFrom_WhenTheDelayIsExceeded_ShouldReturnState([Frozen] IState<ProducerState> uut)
{
// Arrange
const ProducerState expected = ProducerState.Disconnected;
uut.OnStateChangeFrom(ProducerState.Connected, Arg.Any<CancellationToken>()).Returns(expected);
uut.IsFinalState(expected).Returns(false);
uut.OnStateChangeTo(ProducerState.Connected, Arg.Any<CancellationToken>()).Throws<OperationCanceledException>();
// Act
var actual = await uut.OnStateChangeFrom(ProducerState.Connected, TimeSpan.FromSeconds(1));
// Assert
actual.Should().Be(expected);
}
[Theory, Tests.AutoData]
public async Task OnStateChangeFrom_WhenCancellationTokenIsCancelledInitially_ShouldThrowException([Frozen] IState<ProducerState> uut)
{
// Arrange
var cts = new CancellationTokenSource();
cts.Cancel();
uut.OnStateChangeFrom(ProducerState.Disconnected, cts.Token).Throws<OperationCanceledException>();
// Act
var exception = await Record.ExceptionAsync(() => uut.OnStateChangeFrom(ProducerState.Disconnected, TimeSpan.FromSeconds(1), cts.Token).AsTask());
// Assert
exception.Should().BeOfType<OperationCanceledException>();
}
[Theory, Tests.AutoData]
public async Task OnStateChangeFrom_WhenCancellationTokenIsCancelledWhileWaitingForDelay_ShouldThrowException([Frozen] IState<ProducerState> uut)
{
// Arrange
var cts = new CancellationTokenSource();
cts.Cancel();
uut.OnStateChangeFrom(ProducerState.Disconnected, cts.Token).Returns(ProducerState.Disconnected);
uut.IsFinalState(ProducerState.Disconnected).Returns(false);
uut.OnStateChangeTo(ProducerState.Disconnected, Arg.Any<CancellationToken>()).Throws<OperationCanceledException>();
// Act
var exception = await Record.ExceptionAsync(() => uut.OnStateChangeFrom(ProducerState.Disconnected, TimeSpan.FromSeconds(1), cts.Token).AsTask());
// Assert
exception.Should().BeOfType<OperationCanceledException>();
}
[Theory, Tests.AutoData]
public async Task DelayedStateMonitor_WhenChangingToFinalStateInitially_ShouldInvokeOnStateLeft([Frozen] IState<ProducerState> uut)
{
// Arrange
const ProducerState expected = ProducerState.Faulted;
uut.OnStateChangeFrom(ProducerState.Connected, Arg.Any<CancellationToken>()).Returns(expected);
uut.IsFinalState(expected).Returns(true);
ProducerState? stateLeft = null;
ProducerState? stateReached = null;
void onStateLeft(IState<ProducerState> _, ProducerState state) => stateLeft = state;
void onStateReached(IState<ProducerState> _, ProducerState state) => stateReached = state;
// Act
await uut.DelayedStateMonitor(ProducerState.Connected, TimeSpan.FromSeconds(1), onStateLeft, onStateReached);
// Assert
stateLeft.HasValue.Should().BeTrue();
stateLeft!.Value.Should().Be(expected);
stateReached.HasValue.Should().BeFalse();
}
[Theory, Tests.AutoData]
public async Task DelayedStateMonitor_WhenChangingToFinalStateWhileWaiting_ShouldInvokeOnStateLeft([Frozen] IState<ProducerState> uut)
{
// Arrange
const ProducerState expected = ProducerState.Disconnected;
uut.OnStateChangeFrom(ProducerState.Connected, Arg.Any<CancellationToken>()).Returns(expected);
uut.IsFinalState(ProducerState.Disconnected).Returns(false);
uut.OnStateChangeTo(ProducerState.Connected, Arg.Any<CancellationToken>()).Returns(x => throw new OperationCanceledException(), x => ProducerState.Faulted);
uut.IsFinalState(ProducerState.Faulted).Returns(true);
ProducerState? stateLeft = null;
ProducerState? stateReached = null;
void onStateLeft(IState<ProducerState> _, ProducerState state) => stateLeft = state;
void onStateReached(IState<ProducerState> _, ProducerState state) => stateReached = state;
// Act
await uut.DelayedStateMonitor(ProducerState.Connected, TimeSpan.FromSeconds(1), onStateLeft, onStateReached);
// Assert
stateLeft.HasValue.Should().BeTrue();
stateLeft!.Value.Should().Be(expected);
stateReached.HasValue.Should().BeFalse();
}
}