This is an automated email from the ASF dual-hosted git repository.
blankensteiner pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-dotpulsar.git
The following commit(s) were added to refs/heads/master by this push:
new 94a8a35 Added delay option for OnStateChangeFrom/To for IState and
StateChangedFrom/To for IConsumer, IProducer, and IReader
94a8a35 is described below
commit 94a8a35133e7521bf78903180ad80ecc6d6fa80a
Author: Daniel Blankensteiner <[email protected]>
AuthorDate: Tue Nov 29 15:34:32 2022 +0100
Added delay option for OnStateChangeFrom/To for IState and
StateChangedFrom/To for IConsumer, IProducer, and IReader
---
CHANGELOG.md | 1 +
samples/Producing/Program.cs | 2 +-
src/DotPulsar/Extensions/ConsumerExtensions.cs | 40 +++++++-
src/DotPulsar/Extensions/ProducerExtensions.cs | 41 +++++++-
src/DotPulsar/Extensions/ReaderExtensions.cs | 41 +++++++-
src/DotPulsar/Extensions/StateExtensions.cs | 106 ++++++++++++++++++++
tests/DotPulsar.Tests/AutoDataAttribute.cs | 23 +++++
tests/DotPulsar.Tests/DotPulsar.Tests.csproj | 2 +
.../Extensions/StateExtensionsTests.cs | 110 +++++++++++++++++++++
tests/DotPulsar.Tests/InlineAutoDataAttribute.cs | 20 ++++
tests/DotPulsar.Tests/ProducerTests.cs | 4 +-
tests/DotPulsar.Tests/TokenTests.cs | 4 +-
12 files changed, 374 insertions(+), 20 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d8ddf2c..f0bab92 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@ The format is based on [Keep a
Changelog](https://keepachangelog.com/en/1.0.0/)
### Added
- .NET 7 added as a target framework
+- Delay option for OnStateChangeFrom/To for IState and StateChangedFrom/To for
IConsumer, IProducer, and IReader
### Removed
diff --git a/samples/Producing/Program.cs b/samples/Producing/Program.cs
index 03025fe..8416c69 100644
--- a/samples/Producing/Program.cs
+++ b/samples/Producing/Program.cs
@@ -1,4 +1,4 @@
-/*
+/*
* 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
diff --git a/src/DotPulsar/Extensions/ConsumerExtensions.cs
b/src/DotPulsar/Extensions/ConsumerExtensions.cs
index a2581e7..bd34782 100644
--- a/src/DotPulsar/Extensions/ConsumerExtensions.cs
+++ b/src/DotPulsar/Extensions/ConsumerExtensions.cs
@@ -1,4 +1,4 @@
-/*
+/*
* 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
@@ -70,8 +70,23 @@ public static class ConsumerExtensions
/// </remarks>
public static async ValueTask<ConsumerStateChanged> StateChangedTo(this
IConsumer consumer, ConsumerState state, CancellationToken cancellationToken =
default)
{
- var newState = await consumer.OnStateChangeTo(state,
cancellationToken).ConfigureAwait(false);
- return new ConsumerStateChanged(consumer, newState);
+ var currentState = await consumer.OnStateChangeTo(state,
cancellationToken).ConfigureAwait(false);
+ return new ConsumerStateChanged(consumer, currentState);
+ }
+
+ /// <summary>
+ /// Wait for the state to change to a specific state with a delay.
+ /// </summary>
+ /// <returns>
+ /// The current state.
+ /// </returns>
+ /// <remarks>
+ /// If the state change to a final state, then all awaiting tasks will
complete.
+ /// </remarks>
+ public static async ValueTask<ConsumerStateChanged> StateChangedTo(this
IConsumer consumer, ConsumerState state, TimeSpan delay, CancellationToken
cancellationToken = default)
+ {
+ var currentState = await consumer.OnStateChangeTo(state, delay,
cancellationToken).ConfigureAwait(false);
+ return new ConsumerStateChanged(consumer, currentState);
}
/// <summary>
@@ -85,7 +100,22 @@ public static class ConsumerExtensions
/// </remarks>
public static async ValueTask<ConsumerStateChanged> StateChangedFrom(this
IConsumer consumer, ConsumerState state, CancellationToken cancellationToken =
default)
{
- var newState = await consumer.OnStateChangeFrom(state,
cancellationToken).ConfigureAwait(false);
- return new ConsumerStateChanged(consumer, newState);
+ var currentState = await consumer.OnStateChangeFrom(state,
cancellationToken).ConfigureAwait(false);
+ return new ConsumerStateChanged(consumer, currentState);
+ }
+
+ /// <summary>
+ /// Wait for the state to change from a specific state with delay.
+ /// </summary>
+ /// <returns>
+ /// The current state.
+ /// </returns>
+ /// <remarks>
+ /// If the state change to a final state, then all awaiting tasks will
complete.
+ /// </remarks>
+ public static async ValueTask<ConsumerStateChanged> StateChangedFrom(this
IConsumer consumer, ConsumerState state, TimeSpan delay, CancellationToken
cancellationToken = default)
+ {
+ var currentState = await consumer.OnStateChangeFrom(state, delay,
cancellationToken).ConfigureAwait(false);
+ return new ConsumerStateChanged(consumer, currentState);
}
}
diff --git a/src/DotPulsar/Extensions/ProducerExtensions.cs
b/src/DotPulsar/Extensions/ProducerExtensions.cs
index 71ea70d..8933a0d 100644
--- a/src/DotPulsar/Extensions/ProducerExtensions.cs
+++ b/src/DotPulsar/Extensions/ProducerExtensions.cs
@@ -1,4 +1,4 @@
-/*
+/*
* 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
@@ -16,6 +16,7 @@ namespace DotPulsar.Extensions;
using Abstractions;
using Internal;
+using System;
using System.Threading;
using System.Threading.Tasks;
@@ -41,8 +42,23 @@ public static class ProducerExtensions
/// </remarks>
public static async ValueTask<ProducerStateChanged> StateChangedTo(this
IProducer producer, ProducerState state, CancellationToken cancellationToken =
default)
{
- var newState = await producer.OnStateChangeTo(state,
cancellationToken).ConfigureAwait(false);
- return new ProducerStateChanged(producer, newState);
+ var currentState = await producer.OnStateChangeTo(state,
cancellationToken).ConfigureAwait(false);
+ return new ProducerStateChanged(producer, currentState);
+ }
+
+ /// <summary>
+ /// Wait for the state to change to a specific state with a delay.
+ /// </summary>
+ /// <returns>
+ /// The current state.
+ /// </returns>
+ /// <remarks>
+ /// If the state change to a final state, then all awaiting tasks will
complete.
+ /// </remarks>
+ public static async ValueTask<ProducerStateChanged> StateChangedTo(this
IProducer producer, ProducerState state, TimeSpan delay, CancellationToken
cancellationToken = default)
+ {
+ var currentState = await producer.OnStateChangeTo(state, delay,
cancellationToken).ConfigureAwait(false);
+ return new ProducerStateChanged(producer, currentState);
}
/// <summary>
@@ -56,7 +72,22 @@ public static class ProducerExtensions
/// </remarks>
public static async ValueTask<ProducerStateChanged> StateChangedFrom(this
IProducer producer, ProducerState state, CancellationToken cancellationToken =
default)
{
- var newState = await producer.OnStateChangeFrom(state,
cancellationToken).ConfigureAwait(false);
- return new ProducerStateChanged(producer, newState);
+ var currentState = await producer.OnStateChangeFrom(state,
cancellationToken).ConfigureAwait(false);
+ return new ProducerStateChanged(producer, currentState);
+ }
+
+ /// <summary>
+ /// Wait for the state to change from a specific state with a delay.
+ /// </summary>
+ /// <returns>
+ /// The current state.
+ /// </returns>
+ /// <remarks>
+ /// If the state change to a final state, then all awaiting tasks will
complete.
+ /// </remarks>
+ public static async ValueTask<ProducerStateChanged> StateChangedFrom(this
IProducer producer, ProducerState state, TimeSpan delay, CancellationToken
cancellationToken = default)
+ {
+ var currentState = await producer.OnStateChangeFrom(state, delay,
cancellationToken).ConfigureAwait(false);
+ return new ProducerStateChanged(producer, currentState);
}
}
diff --git a/src/DotPulsar/Extensions/ReaderExtensions.cs
b/src/DotPulsar/Extensions/ReaderExtensions.cs
index 661c5be..7a7449d 100644
--- a/src/DotPulsar/Extensions/ReaderExtensions.cs
+++ b/src/DotPulsar/Extensions/ReaderExtensions.cs
@@ -1,4 +1,4 @@
-/*
+/*
* 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
@@ -15,6 +15,7 @@
namespace DotPulsar.Extensions;
using DotPulsar.Abstractions;
+using System;
using System.Threading;
using System.Threading.Tasks;
@@ -34,8 +35,23 @@ public static class ReaderExtensions
/// </remarks>
public static async ValueTask<ReaderStateChanged> StateChangedTo(this
IReader reader, ReaderState state, CancellationToken cancellationToken =
default)
{
- var newState = await reader.OnStateChangeTo(state,
cancellationToken).ConfigureAwait(false);
- return new ReaderStateChanged(reader, newState);
+ var currentState = await reader.OnStateChangeTo(state,
cancellationToken).ConfigureAwait(false);
+ return new ReaderStateChanged(reader, currentState);
+ }
+
+ /// <summary>
+ /// Wait for the state to change to a specific state with a delay.
+ /// </summary>
+ /// <returns>
+ /// The current state.
+ /// </returns>
+ /// <remarks>
+ /// If the state change to a final state, then all awaiting tasks will
complete.
+ /// </remarks>
+ public static async ValueTask<ReaderStateChanged> StateChangedTo(this
IReader reader, ReaderState state, TimeSpan delay, CancellationToken
cancellationToken = default)
+ {
+ var currentState = await reader.OnStateChangeTo(state, delay,
cancellationToken).ConfigureAwait(false);
+ return new ReaderStateChanged(reader, currentState);
}
/// <summary>
@@ -49,7 +65,22 @@ public static class ReaderExtensions
/// </remarks>
public static async ValueTask<ReaderStateChanged> StateChangedFrom(this
IReader reader, ReaderState state, CancellationToken cancellationToken =
default)
{
- var newState = await reader.OnStateChangeFrom(state,
cancellationToken).ConfigureAwait(false);
- return new ReaderStateChanged(reader, newState);
+ var currentState = await reader.OnStateChangeFrom(state,
cancellationToken).ConfigureAwait(false);
+ return new ReaderStateChanged(reader, currentState);
+ }
+
+ /// <summary>
+ /// Wait for the state to change from a specific state with a delay.
+ /// </summary>
+ /// <returns>
+ /// The current state.
+ /// </returns>
+ /// <remarks>
+ /// If the state change to a final state, then all awaiting tasks will
complete.
+ /// </remarks>
+ public static async ValueTask<ReaderStateChanged> StateChangedFrom(this
IReader reader, ReaderState state, TimeSpan delay, CancellationToken
cancellationToken = default)
+ {
+ var currentState = await reader.OnStateChangeFrom(state, delay,
cancellationToken).ConfigureAwait(false);
+ return new ReaderStateChanged(reader, currentState);
}
}
diff --git a/src/DotPulsar/Extensions/StateExtensions.cs
b/src/DotPulsar/Extensions/StateExtensions.cs
new file mode 100644
index 0000000..bb5f280
--- /dev/null
+++ b/src/DotPulsar/Extensions/StateExtensions.cs
@@ -0,0 +1,106 @@
+/*
+ * 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.Extensions;
+
+using DotPulsar.Abstractions;
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+/// <summary>
+/// Extensions for IState.
+/// </summary>
+public static class StateExtensions
+{
+ /// <summary>
+ /// Wait for the state to change to a specific state with a delay.
+ /// </summary>
+ /// <returns>
+ /// The current state.
+ /// </returns>
+ /// <remarks>
+ /// If the state change to a final state, then all awaiting tasks will
complete.
+ /// </remarks>
+ public static async ValueTask<TState> OnStateChangeTo<TState>(
+ this IState<TState> stateChanged,
+ TState state,
+ TimeSpan delay,
+ CancellationToken cancellationToken = default) where TState : notnull
+ {
+ while (true)
+ {
+ var currentState = await stateChanged.OnStateChangeTo(state,
cancellationToken).ConfigureAwait(false);
+ if (stateChanged.IsFinalState(currentState))
+ return currentState;
+
+ using var cts =
CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
+ cts.CancelAfter(delay);
+
+ try
+ {
+ currentState = await stateChanged.OnStateChangeFrom(state,
cts.Token).ConfigureAwait(false);
+ if (stateChanged.IsFinalState(currentState))
+ return currentState;
+ }
+ catch (OperationCanceledException)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ throw;
+
+ return state;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Wait for the state to change from a specific state with a delay.
+ /// </summary>
+ /// <returns>
+ /// The current state.
+ /// </returns>
+ /// <remarks>
+ /// If the state change to a final state, then all awaiting tasks will
complete.
+ /// </remarks>
+ public static async ValueTask<TState> OnStateChangeFrom<TState>(
+ this IState<TState> stateChanged,
+ TState state,
+ TimeSpan delay,
+ CancellationToken cancellationToken = default) where TState : notnull
+ {
+ while (true)
+ {
+ var currentState = await stateChanged.OnStateChangeFrom(state,
cancellationToken).ConfigureAwait(false);
+ if (stateChanged.IsFinalState(currentState))
+ return currentState;
+
+ using var cts =
CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
+ cts.CancelAfter(delay);
+
+ try
+ {
+ currentState = await stateChanged.OnStateChangeTo(state,
cts.Token).ConfigureAwait(false);
+ if (stateChanged.IsFinalState(currentState))
+ return currentState;
+ }
+ catch (OperationCanceledException)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ throw;
+
+ return state;
+ }
+ }
+ }
+}
diff --git a/tests/DotPulsar.Tests/AutoDataAttribute.cs
b/tests/DotPulsar.Tests/AutoDataAttribute.cs
new file mode 100644
index 0000000..3a495e1
--- /dev/null
+++ b/tests/DotPulsar.Tests/AutoDataAttribute.cs
@@ -0,0 +1,23 @@
+/*
+ * 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;
+
+using AutoFixture;
+using AutoFixture.AutoNSubstitute;
+
+public class AutoDataAttribute : AutoFixture.Xunit2.AutoDataAttribute
+{
+ public AutoDataAttribute() : base(() => new Fixture().Customize(new
AutoNSubstituteCustomization())) { }
+}
diff --git a/tests/DotPulsar.Tests/DotPulsar.Tests.csproj
b/tests/DotPulsar.Tests/DotPulsar.Tests.csproj
index e6ab414..349b2f5 100644
--- a/tests/DotPulsar.Tests/DotPulsar.Tests.csproj
+++ b/tests/DotPulsar.Tests/DotPulsar.Tests.csproj
@@ -6,6 +6,8 @@
</PropertyGroup>
<ItemGroup>
+ <PackageReference Include="AutoFixture.AutoNSubstitute" Version="4.17.0" />
+ <PackageReference Include="AutoFixture.Xunit2" Version="4.17.0" />
<PackageReference Include="DotNetZip" Version="1.16.0" />
<PackageReference Include="Ductus.FluentDocker" Version="2.10.57" />
<PackageReference Include="FluentAssertions" Version="6.8.0" />
diff --git a/tests/DotPulsar.Tests/Extensions/StateExtensionsTests.cs
b/tests/DotPulsar.Tests/Extensions/StateExtensionsTests.cs
new file mode 100644
index 0000000..b2b74b1
--- /dev/null
+++ b/tests/DotPulsar.Tests/Extensions/StateExtensionsTests.cs
@@ -0,0 +1,110 @@
+/*
+ * 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 FluentAssertions;
+using NSubstitute;
+using NSubstitute.ExceptionExtensions;
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+
+[Trait("Category", "Unit")]
+public class StateExtensionsTests
+{
+ [Theory, Tests.AutoData]
+ public async Task
OnStateChangeTo_WhenChangingToFinalStateInitially_ShouldReturnFinalState([Frozen]
IState<ProducerState> sut)
+ {
+ // Arrange
+ const ProducerState expected = ProducerState.Faulted;
+ sut.OnStateChangeTo(ProducerState.Disconnected,
Arg.Any<CancellationToken>()).Returns(expected);
+ sut.IsFinalState(expected).Returns(true);
+
+ // Act
+ var actual = await sut.OnStateChangeTo(ProducerState.Disconnected,
TimeSpan.FromSeconds(1));
+
+ // Assert
+ actual.Should().Be(expected);
+ }
+
+ [Theory, Tests.AutoData]
+ public async Task
OnStateChangeTo_WhenChangingToFinalStateWhileWaitingForDelay_ShouldReturnFinalState([Frozen]
IState<ProducerState> sut)
+ {
+ // Arrange
+ const ProducerState expected = ProducerState.Faulted;
+ sut.OnStateChangeTo(ProducerState.Disconnected,
Arg.Any<CancellationToken>()).Returns(ProducerState.Disconnected);
+ sut.IsFinalState(ProducerState.Disconnected).Returns(false);
+ sut.OnStateChangeFrom(ProducerState.Disconnected,
Arg.Any<CancellationToken>()).Returns(expected);
+ sut.IsFinalState(expected).Returns(true);
+
+ // Act
+ var actual = await sut.OnStateChangeTo(ProducerState.Disconnected,
TimeSpan.FromSeconds(1));
+
+ // Assert
+ actual.Should().Be(expected);
+ }
+
+ [Theory, Tests.AutoData]
+ public async Task
OnStateChangeTo_WhenTheDelayIsExceeded_ShouldReturnState([Frozen]
IState<ProducerState> sut)
+ {
+ // Arrange
+ const ProducerState expected = ProducerState.Disconnected;
+ sut.OnStateChangeTo(expected,
Arg.Any<CancellationToken>()).Returns(expected);
+ sut.IsFinalState(expected).Returns(false);
+ sut.OnStateChangeFrom(expected,
Arg.Any<CancellationToken>()).Throws<OperationCanceledException>();
+
+ // Act
+ var actual = await sut.OnStateChangeTo(expected,
TimeSpan.FromSeconds(1));
+
+ // Assert
+ actual.Should().Be(expected);
+ }
+
+ [Theory, Tests.AutoData]
+ public async Task
OnStateChangeTo_WhenCancellationTokenIsCancelledInitially_ShouldThrowException([Frozen]
IState<ProducerState> sut)
+ {
+ // Arrange
+ var cts = new CancellationTokenSource();
+ cts.Cancel();
+ sut.OnStateChangeTo(ProducerState.Disconnected,
cts.Token).Throws<OperationCanceledException>();
+
+ // Act
+ var exception = await Record.ExceptionAsync(() =>
sut.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> sut)
+ {
+ // Arrange
+ var cts = new CancellationTokenSource();
+ cts.Cancel();
+ sut.OnStateChangeTo(ProducerState.Disconnected,
cts.Token).Returns(ProducerState.Disconnected);
+ sut.IsFinalState(ProducerState.Disconnected).Returns(false);
+ sut.OnStateChangeFrom(ProducerState.Disconnected,
Arg.Any<CancellationToken>()).Throws<OperationCanceledException>();
+
+ // Act
+ var exception = await Record.ExceptionAsync(() =>
sut.OnStateChangeTo(ProducerState.Disconnected, TimeSpan.FromSeconds(1),
cts.Token).AsTask());
+
+ // Assert
+ exception.Should().BeOfType<OperationCanceledException>();
+ }
+}
diff --git a/tests/DotPulsar.Tests/InlineAutoDataAttribute.cs
b/tests/DotPulsar.Tests/InlineAutoDataAttribute.cs
new file mode 100644
index 0000000..52a19c2
--- /dev/null
+++ b/tests/DotPulsar.Tests/InlineAutoDataAttribute.cs
@@ -0,0 +1,20 @@
+/*
+ * 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;
+
+public class InlineAutoDataAttribute :
AutoFixture.Xunit2.InlineAutoDataAttribute
+{
+ public InlineAutoDataAttribute(params object[] objects) : base(new
AutoDataAttribute(), objects) { }
+}
diff --git a/tests/DotPulsar.Tests/ProducerTests.cs
b/tests/DotPulsar.Tests/ProducerTests.cs
index 1f63ad2..9a6a1e1 100644
--- a/tests/DotPulsar.Tests/ProducerTests.cs
+++ b/tests/DotPulsar.Tests/ProducerTests.cs
@@ -1,4 +1,4 @@
-/*
+/*
* 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
@@ -15,7 +15,7 @@
namespace DotPulsar.Tests;
using Abstractions;
-using Extensions;
+using DotPulsar.Extensions;
using FluentAssertions;
using System;
using System.Collections.Generic;
diff --git a/tests/DotPulsar.Tests/TokenTests.cs
b/tests/DotPulsar.Tests/TokenTests.cs
index bd075aa..9834a63 100644
--- a/tests/DotPulsar.Tests/TokenTests.cs
+++ b/tests/DotPulsar.Tests/TokenTests.cs
@@ -1,4 +1,4 @@
-/*
+/*
* 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
@@ -16,7 +16,7 @@ namespace DotPulsar.Tests;
using DotPulsar.Abstractions;
using DotPulsar.Exceptions;
-using Extensions;
+using DotPulsar.Extensions;
using FluentAssertions;
using System;
using System.Threading;