Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/test_linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,8 @@ jobs:
cd tests/NATS.Net.DocsExamples
dotnet run

- name: Check ABI Compatibility (Type Forwarding)
run: |
cd tests/NATS.Client.CheckAbi
bash run-abi-check.sh

14 changes: 14 additions & 0 deletions NATS.Net.sln
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NATS.Slow.Tests", "tests\NA
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NATS.Client.Abstractions", "src\NATS.Client.Abstractions\NATS.Client.Abstractions.csproj", "{71C2BC96-C104-4748-B6CF-E74BAC4E709D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NATS.Client.CheckAbiTransientLib", "tests\NATS.Client.CheckAbiTransientLib\NATS.Client.CheckAbiTransientLib.csproj", "{21649885-B40A-4F6B-9286-A7E378276C3E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NATS.Client.CheckAbi", "tests\NATS.Client.CheckAbi\NATS.Client.CheckAbi.csproj", "{DA8E9EC2-990C-4DA2-A3F3-7E7796C71DD8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -359,6 +363,14 @@ Global
{71C2BC96-C104-4748-B6CF-E74BAC4E709D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{71C2BC96-C104-4748-B6CF-E74BAC4E709D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{71C2BC96-C104-4748-B6CF-E74BAC4E709D}.Release|Any CPU.Build.0 = Release|Any CPU
{21649885-B40A-4F6B-9286-A7E378276C3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{21649885-B40A-4F6B-9286-A7E378276C3E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{21649885-B40A-4F6B-9286-A7E378276C3E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{21649885-B40A-4F6B-9286-A7E378276C3E}.Release|Any CPU.Build.0 = Release|Any CPU
{DA8E9EC2-990C-4DA2-A3F3-7E7796C71DD8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DA8E9EC2-990C-4DA2-A3F3-7E7796C71DD8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DA8E9EC2-990C-4DA2-A3F3-7E7796C71DD8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DA8E9EC2-990C-4DA2-A3F3-7E7796C71DD8}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -417,6 +429,8 @@ Global
{0B6CBF18-D11C-4CC3-A50C-437A9F7E761D} = {5BF3C0C5-94CA-4008-8DF5-890ED8E06990}
{1F6C87C7-1911-4E96-ADB4-1EF27BD09C60} = {C526E8AB-739A-48D7-8FC4-048978C9B650}
{71C2BC96-C104-4748-B6CF-E74BAC4E709D} = {4827B3EC-73D8-436D-AE2A-5E29AC95FD0C}
{21649885-B40A-4F6B-9286-A7E378276C3E} = {C526E8AB-739A-48D7-8FC4-048978C9B650}
{DA8E9EC2-990C-4DA2-A3F3-7E7796C71DD8} = {C526E8AB-739A-48D7-8FC4-048978C9B650}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8CBB7278-D093-448E-B3DE-B5991209A1AA}
Expand Down
7 changes: 7 additions & 0 deletions src/NATS.Client.Core/TypeForwarders.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using System.Runtime.CompilerServices;
using NATS.Client.Core;

[assembly: TypeForwardedTo(typeof(INatsSerializer<>))]
[assembly: TypeForwardedTo(typeof(INatsSerialize<>))]
[assembly: TypeForwardedTo(typeof(INatsDeserialize<>))]
[assembly: TypeForwardedTo(typeof(INatsSerializerRegistry))]
25 changes: 25 additions & 0 deletions tests/NATS.Client.CheckAbi/NATS.Client.CheckAbi.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<GenerateTargetFrameworkAttribute>false</GenerateTargetFrameworkAttribute>
</PropertyGroup>

<!-- Reference local 2.7.0 source -->
<ItemGroup>
<ProjectReference Include="..\..\src\NATS.Net\NATS.Net.csproj" />
</ItemGroup>

<!-- Reference pre-built NATS.Client.CheckAbiTransientLib.dll (compiled against 2.6.0) -->
<ItemGroup>
<Reference Include="NATS.Client.CheckAbiTransientLib">
<HintPath>..\NATS.Client.CheckAbiTransientLib\bin\Release\net8.0\NATS.Client.CheckAbiTransientLib.dll</HintPath>
<Private>true</Private>
</Reference>
</ItemGroup>

</Project>
37 changes: 37 additions & 0 deletions tests/NATS.Client.CheckAbi/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System.Buffers;
using NATS.Client.CheckAbiTransientLib;
using NATS.Client.Core;

// This project simulates the real-world ABI compatibility scenario:
// - AbiCheck references NATS.Net 2.7.0 (local source with type forwarders)
// - TransientLib was compiled against NATS.Net 2.6.0 (types in NATS.Client.Core)
// - At runtime, type forwarding should allow TransientLib to work with 2.7.0
Console.WriteLine("ABI Compatibility Check (Transient Dependency Simulation)");
Console.WriteLine("==========================================================");
Console.WriteLine();

// Check where THIS project sees the types (should be Abstractions since we use 2.7.0)
Console.WriteLine("Types as seen by this project (compiled against 2.7.0):");
Console.WriteLine($" INatsSerialize<> assembly: {typeof(INatsSerialize<>).Assembly.GetName().Name}");
Console.WriteLine($" INatsDeserialize<> assembly: {typeof(INatsDeserialize<>).Assembly.GetName().Name}");
Console.WriteLine($" INatsSerializer<> assembly: {typeof(INatsSerializer<>).Assembly.GetName().Name}");
Console.WriteLine($" INatsSerializerRegistry assembly: {typeof(INatsSerializerRegistry).Assembly.GetName().Name}");
Console.WriteLine();

// Check where TransientLib sees the types (compiled against 2.6.0, but should resolve via forwarding)
Console.WriteLine("Types as seen by TransientLib (compiled against 2.6.0):");
Console.WriteLine($" INatsSerialize<> assembly: {MySerializer.GetSerializerInterfaceAssembly()}");
Console.WriteLine();

// Use the serializer from TransientLib (compiled against 2.6.0)
Console.WriteLine("Testing TransientLib.MySerializer (compiled against 2.6.0):");
var serializer = new MySerializer();
var buffer = new ArrayBufferWriter<byte>();
serializer.Serialize(buffer, "hello from transient dependency");
Console.WriteLine($" Serialized to {buffer.WrittenCount} bytes");

var deserialized = serializer.Deserialize(new ReadOnlySequence<byte>(buffer.WrittenSpan.ToArray()));
Console.WriteLine($" Deserialized: '{deserialized}'");

Console.WriteLine();
Console.WriteLine("SUCCESS: ABI compatibility verified with transient dependency!");
31 changes: 31 additions & 0 deletions tests/NATS.Client.CheckAbi/run-abi-check.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/bin/bash
set -e

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"

echo "=== NATS.Net ABI Compatibility Check (Transient Dependency Simulation) ==="
echo ""
echo "This test simulates:"
echo " - An app using NATS.Net 2.7.0 (with type forwarders)"
echo " - A transient dependency (TransientLib) compiled against NATS.Net 2.6.0"
echo " - Type forwarding should allow the old library to work with new NATS.Net"
echo ""

# Step 1: Build CheckAbiTransientLib against 2.6.0 NuGet package
echo "[1/3] Building NATS.Client.CheckAbiTransientLib against NATS.Net 2.6.0..."
dotnet build "$SCRIPT_DIR/../NATS.Client.CheckAbiTransientLib/NATS.Client.CheckAbiTransientLib.csproj" -c Release

# Step 2: Build AbiCheck (references local 2.7.0 source + TransientLib.dll)
echo ""
echo "[2/3] Building AbiCheck against local NATS.Net 2.7.0 source + TransientLib..."
dotnet build "$SCRIPT_DIR/NATS.Client.CheckAbi.csproj" -c Release

# Step 3: Run the test
echo ""
echo "[3/3] Running ABI compatibility check..."
echo ""
dotnet run --project "$SCRIPT_DIR/NATS.Client.CheckAbi.csproj" -c Release --no-build

echo ""
echo "=== ABI Check Complete ==="
29 changes: 29 additions & 0 deletions tests/NATS.Client.CheckAbiTransientLib/MySerializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System.Buffers;
using NATS.Client.Core;

namespace NATS.Client.CheckAbiTransientLib;

/// <summary>
/// This class is compiled against NATS.Net 2.6.0 where INatsSerializer lives in NATS.Client.Core.
/// When used with NATS.Net 2.7.0+, type forwarding should redirect to NATS.Client.Abstractions.
/// </summary>
public class MySerializer : INatsSerializer<string>
{
public static string GetSerializerInterfaceAssembly()
{
return typeof(INatsSerialize<>).Assembly.GetName().Name!;
}

public void Serialize(IBufferWriter<byte> bufferWriter, string value)
{
var bytes = System.Text.Encoding.UTF8.GetBytes(value);
bufferWriter.Write(bytes);
}

public string? Deserialize(in ReadOnlySequence<byte> buffer)
{
return System.Text.Encoding.UTF8.GetString(buffer.ToArray());
}

public INatsSerializer<string> CombineWith(INatsSerializer<string> next) => this;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="NATS.Net" Version="2.6.0" />
</ItemGroup>

</Project>
Loading