Skip to content

Commit

Permalink
Merge pull request #34 from shepherrrd/main
Browse files Browse the repository at this point in the history
Add Unit Tests for ApiToolkitClientFactory Implementation and Interface Definition for IApiToolkitClientFactory
  • Loading branch information
dawkaka authored Aug 11, 2024
2 parents f27ba9b + 99b6c27 commit c5c51bb
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 2 deletions.
32 changes: 31 additions & 1 deletion ApiToolKit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System.Diagnostics;
using Microsoft.Extensions.DependencyInjection;
using System.Text.Json;
using static System.Web.HttpUtility;

Expand Down Expand Up @@ -424,6 +425,31 @@ public class ATError
public string StackTrace { get; set; }
}

public interface IApiToolkitClientFactory
{
HttpClient CreateClient(ATOptions options);
}

public class ApiToolkitClientFactory : IApiToolkitClientFactory
{
private readonly IHttpClientFactory _httpClientFactory;
private readonly IServiceProvider _serviceProvider;

public ApiToolkitClientFactory(IHttpClientFactory httpClientFactory, IServiceProvider serviceProvider)
{
_httpClientFactory = httpClientFactory;
_serviceProvider = serviceProvider;
}

public HttpClient CreateClient(ATOptions options)
{
var client = _httpClientFactory.CreateClient();

var handler = _serviceProvider.GetRequiredService<ObservingHandler>();
handler.SetOptions(options);
return new HttpClient(handler);
}
}

