-
Notifications
You must be signed in to change notification settings - Fork 1
test: Add WinTun module test coverage #165
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
|
|
||
| <PropertyGroup> | ||
| <TargetFramework>net10.0</TargetFramework> | ||
| <AllowUnsafeBlocks>true</AllowUnsafeBlocks> | ||
| <IsPackable>false</IsPackable> | ||
| </PropertyGroup> | ||
|
|
||
| <ItemGroup> | ||
| <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" /> | ||
| <PackageReference Include="xunit" Version="2.6.6" /> | ||
| <PackageReference Include="xunit.runner.visualstudio" Version="2.8.0" /> | ||
| </ItemGroup> | ||
|
|
||
| <ItemGroup> | ||
| <ProjectReference Include="..\..\src\Magma.WinTun\Magma.WinTun.csproj" /> | ||
| </ItemGroup> | ||
|
|
||
| </Project> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| # Magma.WinTun.Facts | ||
|
|
||
| Test suite for the WinTun module. | ||
|
|
||
| ## Running Tests | ||
|
|
||
| ### Unit Tests | ||
|
|
||
| Unit tests run on all platforms (Windows and Linux) and do not require the WinTun driver: | ||
|
|
||
| ```bash | ||
| dotnet test test/Magma.WinTun.Facts | ||
| ``` | ||
|
|
||
| ### Integration Tests | ||
|
|
||
| Integration tests require: | ||
| - Windows operating system | ||
| - WinTun driver installed | ||
| - A configured TAP adapter | ||
|
||
|
|
||
| Integration tests are **skipped by default**. To enable them: | ||
|
|
||
| 1. Set the environment variable: | ||
| ```powershell | ||
| $env:WINTUN_INTEGRATION_TESTS="1" | ||
| ``` | ||
|
|
||
| 2. (Optional) Specify a custom adapter name: | ||
| ```powershell | ||
| $env:WINTUN_ADAPTER_NAME="YourAdapterName" | ||
| ``` | ||
|
|
||
| 3. Run the tests: | ||
| ```bash | ||
| dotnet test test/Magma.WinTun.Facts | ||
| ``` | ||
|
|
||
| Or run only integration tests: | ||
| ```bash | ||
| dotnet test test/Magma.WinTun.Facts --filter Category=Integration | ||
| ``` | ||
|
|
||
| ## Test Categories | ||
|
|
||
| - **Unit Tests**: Test public APIs without requiring the WinTun driver | ||
| - `WinIOFacts`: Constants and P/Invoke declarations | ||
|
||
| - `WinTunTransportReceiverFacts`: Transport receiver interface | ||
| - `WinTunMemoryPoolFacts`: Memory pool lifecycle and management | ||
|
|
||
| - **Integration Tests** (Category="Integration"): Require WinTun driver | ||
| - `WinTunPortIntegrationFacts`: Adapter create/destroy lifecycle | ||
|
|
||
| ## Platform Support | ||
|
|
||
| - **Linux**: Unit tests run and pass. Integration tests are skipped. | ||
| - **Windows**: All tests can run if WinTun driver is installed and integration tests are enabled. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,115 @@ | ||
| using System; | ||
| using System.Buffers; | ||
| using System.Threading.Tasks; | ||
| using Magma.WinTun.Internal; | ||
| using Xunit; | ||
|
|
||
| namespace Magma.WinTun.Facts | ||
| { | ||
| public class WinTunMemoryPoolFacts | ||
| { | ||
| [Fact] | ||
| public void PoolCreatesBuffersOfCorrectSize() | ||
| { | ||
| var poolSize = 10; | ||
| var bufferSize = 2000; | ||
| var pool = new WinTunMemoryPool(poolSize, bufferSize); | ||
|
|
||
| var success = pool.TryGetMemory(out var memory); | ||
|
|
||
| Assert.True(success); | ||
| Assert.NotNull(memory); | ||
| Assert.Equal(bufferSize, memory.Memory.Length); | ||
|
|
||
| memory.Return(); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void PoolSupportsMultipleBuffers() | ||
| { | ||
| var poolSize = 5; | ||
| var bufferSize = 1500; | ||
| var pool = new WinTunMemoryPool(poolSize, bufferSize); | ||
|
|
||
| var buffers = new WinTunMemoryPool.WinTunOwnedMemory[poolSize]; | ||
|
|
||
| for (var i = 0; i < poolSize; i++) | ||
| { | ||
| var success = pool.TryGetMemory(out buffers[i]); | ||
| Assert.True(success); | ||
| Assert.Equal(bufferSize, buffers[i].Memory.Length); | ||
| } | ||
|
|
||
| var exhausted = pool.TryGetMemory(out _); | ||
| Assert.False(exhausted); | ||
|
Comment on lines
+43
to
+44
|
||
|
|
||
| for (var i = 0; i < poolSize; i++) | ||
| { | ||
| buffers[i].Return(); | ||
| } | ||
| } | ||
|
|
||
| [Fact] | ||
| public void ReturnedBufferCanBeReused() | ||
| { | ||
| var pool = new WinTunMemoryPool(2, 1000); | ||
|
|
||
| var success1 = pool.TryGetMemory(out var memory1); | ||
| Assert.True(success1); | ||
|
|
||
| memory1.Return(); | ||
|
|
||
| var success2 = pool.TryGetMemory(out var memory2); | ||
| Assert.True(success2); | ||
|
|
||
| memory2.Return(); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void TryGetMemoryReturnsFalseWhenExhausted() | ||
| { | ||
| var pool = new WinTunMemoryPool(1, 1000); | ||
|
|
||
| var success1 = pool.TryGetMemory(out var memory1); | ||
| Assert.True(success1); | ||
|
|
||
| var success2 = pool.TryGetMemory(out var memory2); | ||
| Assert.False(success2); | ||
| Assert.Null(memory2); | ||
|
|
||
| memory1.Return(); | ||
| } | ||
|
|
||
| [Fact] | ||
| public async Task GetMemoryAsyncWaitsWhenPoolIsEmpty() | ||
| { | ||
| var pool = new WinTunMemoryPool(1, 1000); | ||
|
|
||
| var memory1 = await pool.GetMemoryAsync(); | ||
|
|
||
| var getTask = pool.GetMemoryAsync(); | ||
| await Task.Delay(50); | ||
| Assert.False(getTask.IsCompleted); | ||
|
|
||
| memory1.Return(); | ||
|
|
||
| var memory2 = await getTask; | ||
| Assert.NotNull(memory2); | ||
|
|
||
| memory2.Return(); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void MemoryOwnerGetSpanReturnsCorrectSpan() | ||
| { | ||
| var pool = new WinTunMemoryPool(1, 1500); | ||
| var success = pool.TryGetMemory(out var memory); | ||
|
|
||
| Assert.True(success); | ||
| var span = memory.GetSpan(); | ||
| Assert.Equal(1500, span.Length); | ||
|
|
||
| memory.Return(); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| using System; | ||
| using System.Runtime.InteropServices; | ||
| using Magma.Network.Abstractions; | ||
| using Magma.WinTun.Internal; | ||
| using Xunit; | ||
|
|
||
| namespace Magma.WinTun.Facts | ||
| { | ||
| [Trait("Category", "Integration")] | ||
| public class WinTunPortIntegrationFacts | ||
| { | ||
| private static bool IsWindows => RuntimeInformation.IsOSPlatform(OSPlatform.Windows); | ||
| private static bool IntegrationTestsEnabled => | ||
| !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("WINTUN_INTEGRATION_TESTS")); | ||
|
|
||
| [Fact(Skip = "Requires WinTun driver and adapter - set WINTUN_INTEGRATION_TESTS=1 to enable")] | ||
| public void CanCreateWinTunPort() | ||
| { | ||
| if (!IsWindows || !IntegrationTestsEnabled) | ||
| { | ||
| return; | ||
| } | ||
|
Comment on lines
+16
to
+22
|
||
|
|
||
| var adapterName = Environment.GetEnvironmentVariable("WINTUN_ADAPTER_NAME") ?? "WinTun"; | ||
|
|
||
| using (var port = new WinTunPort<TestPacketReceiver>( | ||
| adapterName, | ||
| transmitter => new TestPacketReceiver())) | ||
| { | ||
| Assert.NotNull(port); | ||
| } | ||
| } | ||
|
|
||
| [Fact(Skip = "Requires WinTun driver and adapter - set WINTUN_INTEGRATION_TESTS=1 to enable")] | ||
| public void WinTunPortDisposesCleanly() | ||
| { | ||
| if (!IsWindows || !IntegrationTestsEnabled) | ||
| { | ||
| return; | ||
| } | ||
|
Comment on lines
+34
to
+40
|
||
|
|
||
| var adapterName = Environment.GetEnvironmentVariable("WINTUN_ADAPTER_NAME") ?? "WinTun"; | ||
|
|
||
| var port = new WinTunPort<TestPacketReceiver>( | ||
| adapterName, | ||
| transmitter => new TestPacketReceiver()); | ||
|
|
||
| port.Dispose(); | ||
|
|
||
| port.Dispose(); | ||
| } | ||
|
|
||
| private class TestPacketReceiver : IPacketReceiver | ||
| { | ||
| public void FlushPendingAcks() | ||
| { | ||
| } | ||
|
|
||
| public T TryConsume<T>(T input) where T : System.Buffers.IMemoryOwner<byte> | ||
| { | ||
| return default; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| using System; | ||
| using System.Buffers; | ||
| using Magma.WinTun; | ||
| using Xunit; | ||
|
|
||
| namespace Magma.WinTun.Facts | ||
| { | ||
| public class WinTunTransportReceiverFacts | ||
| { | ||
| [Fact] | ||
| public void CanInstantiateWinTunTransportReceiver() | ||
| { | ||
| var receiver = new WinTunTransportReceiver(); | ||
| Assert.NotNull(receiver); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void FlushPendingAcksThrowsNotImplementedException() | ||
| { | ||
| var receiver = new WinTunTransportReceiver(); | ||
| Assert.Throws<NotImplementedException>(() => receiver.FlushPendingAcks()); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void TryConsumeThrowsNotImplementedException() | ||
| { | ||
| var receiver = new WinTunTransportReceiver(); | ||
| using var memory = MemoryPool<byte>.Shared.Rent(100); | ||
|
|
||
| Assert.Throws<NotImplementedException>(() => receiver.TryConsume(memory)); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test code does not contain any unsafe code blocks. The
AllowUnsafeBlocksproperty can be removed. Other test projects in the codebase (e.g., Magma.Internet.Ip.Facts, Magma.Link.Facts) don't set this property unless the test code directly uses unsafe blocks.