diff --git a/RabbitMQ.AMQP.Client/IEnvironment.cs b/RabbitMQ.AMQP.Client/IEnvironment.cs index 6993868..258b9be 100644 --- a/RabbitMQ.AMQP.Client/IEnvironment.cs +++ b/RabbitMQ.AMQP.Client/IEnvironment.cs @@ -2,38 +2,42 @@ // and the Mozilla Public License, version 2.0. // Copyright (c) 2017-2024 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. -using System.Collections.ObjectModel; using System.Threading.Tasks; namespace RabbitMQ.AMQP.Client { /// - /// Interface to create IConnections and manage them. + /// + /// The is the main entry point to a node or a cluster of nodes. + /// + /// + /// The method allows creating instances. + /// An application is expected to maintain a single instance and to close that instance + /// upon application exit. + /// + /// + /// instances are expected to be thread-safe. + /// /// public interface IEnvironment { /// - /// Create a new connection with the given connection settings. + /// Create a new with the given connection settings. /// /// - /// IConnection + /// instance. public Task CreateConnectionAsync(ConnectionSettings connectionSettings); /// - /// Create a new connection with the default connection settings. + /// Create a new with the default connection settings. /// - /// IConnection + /// instance. public Task CreateConnectionAsync(); /// - /// Get all connections. + /// Close this environment and its resources. /// - public ReadOnlyCollection GetConnections(); - - /// - /// Close all connections. - /// - /// + /// // TODO cancellation token Task CloseAsync(); } diff --git a/RabbitMQ.AMQP.Client/Impl/AmqpEnvironment.cs b/RabbitMQ.AMQP.Client/Impl/AmqpEnvironment.cs index c3c3e72..df358a1 100644 --- a/RabbitMQ.AMQP.Client/Impl/AmqpEnvironment.cs +++ b/RabbitMQ.AMQP.Client/Impl/AmqpEnvironment.cs @@ -3,13 +3,21 @@ // Copyright (c) 2017-2024 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. using System.Collections.Concurrent; -using System.Collections.ObjectModel; +using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace RabbitMQ.AMQP.Client.Impl { + /// + /// + /// is the implementation of . + /// + /// + /// The method allows creating instances. + /// + /// public class AmqpEnvironment : IEnvironment { private ConnectionSettings ConnectionSettings { get; } @@ -23,12 +31,24 @@ private AmqpEnvironment(ConnectionSettings connectionSettings, IMetricsReporter? _metricsReporter = metricsReporter; } - // TODO to play nicely with IoC containers, we should not have static Create methods + /// + /// Create a new instance, using the provided + /// and optional + /// + /// + /// + /// instance. public static IEnvironment Create(ConnectionSettings connectionSettings, IMetricsReporter? metricsReporter = default) { + // TODO to play nicely with IoC containers, we should not have static Create methods return new AmqpEnvironment(connectionSettings, metricsReporter); } + /// + /// Create a new instance, using the provided . + /// + /// + /// instance. public async Task CreateConnectionAsync(ConnectionSettings connectionSettings) { IConnection c = await AmqpConnection.CreateAsync(connectionSettings, _metricsReporter).ConfigureAwait(false); @@ -49,6 +69,10 @@ public async Task CreateConnectionAsync(ConnectionSettings connecti return c; } + /// + /// Create a new instance, using the . + /// + /// instance. public Task CreateConnectionAsync() { if (ConnectionSettings is null) @@ -59,13 +83,16 @@ public Task CreateConnectionAsync() return CreateConnectionAsync(ConnectionSettings); } - public ReadOnlyCollection GetConnections() => - new(_connections.Values.ToList()); - + /// + /// Close this environment and its resources. + /// + /// // TODO cancellation token public Task CloseAsync() { return Task.WhenAll(_connections.Values.Select(c => c.CloseAsync())); } + + internal IList Connections => _connections.Values.ToList(); } } diff --git a/RabbitMQ.AMQP.Client/PublicAPI.Unshipped.txt b/RabbitMQ.AMQP.Client/PublicAPI.Unshipped.txt index 7b38b66..51477cf 100644 --- a/RabbitMQ.AMQP.Client/PublicAPI.Unshipped.txt +++ b/RabbitMQ.AMQP.Client/PublicAPI.Unshipped.txt @@ -214,7 +214,6 @@ RabbitMQ.AMQP.Client.IEnvironment RabbitMQ.AMQP.Client.IEnvironment.CloseAsync() -> System.Threading.Tasks.Task! RabbitMQ.AMQP.Client.IEnvironment.CreateConnectionAsync() -> System.Threading.Tasks.Task! RabbitMQ.AMQP.Client.IEnvironment.CreateConnectionAsync(RabbitMQ.AMQP.Client.ConnectionSettings! connectionSettings) -> System.Threading.Tasks.Task! -RabbitMQ.AMQP.Client.IEnvironment.GetConnections() -> System.Collections.ObjectModel.ReadOnlyCollection! RabbitMQ.AMQP.Client.IExchangeSpecification RabbitMQ.AMQP.Client.IExchangeSpecification.Argument(string! key, object! value) -> RabbitMQ.AMQP.Client.IExchangeSpecification! RabbitMQ.AMQP.Client.IExchangeSpecification.Arguments(System.Collections.Generic.Dictionary! arguments) -> RabbitMQ.AMQP.Client.IExchangeSpecification! @@ -361,7 +360,6 @@ RabbitMQ.AMQP.Client.Impl.AmqpEnvironment RabbitMQ.AMQP.Client.Impl.AmqpEnvironment.CloseAsync() -> System.Threading.Tasks.Task! RabbitMQ.AMQP.Client.Impl.AmqpEnvironment.CreateConnectionAsync() -> System.Threading.Tasks.Task! RabbitMQ.AMQP.Client.Impl.AmqpEnvironment.CreateConnectionAsync(RabbitMQ.AMQP.Client.ConnectionSettings! connectionSettings) -> System.Threading.Tasks.Task! -RabbitMQ.AMQP.Client.Impl.AmqpEnvironment.GetConnections() -> System.Collections.ObjectModel.ReadOnlyCollection! RabbitMQ.AMQP.Client.Impl.AmqpExchangeSpecification RabbitMQ.AMQP.Client.Impl.AmqpExchangeSpecification.AmqpExchangeSpecification(RabbitMQ.AMQP.Client.Impl.AmqpManagement! management) -> void RabbitMQ.AMQP.Client.Impl.AmqpExchangeSpecification.Argument(string! key, object! value) -> RabbitMQ.AMQP.Client.IExchangeSpecification! diff --git a/Tests/ClusterTests.cs b/Tests/ClusterTests.cs index 1a073a3..8513e6e 100644 --- a/Tests/ClusterTests.cs +++ b/Tests/ClusterTests.cs @@ -33,15 +33,17 @@ public async Task CreateConnectionWithEnvironmentAndMultipleUris() ConnectionSettings connectionSettings = connectionSettingBuilder.Build(); IEnvironment env = AmqpEnvironment.Create(connectionSettings); + var amqpEnv = (AmqpEnvironment)env; // Note: by using _connection, the test will dispose the object on teardown _connection = await env.CreateConnectionAsync(); Assert.NotNull(_connection); - Assert.NotEmpty(env.GetConnections()); + + Assert.NotEmpty(amqpEnv.Connections); await env.CloseAsync(); Assert.Equal(State.Closed, _connection.State); - Assert.Empty(env.GetConnections()); + Assert.Empty(amqpEnv.Connections); } } diff --git a/Tests/EnvironmentTests.cs b/Tests/EnvironmentTests.cs index 786da93..5f10beb 100644 --- a/Tests/EnvironmentTests.cs +++ b/Tests/EnvironmentTests.cs @@ -18,82 +18,92 @@ public class EnvironmentTests(ITestOutputHelper testOutputHelper) public async Task CreateAConnectionWithEnvironment() { IEnvironment env = AmqpEnvironment.Create(ConnectionSettingsBuilder.Create().Build()); + var amqpEnv = (AmqpEnvironment)env; + IConnection connection = await env.CreateConnectionAsync(); + Assert.NotNull(connection); - Assert.NotEmpty(env.GetConnections()); + Assert.NotEmpty(amqpEnv.Connections); await env.CloseAsync(); Assert.Equal(State.Closed, connection.State); - Assert.Empty(env.GetConnections()); + Assert.Empty(amqpEnv.Connections); } [Fact] public async Task CreateMoreConnectionsWithDifferentParametersEnvironment() { string envConnectionName = "EnvironmentConnection_" + Guid.NewGuid(); + IEnvironment env = AmqpEnvironment.Create( ConnectionSettingsBuilder.Create().ContainerId(envConnectionName).Build()); + var amqpEnv = (AmqpEnvironment)env; IConnection connection = await env.CreateConnectionAsync(); + Assert.NotNull(connection); await WaitUntilConnectionIsOpen(envConnectionName); - Assert.NotEmpty(env.GetConnections()); - Assert.Single(env.GetConnections()); + Assert.NotEmpty(amqpEnv.Connections); + Assert.Single(amqpEnv.Connections); string envConnectionName2 = "EnvironmentConnection2_" + Guid.NewGuid(); IConnection connection2 = await env.CreateConnectionAsync( ConnectionSettingsBuilder.Create().ContainerId(envConnectionName2).Build()); Assert.NotNull(connection2); - Assert.Equal(2, env.GetConnections().Count); + Assert.Equal(2, amqpEnv.Connections.Count); await WaitUntilConnectionIsOpen(envConnectionName2); await env.CloseAsync(); Assert.Equal(State.Closed, connection.State); Assert.Equal(State.Closed, connection2.State); - Assert.Empty(env.GetConnections()); + Assert.Empty(amqpEnv.Connections); } [Fact] public async Task CloseConnectionsIndividually() { string envConnectionName = "EnvironmentConnection_" + Guid.NewGuid(); + IEnvironment env = AmqpEnvironment.Create( ConnectionSettingsBuilder.Create().ContainerId(envConnectionName).Build()); + var amqpEnv = (AmqpEnvironment)env; + IConnection connection = await env.CreateConnectionAsync(); + await WaitUntilConnectionIsOpen(envConnectionName); - Assert.Single(env.GetConnections()); - Assert.Equal(1, env.GetConnections()[0].Id); + Assert.Single(amqpEnv.Connections); + Assert.Equal(1, amqpEnv.Connections[0].Id); string envConnectionName2 = "EnvironmentConnection2_" + Guid.NewGuid().ToString(); IConnection connection2 = await env.CreateConnectionAsync( ConnectionSettingsBuilder.Create().ContainerId(envConnectionName2).Build()); - Assert.Equal(2, env.GetConnections().Count); - Assert.Equal(2, env.GetConnections()[1].Id); + Assert.Equal(2, amqpEnv.Connections.Count); + Assert.Equal(2, amqpEnv.Connections[1].Id); await WaitUntilConnectionIsOpen(envConnectionName2); string envConnectionName3 = "EnvironmentConnection3_" + Guid.NewGuid().ToString(); IConnection connection3 = await env.CreateConnectionAsync( ConnectionSettingsBuilder.Create().ContainerId(envConnectionName3).Build()); - Assert.Equal(3, env.GetConnections().Count); - Assert.Equal(3, env.GetConnections()[2].Id); + Assert.Equal(3, amqpEnv.Connections.Count); + Assert.Equal(3, amqpEnv.Connections[2].Id); await WaitUntilConnectionIsOpen(envConnectionName3); // closing await connection.CloseAsync(); Assert.Equal(State.Closed, connection.State); - Assert.Equal(2, env.GetConnections().Count); + Assert.Equal(2, amqpEnv.Connections.Count); await WaitUntilConnectionIsClosed(envConnectionName); await connection2.CloseAsync(); Assert.Equal(State.Closed, connection2.State); - Assert.Single(env.GetConnections()); + Assert.Single(amqpEnv.Connections); await WaitUntilConnectionIsClosed(envConnectionName2); await connection3.CloseAsync(); Assert.Equal(State.Closed, connection3.State); await WaitUntilConnectionIsClosed(envConnectionName3); - Assert.Empty(env.GetConnections()); + Assert.Empty(amqpEnv.Connections); await env.CloseAsync(); } }