public class ATOptions
{
Expand All @@ -436,9 +462,13 @@ public class ObservingHandler : DelegatingHandler
{
private readonly HttpContext _context;
private readonly Func<Payload, Task> _publishMessageAsync;
private readonly ATOptions _options;
private ATOptions _options;
private readonly string _project_id;
private readonly string? _msg_id;

Check warning on line 467 in ApiToolKit.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
public void SetOptions(ATOptions options)
{
_options = options;
}
public ObservingHandler(Func<Payload, Task> publishMessage, string project_id, HttpContext? httpContext = null, ATOptions? options = null) : base(new HttpClientHandler())

Check warning on line 472 in ApiToolKit.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 472 in ApiToolKit.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
{
_context = httpContext ?? throw new ArgumentNullException(nameof(httpContext));
Expand Down
75 changes: 74 additions & 1 deletion ApiToolkitTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.Builder;

using Moq;
using System.Net.Http;
using Microsoft.Extensions.DependencyInjection;
public class RedactTests
{
[Test]
Expand Down Expand Up @@ -208,3 +210,74 @@ public async Task MiddlewareTest_ReturnsNotFoundForRequest()
}
}


public class ApiToolkitClientFactoryTests
{
private Mock<IHttpClientFactory> _httpClientFactoryMock;
private Mock<IServiceProvider> _serviceProviderMock;
private Mock<ObservingHandler> _observingHandlerMock;
private IApiToolkitClientFactory _apiToolkitClientFactory;

[SetUp]
public void SetUp()
{
_httpClientFactoryMock = new Mock<IHttpClientFactory>();
_serviceProviderMock = new Mock<IServiceProvider>();
_observingHandlerMock = new Mock<ObservingHandler>();

// Set up the service provider to return the observing handler mock
_serviceProviderMock
.Setup(sp => sp.GetService(typeof(ObservingHandler)))
.Returns(_observingHandlerMock.Object);

// Initialize the ApiToolkitClientFactory with mocks
_apiToolkitClientFactory = new ApiToolkitClientFactory(_httpClientFactoryMock.Object, _serviceProviderMock.Object);
}

[Test]
public void CreateClient_ShouldReturnHttpClient_WithConfiguredHandler()
{
// Arrange
var options = new ATOptions
{
PathWildCard = "/posts/{id}",
RedactHeaders = new List<string> { "User-Agent" },
RedactRequestBody = new List<string> { "$.user.password" },
RedactResponseBody = new List<string> { "$.user.data.email" }
};

// Act
var client = _apiToolkitClientFactory.CreateClient(options);

// Assert
Assert.NotNull(client);
_observingHandlerMock.Verify(h => h.SetOptions(options), Times.Once);
}

[Test]
public void CreateClient_ShouldUseObservingHandler_FromServiceProvider()
{
// Act
var client = _apiToolkitClientFactory.CreateClient(new ATOptions());

// Assert
_serviceProviderMock.Verify(sp => sp.GetService(typeof(ObservingHandler)), Times.Once);
}

[Test]
public void CreateClient_ShouldThrowException_WhenHandlerNotRegistered()
{
// Arrange
var invalidServiceProvider = new Mock<IServiceProvider>();
invalidServiceProvider.Setup(sp => sp.GetService(typeof(ObservingHandler)))
.Returns(null); // Simulate missing handler registration

var factory = new ApiToolkitClientFactory(_httpClientFactoryMock.Object, invalidServiceProvider.Object);

// Act & Assert
Assert.Throws<NullReferenceException>(() => factory.CreateClient(new ATOptions()));
}
}



65 changes: 65 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ Next, initialize APItoolkit in your application's entry point (e.g., `Program.cs
using ApiToolkit.Net;

// Initialize the APItoolkit client
builder.Services.AddTransient<ObservingHandler>();

// Register the custom API Toolkit Client Factory
builder.Services.AddSingleton<IApiToolkitClientFactory, ApiToolkitClientFactory>();

var config = new Config
{
ApiKey = "{ENTER_YOUR_API_KEY_HERE}",
Expand All @@ -60,6 +65,66 @@ app.Use(async (context, next) =>
# ...
```

## Usage

You can now use the IApiToolKitClientFactory Interface to directly make your Http requests

```csharp
public class MyService
{
private readonly IApiToolkitClientFactory _apiToolkitClientFactory;

public MyService(IApiToolkitClientFactory apiToolkitClientFactory)
{
_apiToolkitClientFactory = apiToolkitClientFactory;
}

public async Task<string> GetPostAsync()
{
var options = new ATOptions
{
PathWildCard = "/posts/{id}",
RedactHeaders = new[] { "User-Agent" },
RedactRequestBody = new[] { "$.user.password" },
RedactResponseBody = new[] { "$.user.data.email" }
};

var client = _apiToolkitClientFactory.CreateClient(options);
var response = await client.GetAsync("https://jsonplaceholder.typicode.com/posts/1");
return await response.Content.ReadAsStringAsync();
}
}
```

Traditional Middleware Setup
If you prefer to set up the middleware traditionally, here's how you can initialize APItoolkit in your application's entry point (e.g., Program.cs):

```csharp
using ApiToolkit.Net;

// Initialize the APItoolkit client
var config = new Config
{
ApiKey = "{ENTER_YOUR_API_KEY_HERE}",
Debug = false,
Tags = new List<string> { "environment: production", "region: us-east-1" },
ServiceVersion: "v2.0",
};
var client = await APIToolkit.NewClientAsync(config);

// Register the middleware to use the initialized client
app.Use(async (context, next) =>
{
var apiToolkit = new APIToolkit(next, client);
await apiToolkit.InvokeAsync(context);
});

// app.UseEndpoint(..)
// other middleware and logic
// ...
```


> [!NOTE]
>
> - Please make sure the APItoolkit middleware is added before `UseEndpoint` and other middleware are initialized.
Expand Down
1 change: 1 addition & 0 deletions apitoolkit-dotnet.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="7.0.5" />
<!-- Deprecated -->
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.2.7" />
<PackageReference Include="Moq" Version="4.20.70" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.2" />
<PackageReference Include="NUnit" Version="3.13.3" />
Expand Down

0 comments on commit c5c51bb

Please sign in to comment.