Skip to content

Commit 9a94134

Browse files
committed
refactor(ffi-interop): Add plugin driver and refactor mock server interop methods
1 parent a0f0744 commit 9a94134

File tree

7 files changed

+73
-16
lines changed

7 files changed

+73
-16
lines changed

samples/Grpc/GrpcGreeterClient.Tests/GrpcGreeterClientTest.cs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public async Task ReturnsMismatchWhenNoGrpcClientRequestMade()
2525
// arrange
2626
var host = "0.0.0.0";
2727
var pact = NativeInterop.NewPact("grpc-greeter-client", "grpc-greeter");
28-
var interaction = NativeInterop.NewSyncMessageInteraction(pact, "a request to a plugin");
28+
var interaction = PluginInterop.NewSyncMessageInteraction(pact, "a request to a plugin");
2929
NativeInterop.WithSpecification(pact, PactSpecification.V4);
3030
var content = $@"{{
3131
""pact:proto"":""{Path.Join(Directory.GetCurrentDirectory(), "..", "..", "..", "..", "GrpcGreeterClient", "Protos", "greet.proto").Replace("\\", "\\\\")}"",
@@ -38,10 +38,11 @@ public async Task ReturnsMismatchWhenNoGrpcClientRequestMade()
3838
""message"": ""matching(type, 'Hello foo')""
3939
}}
4040
}}";
41-
PluginInterop.PluginAdd(pact, "protobuf", "0.4.0");
41+
42+
using var pluginDriver = pact.UsePlugin("protobuf", "0.4.0");
4243
PluginInterop.PluginInteractionContents(interaction, 0, "application/grpc", content);
4344

44-
using var driver = MockServer.CreateMockServer(pact, host, 0, "grpc", false);
45+
using var driver = pact.CreateMockServer(host, 0, "grpc", false);
4546
var port = driver.Port;
4647
testOutputHelper.WriteLine("Port: " + port);
4748

@@ -58,7 +59,6 @@ public async Task ReturnsMismatchWhenNoGrpcClientRequestMade()
5859
ErrorString.Should().Be("Did not receive any requests for path 'Greeter/SayHello'");
5960
ExpectedPath.Should().Be("Greeter/SayHello");
6061

61-
PluginInterop.PluginCleanup(pact);
6262
await Task.Delay(1);
6363
}
6464
[Fact]
@@ -67,7 +67,7 @@ public async Task WritesPactWhenGrpcClientRequestMade()
6767
// arrange
6868
var host = "0.0.0.0";
6969
var pact = NativeInterop.NewPact("grpc-greeter-client", "grpc-greeter");
70-
var interaction = NativeInterop.NewSyncMessageInteraction(pact, "a request to a plugin");
70+
var interaction = PluginInterop.NewSyncMessageInteraction(pact, "a request to a plugin");
7171
NativeInterop.WithSpecification(pact, PactSpecification.V4);
7272
var content = $@"{{
7373
""pact:proto"":""{Path.Join(Directory.GetCurrentDirectory(), "..", "..", "..", "..", "GrpcGreeterClient", "Protos", "greet.proto").Replace("\\", "\\\\")}"",
@@ -81,10 +81,10 @@ public async Task WritesPactWhenGrpcClientRequestMade()
8181
}}
8282
}}";
8383

84-
PluginInterop.PluginAdd(pact, "protobuf", "0.4.0");
84+
using var pluginDriver = pact.UsePlugin("protobuf", "0.4.0");
8585
PluginInterop.PluginInteractionContents(interaction, 0, "application/grpc", content);
8686

87-
using var driver = MockServer.CreateMockServer(pact, host, 0, "grpc", false);
87+
using var driver = pact.CreateMockServer(host, 0, "grpc", false);
8888
var port = driver.Port;
8989
testOutputHelper.WriteLine("Port: " + port);
9090

@@ -105,7 +105,6 @@ public async Task WritesPactWhenGrpcClientRequestMade()
105105
MismatchesString.Should().Be("[]");
106106

107107
PactFileWriter.WritePactFileForPort(port, "../../../../pacts");
108-
PluginInterop.PluginCleanup(pact);
109108
}
110109

111110
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
using System;
2+
3+
namespace PactNet.Drivers;
4+
5+
public interface IPluginDriver : IDisposable
6+
{
7+
}

src/PactNet.Interop/NativeInterop.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,6 @@ public static class NativeInterop
5555

5656
#region Messaging Interop Support
5757

58-
[DllImport(DllName, EntryPoint = "pactffi_new_sync_message_interaction")]
59-
public static extern uint NewSyncMessageInteraction(PactHandle pact, string description);
60-
6158
[DllImport(DllName, EntryPoint = "pactffi_with_message_pact_metadata")]
6259
public static extern void WithMessagePactMetadata(PactHandle pact, string @namespace, string name, string value);
6360

