Skip to content

Commit

Permalink
Allow controlling the disposal of provided transport and HTTP client …
Browse files Browse the repository at this point in the history
…instances (#487)

* Add parameter to control disposal of provided HTTP client when creating transport.

* Add a parameter to control disposal of provided instance when creating DB client.

* Simplify tests by using Mock instances.
  • Loading branch information
DiscoPYF authored Jan 3, 2024
1 parent 97f621d commit e0b7890
Show file tree
Hide file tree
Showing 5 changed files with 206 additions and 30 deletions.
84 changes: 84 additions & 0 deletions arangodb-net-standard.Test/ArangoDBClientTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
using ArangoDBNetStandard;
using ArangoDBNetStandard.Transport;
using Moq;
using Moq.Protected;
using System.Net.Http;
using Xunit;

namespace ArangoDBNetStandardTest
{
public class ArangoDBClientTest
{
public ArangoDBClientTest()
{
}

[Fact]
public void Dispose_ShouldDisposeTransport_WhenTransportDisposalIsNotSuppressed()
{
var mockTransport = new Mock<IApiClientTransport>();

var dbClient = new ArangoDBClient(
mockTransport.Object,
suppressTransportDisposal: false);

// Act
dbClient.Dispose();

// Assert
mockTransport.Verify(client => client.Dispose(), Times.Once);
}

[Fact]
public void Dispose_ShouldNotDisposeTransport_WhenTransportDisposalIsSuppressed()
{
var mockTransport = new Mock<IApiClientTransport>();

var dbClient = new ArangoDBClient(
mockTransport.Object,
suppressTransportDisposal: true);

// Act
dbClient.Dispose();

// Assert
mockTransport.Verify(transport => transport.Dispose(), Times.Never);
}

[Fact]
public void Dispose_ShouldDisposeHttpClient_WhenClientDisposalIsNotSuppressed()
{
var mockMessageHandler = new Mock<HttpMessageHandler>();

var httpClient = new HttpClient(mockMessageHandler.Object);

var dbClient = new ArangoDBClient(
httpClient,
suppressClientDisposal: false);

// Act
dbClient.Dispose();

// Assert
mockMessageHandler.Protected().Verify("Dispose", Times.Once(), true, true);
}

[Fact]
public void Dispose_ShouldNotDisposeHttpClient_WhenClientDisposalIsSuppressed()
{
var mockMessageHandler = new Mock<HttpMessageHandler>();

var httpClient = new HttpClient(mockMessageHandler.Object);

var dbClient = new ArangoDBClient(
httpClient,
suppressClientDisposal: true);

// Act
dbClient.Dispose();

// Assert
mockMessageHandler.Protected().Verify("Dispose", Times.Never(), true, true);
}
}
}
72 changes: 58 additions & 14 deletions arangodb-net-standard.Test/Transport/Http/HttpApiTransportTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,43 @@
using ArangoDBNetStandard.AuthApi.Models;
using ArangoDBNetStandard.DatabaseApi;
using ArangoDBNetStandard.Transport.Http;
using Moq;
using Moq.Protected;
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Xunit;

namespace ArangoDBNetStandardTest.Transport.Http
{
public class HttpApiTransportTest: IClassFixture<HttpApiTransportTestFixture>
public class HttpApiTransportTest : IClassFixture<HttpApiTransportTestFixture>
{
private HttpApiTransportTestFixture _fixture;
private readonly HttpApiTransportTestFixture _fixture;

private readonly Uri _hostUri;

public HttpApiTransportTest(HttpApiTransportTestFixture fixture)
{
_fixture = fixture;
_hostUri = new Uri($"http://{fixture.ArangoDbHost}:{fixture.ArangoDbPort}/");
}

[Fact]
public async Task UseVpack_ShouldSucceed()
{
string arangodbBaseUrl = $"http://{_fixture.ArangoDbHost}:{_fixture.ArangoDbPort}/";
using (var transport = HttpApiTransport.UsingBasicAuth(
new Uri(arangodbBaseUrl),
nameof(HttpApiTransportTest),
"root",
"root"))
_hostUri,
_fixture.DatabaseName,
_fixture.Username,
_fixture.Password))
{
transport.UseVPackContentType();
string docUrl = arangodbBaseUrl + "_db/" + nameof(HttpApiTransportTest) + $"/_admin/echo";
using (var response = await transport.GetAsync(docUrl))
using (var response = await transport.GetAsync("_admin/echo"))
{
Assert.True(
response.IsSuccessStatusCode,
$"Error response. Status code: {response.StatusCode}");

Assert.Equal("application/x-velocypack", response.Content.Headers.ContentType.MediaType);
}
}
Expand All @@ -41,9 +49,8 @@ public async Task UseVpack_ShouldSucceed()
public async Task SetJwt_ShouldSucceed()
{
string jwtToken = null;
string arangodbBaseUrl = $"http://{_fixture.ArangoDbHost}:{_fixture.ArangoDbPort}/";
using (var transport = HttpApiTransport.UsingNoAuth(
new Uri(arangodbBaseUrl),
_hostUri,
nameof(HttpApiTransportTest)))
{
var authClient = new AuthApiClient(transport);
Expand All @@ -70,9 +77,8 @@ public async Task SetJwt_ShouldSucceed()
public async Task UsingJwtAuth_ShouldSucceed()
{
string jwtToken = null;
string arangodbBaseUrl = $"http://{_fixture.ArangoDbHost}:{_fixture.ArangoDbPort}/";
using (var transport = HttpApiTransport.UsingNoAuth(
new Uri(arangodbBaseUrl),
_hostUri,
nameof(HttpApiTransportTest)))
{
var authClient = new AuthApiClient(transport);
Expand All @@ -95,7 +101,7 @@ public async Task UsingJwtAuth_ShouldSucceed()

// Use token in a new transport created via `UsingJwtAuth`.
using (var transport = HttpApiTransport.UsingJwtAuth(
new Uri(arangodbBaseUrl),
_hostUri,
nameof(HttpApiTransportTest),
jwtToken))
{
Expand All @@ -104,5 +110,43 @@ public async Task UsingJwtAuth_ShouldSucceed()
Assert.NotEmpty(userDatabasesResponse.Result);
}
}

[Fact]
public void Dispose_ShouldDisposeHttpClient_WhenDisposalIsNotSuppressed()
{
var mockMessageHandler = new Mock<HttpMessageHandler>();

var httpClient = new HttpClient(mockMessageHandler.Object);

var transport = new HttpApiTransport(
httpClient,
HttpContentType.Json,
suppressClientDisposal: false);

// Act
transport.Dispose();

// Assert
mockMessageHandler.Protected().Verify("Dispose", Times.Once(), true, true);
}

[Fact]
public void Dispose_ShouldNotDisposeHttpClient_WhenDisposalIsSuppressed()
{
var mockMessageHandler = new Mock<HttpMessageHandler>();

var httpClient = new HttpClient(mockMessageHandler.Object);

var transport = new HttpApiTransport(
httpClient,
HttpContentType.Json,
suppressClientDisposal: true);

// Act
transport.Dispose();

// Assert
mockMessageHandler.Protected().Verify("Dispose", Times.Never(), true, true);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,18 @@

namespace ArangoDBNetStandardTest.Transport.Http
{
public class HttpApiTransportTestFixture: ApiClientTestFixtureBase
public class HttpApiTransportTestFixture : ApiClientTestFixtureBase
{
public string DatabaseName { get; } = nameof(HttpApiTransportTest);

public string Username { get; } = "xyzabc";
public string Password { get; } = "abcxyz";

public override async Task InitializeAsync()
{
await base.InitializeAsync();
await CreateDatabase(
nameof(HttpApiTransportTest),
DatabaseName,
new List<DatabaseUser>
{
new DatabaseUser
Expand Down
56 changes: 44 additions & 12 deletions arangodb-net-standard/ArangoDBClient.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Net.Http;
using ArangoDBNetStandard.AdminApi;
using ArangoDBNetStandard.AdminApi;
using ArangoDBNetStandard.AnalyzerApi;
using ArangoDBNetStandard.AqlFunctionApi;
using ArangoDBNetStandard.AuthApi;
Expand All @@ -17,6 +16,7 @@
using ArangoDBNetStandard.Transport.Http;
using ArangoDBNetStandard.UserApi;
using ArangoDBNetStandard.ViewApi;
using System.Net.Http;

namespace ArangoDBNetStandard
{
Expand All @@ -25,6 +25,8 @@ namespace ArangoDBNetStandard
/// </summary>
public class ArangoDBClient : IArangoDBClient
{
protected readonly bool _suppressTransportDisposal;

/// <summary>
/// The transport client used to communicate with the ArangoDB host.
/// </summary>
Expand Down Expand Up @@ -79,7 +81,7 @@ public class ArangoDBClient : IArangoDBClient
/// Index management API
/// </summary>
public IIndexApiClient Index { get; private set; }

/// <summary>
/// Bulk Operations API.
/// </summary>
Expand All @@ -89,12 +91,12 @@ public class ArangoDBClient : IArangoDBClient
/// View management API.
/// </summary>
public IViewApiClient View { get; private set; }

/// <summary>
/// Analyzer management API.
/// </summary>
public IAnalyzerApiClient Analyzer { get; private set; }
public IAnalyzerApiClient Analyzer { get; private set; }

/// <summary>
/// Admin management API
/// </summary>
Expand All @@ -110,9 +112,18 @@ public class ArangoDBClient : IArangoDBClient
/// <see cref="HttpClient"/> instance, using the default JSON serialization.
/// </summary>
/// <param name="client"></param>
public ArangoDBClient(HttpClient client)
/// <param name="suppressClientDisposal">
/// True to prevent disposal of the provided <see cref="HttpClient"/> instance
/// when <see cref="ArangoDBClient"/> is disposed.
/// Default is false, to avoid a breaking change.
/// </param>
public ArangoDBClient(HttpClient client, bool suppressClientDisposal = false)
{
_transport = new HttpApiTransport(client, HttpContentType.Json);
_transport = new HttpApiTransport(
client,
HttpContentType.Json,
suppressClientDisposal);
_suppressTransportDisposal = false;

var serialization = new JsonNetApiClientSerialization();

Expand All @@ -124,9 +135,17 @@ public ArangoDBClient(HttpClient client)
/// using the provided transport layer and the default JSON serialization.
/// </summary>
/// <param name="transport">The ArangoDB transport layer implementation.</param>
public ArangoDBClient(IApiClientTransport transport)
/// <param name="suppressTransportDisposal">
/// True to prevent disposal of the provided <see cref="IApiClientTransport"/> instance
/// when <see cref="ArangoDBClient"/> is disposed.
/// Default is false, to avoid a breaking change.
/// </param>
public ArangoDBClient(
IApiClientTransport transport,
bool suppressTransportDisposal = false)
{
_transport = transport;
_suppressTransportDisposal = suppressTransportDisposal;

var serialization = new JsonNetApiClientSerialization();

Expand All @@ -139,9 +158,18 @@ public ArangoDBClient(IApiClientTransport transport)
/// </summary>
/// <param name="transport">The ArangoDB transport layer implementation.</param>
/// <param name="serialization">The serialization layer implementation.</param>
public ArangoDBClient(IApiClientTransport transport, IApiClientSerialization serialization)
/// <param name="suppressTransportDisposal">
/// True to prevent disposal of the provided <see cref="IApiClientTransport"/> instance
/// when <see cref="ArangoDBClient"/> is disposed.
/// Default is false, to avoid a breaking change.
/// </param>
public ArangoDBClient(
IApiClientTransport transport,
IApiClientSerialization serialization,
bool suppressTransportDisposal = false)
{
_transport = transport;
_suppressTransportDisposal = suppressTransportDisposal;

InitializeApis(_transport, serialization);
}
Expand All @@ -151,6 +179,10 @@ public ArangoDBClient(IApiClientTransport transport, IApiClientSerialization ser
/// </summary>
public void Dispose()
{
if (_suppressTransportDisposal)
{
return;
}
_transport.Dispose();
}

Expand All @@ -168,9 +200,9 @@ private void InitializeApis(
Graph = new GraphApiClient(transport, serialization);
User = new UserApiClient(transport, serialization);
Index = new IndexApiClient(transport, serialization);
BulkOperations = new BulkOperationsApiClient(transport, serialization);
BulkOperations = new BulkOperationsApiClient(transport, serialization);
View = new ViewApiClient(transport, serialization);
Analyzer = new AnalyzerApiClient(transport, serialization);
Analyzer = new AnalyzerApiClient(transport, serialization);
Admin = new AdminApiClient(transport, serialization);
Pregel = new PregelApiClient(transport, serialization);
}
Expand Down
Loading

0 comments on commit e0b7890

Please sign in to comment.