src/PactNet.Interop/MockServer.cs renamed to src/PactNet.Interop/PactHandleExtensions.cs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
namespace PactNet.Interop;
55

6-
public static class MockServer
6+
public static class PactHandleExtensions
77
{
88
/// <summary>
99
/// Create the mock server for the current pact
@@ -13,9 +13,9 @@ public static class MockServer
1313
/// <param name="port">Port for the mock server, or null to allocate one automatically</param>
1414
/// <param name="transport">Transport type for the mock server</param>
1515
/// <param name="tls">Enable TLS</param>
16-
/// <returns>Mock server port</returns>
16+
/// <returns>IMockServerDriver</returns>
1717
/// <exception cref="InvalidOperationException">Failed to start mock server</exception>
18-
public static IMockServerDriver CreateMockServer(PactHandle pact, string host, int? port, string transport, bool tls)
18+
public static IMockServerDriver CreateMockServer(this PactHandle pact, string host, int? port, string transport, bool tls)
1919
{
2020
int result = MockServerInterop.CreateMockServerForTransport(pact, host, (ushort)port.GetValueOrDefault(0), transport, null);
2121

@@ -34,4 +34,23 @@ public static IMockServerDriver CreateMockServer(PactHandle pact, string host, i
3434
_ => new InvalidOperationException($"Unknown mock server error: {result}")
3535
};
3636
}
37+
38+
39+
public static IPluginDriver UsePlugin(this PactHandle pact, string plugInName, string pluginVersion)
40+
{
41+
uint result = PluginInterop.PluginAdd(pact, plugInName, pluginVersion);
42+
43+
if (result == 0)
44+
{
45+
return new PluginDriver(pact);
46+
}
47+
48+
throw result switch
49+
{
50+
1 => new InvalidOperationException("The pact reference library panicked."),
51+
2 => new InvalidOperationException("Failed to load the plugin."),
52+
3 => new InvalidOperationException("Pact Handle is not valid."),
53+
_ => new InvalidOperationException($"Unknown mock server error: {result}")
54+
};
55+
}
3756
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using System;
2+
using PactNet.Drivers;
3+
4+
namespace PactNet.Interop;
5+
6+
internal class PluginDriver(PactHandle pact) : IPluginDriver
7+
{
8+
/// <summary>
9+
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
10+
/// </summary>
11+
public void Dispose()
12+
{
13+
this.ReleaseUnmanagedResources();
14+
GC.SuppressFinalize(this);
15+
}
16+
17+
/// <summary>
18+
/// Allows an object to try to free resources and perform other cleanup operations before it is reclaimed by garbage collection.
19+
/// </summary>
20+
~PluginDriver()
21+
{
22+
this.ReleaseUnmanagedResources();
23+
}
24+
25+
/// <summary>
26+
/// Release unmanaged resources
27+
/// </summary>
28+
private void ReleaseUnmanagedResources()
29+
{
30+
PluginInterop.PluginCleanup(pact);
31+
}
32+
}

src/PactNet.Interop/PluginInterop.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@ public class PluginInterop
66
{
77
private const string DllName = "pact_ffi";
88

9+
[DllImport(DllName, EntryPoint = "pactffi_new_sync_message_interaction")]
10+
public static extern InteractionHandle NewSyncMessageInteraction(PactHandle pact, string description);
11+
912
[DllImport(DllName, EntryPoint = "pactffi_using_plugin")]
1013
public static extern uint PluginAdd(PactHandle pact, string name, string version);
1114

1215
[DllImport(DllName, EntryPoint = "pactffi_interaction_contents")]
13-
public static extern uint PluginInteractionContents(uint interaction, InteractionPart part, string contentType, string body);
16+
public static extern uint PluginInteractionContents(InteractionHandle interaction, InteractionPart part, string contentType, string body);
1417

1518
[DllImport(DllName, EntryPoint = "pactffi_cleanup_plugins")]
1619
public static extern void PluginCleanup(PactHandle pact);

src/PactNet/Drivers/HttpPactDriver.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public IHttpInteractionDriver NewHttpInteraction(string description)
3838
/// <param name="tls">Enable TLS</param>
3939
/// <returns>Mock server port</returns>
4040
/// <exception cref="InvalidOperationException">Failed to start mock server</exception>
41-
public IMockServerDriver CreateMockServer(string host, int? port, bool tls) => MockServer.CreateMockServer(this.pact, host, port, "http", tls);
41+
public IMockServerDriver CreateMockServer(string host, int? port, bool tls) => this.pact.CreateMockServer(host, port, "http", tls);
4242

4343
public void WritePactFile(string directory) => PactFileWriter.WritePactFile(this.pact, directory);
4444
}

0 commit comments

Comments
 (0)