public void GetUriSchemeUnderstandsAmqpConnectionTypes(EventHubsTransportType transportType) { var scheme = transportType.GetUriScheme(); Assert.That(scheme, Is.Not.Null.And.Not.Empty); Assert.That(transportType.GetUriScheme(), Contains.Substring("amqp")); }
/// <summary> /// Initializes a new instance of the <see cref="AmqpConnectionScope"/> class. /// </summary> /// /// <param name="serviceEndpoint">Endpoint for the Event Hubs service to which the scope is associated.</param> /// <param name="eventHubName"> The name of the Event Hub to which the scope is associated</param> /// <param name="credential">The credential to use for authorization with the Event Hubs service.</param> /// <param name="transport">The transport to use for communication.</param> /// <param name="proxy">The proxy, if any, to use for communication.</param> /// <param name="identifier">The identifier to assign this scope; if not provided, one will be generated.</param> /// public AmqpConnectionScope(Uri serviceEndpoint, string eventHubName, EventHubTokenCredential credential, EventHubsTransportType transport, IWebProxy proxy, string identifier = default) { Argument.AssertNotNull(serviceEndpoint, nameof(serviceEndpoint)); Argument.AssertNotNullOrEmpty(eventHubName, nameof(eventHubName)); Argument.AssertNotNull(credential, nameof(credential)); ValidateTransport(transport); ServiceEndpoint = serviceEndpoint; EventHubName = eventHubName; Transport = transport; Proxy = proxy; TokenProvider = new CbsTokenProvider(new EventHubTokenCredential(credential, serviceEndpoint.ToString()), OperationCancellationSource.Token); Id = identifier ?? $"{ eventHubName }-{ Guid.NewGuid().ToString("D", CultureInfo.InvariantCulture).Substring(0, 8) }"; #pragma warning disable CA2214 // Do not call overridable methods in constructors. This internal method is virtual for testing purposes. Task <AmqpConnection> connectionFactory(TimeSpan timeout) => CreateAndOpenConnectionAsync(AmqpVersion, ServiceEndpoint, Transport, Proxy, Id, timeout); #pragma warning restore CA2214 // Do not call overridable methods in constructors ActiveConnection = new FaultTolerantAmqpObject <AmqpConnection>(connectionFactory, CloseConnection); }
public async Task ProducerCanPublishBatches(EventHubsTransportType transportType) { await using (EventHubScope scope = await EventHubScope.CreateAsync(1)) { var connectionString = EventHubsTestEnvironment.Instance.BuildConnectionStringForEventHub(scope.EventHubName); var options = new EventHubProducerClientOptions { EnableIdempotentPartitions = true, ConnectionOptions = new EventHubConnectionOptions { TransportType = transportType } }; await using var producer = new EventHubProducerClient(connectionString, options); var cancellationSource = new CancellationTokenSource(); cancellationSource.CancelAfter(EventHubsTestEnvironment.Instance.TestExecutionTimeLimit); var partition = (await producer.GetPartitionIdsAsync()).First(); var batchOptions = new CreateBatchOptions { PartitionId = partition }; using var firstBatch = await producer.CreateBatchAsync(batchOptions, cancellationSource.Token); firstBatch.TryAdd(EventGenerator.CreateEvents(1).First()); using var secondBatch = await producer.CreateBatchAsync(batchOptions, cancellationSource.Token); secondBatch.TryAdd(EventGenerator.CreateEvents(1).First()); secondBatch.TryAdd(EventGenerator.CreateEvents(1).First()); Assert.That(async() => await producer.SendAsync(firstBatch, cancellationSource.Token), Throws.Nothing, "The first publishing operation was not successful."); Assert.That(async() => await producer.SendAsync(secondBatch, cancellationSource.Token), Throws.Nothing, "The second publishing operation was not successful."); } }
/// <summary> /// Provides a test shim for retrieving the credential that a client was /// created with. /// </summary> /// /// <param name="client">The client to retrieve the credential for.</param> /// /// <returns>The credential with which the client was created.</returns> /// private string BuildResource(EventHubConnection client, EventHubsTransportType transportType, string fullyQualifiedNamespace, string eventHubName) => typeof(EventHubConnection) .GetMethod("BuildAudienceResource", BindingFlags.Static | BindingFlags.NonPublic) .Invoke(client, new object[] { transportType, fullyQualifiedNamespace, eventHubName }) as string;
/// <summary> /// Determines the URI scheme to be used for the given connection type. /// </summary> /// /// <param name="instance">The instance that this method was invoked on.</param> /// /// <returns>The scheme that should be used for the given connection type when forming an associated URI.</returns> /// public static string GetUriScheme(this EventHubsTransportType instance) { switch (instance) { case EventHubsTransportType.AmqpTcp: case EventHubsTransportType.AmqpWebSockets: return(AmqpUriScheme); default: throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.InvalidTransportType, instance.ToString(), nameof(instance))); } }
/// <summary> /// Creates an AMQP connection for a given scope. /// </summary> /// /// <param name="amqpVersion">The version of AMQP to use for the connection.</param> /// <param name="serviceEndpoint">The endpoint for the Event Hubs service to which the scope is associated.</param> /// <param name="transportType">The type of transport to use for communication.</param> /// <param name="proxy">The proxy, if any, to use for communication.</param> /// <param name="scopeIdentifier">The unique identifier for the associated scope.</param> /// <param name="timeout">The timeout to consider when creating the connection.</param> /// /// <returns>An AMQP connection that may be used for communicating with the Event Hubs service.</returns> /// protected virtual async Task <AmqpConnection> CreateAndOpenConnectionAsync(Version amqpVersion, Uri serviceEndpoint, EventHubsTransportType transportType, IWebProxy proxy, string scopeIdentifier, TimeSpan timeout) { var hostName = serviceEndpoint.Host; AmqpSettings amqpSettings = CreateAmpqSettings(AmqpVersion); AmqpConnectionSettings connectionSetings = CreateAmqpConnectionSettings(hostName, scopeIdentifier); TransportSettings transportSettings = transportType.IsWebSocketTransport() ? CreateTransportSettingsForWebSockets(hostName, proxy) : CreateTransportSettingsforTcp(hostName, serviceEndpoint.Port); // Create and open the connection, respecting the timeout constraint // that was received. var stopWatch = Stopwatch.StartNew(); var initiator = new AmqpTransportInitiator(amqpSettings, transportSettings); TransportBase transport = await initiator.ConnectTaskAsync(timeout).ConfigureAwait(false); var connection = new AmqpConnection(transport, amqpSettings, connectionSetings); await OpenAmqpObjectAsync(connection, timeout.CalculateRemaining(stopWatch.Elapsed)).ConfigureAwait(false); stopWatch.Stop(); // Create the CBS link that will be used for authorization. The act of creating the link will associate // it with the connection. new AmqpCbsLink(connection); // When the connection is closed, close each of the links associated with it. EventHandler closeHandler = null; closeHandler = (snd, args) => { foreach (var link in ActiveLinks.Keys) { link.SafeClose(); } connection.Closed -= closeHandler; }; connection.Closed += closeHandler; return(connection); }
public void BuildTransportClientAllowsLegalConnectionTypes(EventHubsTransportType connectionType) { var fullyQualifiedNamespace = "my.eventhubs.com"; var path = "some-hub"; var keyName = "aWonderfulKey"; var key = "ABC4223"; var resource = $"amqps://{ fullyQualifiedNamespace }/{ path }"; var options = new EventHubConnectionOptions { TransportType = connectionType }; var signature = new SharedAccessSignature(resource, keyName, key); var credential = new SharedAccessSignatureCredential(signature); var eventHubCredential = new EventHubTokenCredential(credential, resource); var client = new EventHubConnection(fullyQualifiedNamespace, path, credential); Assert.That(() => client.CreateTransportClient(fullyQualifiedNamespace, path, eventHubCredential, options), Throws.Nothing); }
private static EventHubProducerClientOptions CreateEventHubClientOptions( EventHubConfiguration configuration) { EventHubsTransportType transportType = EventHubsTransportType.AmqpTcp; if (!string.IsNullOrEmpty(configuration.TransportType)) { Enum.TryParse(configuration.TransportType, out transportType); } return(new EventHubProducerClientOptions { ConnectionOptions = new EventHubConnectionOptions { TransportType = transportType } }); }
/// <summary> /// Builds the audience for use in the signature. /// </summary> /// /// <param name="transportType">The type of protocol and transport that will be used for communicating with the Event Hubs service.</param> /// <param name="fullyQualifiedNamespace">The fully qualified Event Hubs namespace. This is likely to be similar to <c>{yournamespace}.servicebus.windows.net</c>.</param> /// <param name="eventHubName">The name of the specific Event Hub to connect the client to.</param> /// /// <returns>The value to use as the audience of the signature.</returns> /// private static string BuildAudienceResource(EventHubsTransportType transportType, string fullyQualifiedNamespace, string eventHubName) { var builder = new UriBuilder(fullyQualifiedNamespace) { Scheme = transportType.GetUriScheme(), Path = eventHubName, Port = -1, Fragment = string.Empty, Password = string.Empty, UserName = string.Empty, }; if (builder.Path.EndsWith("/")) { builder.Path = builder.Path.TrimEnd('/'); } return(builder.Uri.AbsoluteUri.ToLowerInvariant()); }
public async Task ConnectionTransportCanRetrieveProperties(EventHubsTransportType transportType) { var partitionCount = 4; await using (EventHubScope scope = await EventHubScope.CreateAsync(partitionCount)) { var connectionString = TestEnvironment.EventHubsConnectionString; await using (var connection = new TestConnectionWithTransport(connectionString, scope.EventHubName, new EventHubConnectionOptions { TransportType = transportType })) { EventHubProperties properties = await connection.GetPropertiesAsync(); Assert.That(properties, Is.Not.Null, "A set of properties should have been returned."); Assert.That(properties.Name, Is.EqualTo(scope.EventHubName), "The property Event Hub name should match the scope."); Assert.That(properties.PartitionIds.Length, Is.EqualTo(partitionCount), "The properties should have the requested number of partitions."); Assert.That(properties.CreatedOn, Is.EqualTo(DateTimeOffset.UtcNow).Within(TimeSpan.FromSeconds(60)), "The Event Hub should have been created just about now."); } } }
public async Task ConnectionTransportCanRetrievePartitionProperties(EventHubsTransportType transportType) { var partitionCount = 4; await using (EventHubScope scope = await EventHubScope.CreateAsync(partitionCount)) { var options = new EventHubConnectionOptions(); var connectionString = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName); var connectionProperties = ConnectionStringParser.Parse(connectionString); var credential = new SharedAccessSignatureCredential ( new SharedAccessSignature ( $"{ options.TransportType.GetUriScheme() }://{ connectionProperties.Endpoint.Host }/{ connectionProperties.EventHubName }".ToLowerInvariant(), connectionProperties.SharedAccessKeyName, connectionProperties.SharedAccessKey, TimeSpan.FromHours(4) ) ); await using (var connection = new TestConnectionWithTransport(connectionProperties.Endpoint.Host, connectionProperties.EventHubName, credential, new EventHubConnectionOptions { TransportType = transportType })) { var cancellation = new CancellationTokenSource(TimeSpan.FromSeconds(20)); var properties = await connection.GetPropertiesAsync(); var partition = properties.PartitionIds.First(); var partitionProperties = await connection.GetPartitionPropertiesAsync(partition, cancellation.Token); Assert.That(partitionProperties, Is.Not.Null, "A set of partition properties should have been returned."); Assert.That(partitionProperties.Id, Is.EqualTo(partition), "The partition identifier should match."); Assert.That(partitionProperties.EventHubName, Is.EqualTo(connectionProperties.EventHubName).Using((IEqualityComparer <string>)StringComparer.InvariantCultureIgnoreCase), "The Event Hub path should match."); Assert.That(partitionProperties.BeginningSequenceNumber, Is.Not.EqualTo(default(long)), "The beginning sequence number should have been populated."); Assert.That(partitionProperties.LastEnqueuedSequenceNumber, Is.Not.EqualTo(default(long)), "The last sequence number should have been populated."); Assert.That(partitionProperties.LastEnqueuedOffset, Is.Not.EqualTo(default(long)), "The last offset should have been populated."); } } }
/// <summary> /// Initializes a new instance of the <see cref="AmqpConnectionScope"/> class. /// </summary> /// /// <param name="serviceEndpoint">Endpoint for the Event Hubs service to which the scope is associated.</param> /// <param name="eventHubName"> The name of the Event Hub to which the scope is associated</param> /// <param name="credential">The credential to use for authorization with the Event Hubs service.</param> /// <param name="transport">The transport to use for communication.</param> /// <param name="proxy">The proxy, if any, to use for communication.</param> /// <param name="identifier">The identifier to assign this scope; if not provided, one will be generated.</param> /// public AmqpConnectionScope(Uri serviceEndpoint, string eventHubName, EventHubTokenCredential credential, EventHubsTransportType transport, IWebProxy proxy, string identifier = default) { Argument.AssertNotNull(serviceEndpoint, nameof(serviceEndpoint)); Argument.AssertNotNullOrEmpty(eventHubName, nameof(eventHubName)); Argument.AssertNotNull(credential, nameof(credential)); ValidateTransport(transport); ServiceEndpoint = serviceEndpoint; EventHubName = eventHubName; Transport = transport; Proxy = proxy; TokenProvider = new CbsTokenProvider(new EventHubTokenCredential(credential, serviceEndpoint.ToString()), OperationCancellationSource.Token); Id = identifier ?? $"{ eventHubName }-{ Guid.NewGuid().ToString("D").Substring(0, 8) }"; Task <AmqpConnection> connectionFactory(TimeSpan timeout) => CreateAndOpenConnectionAsync(AmqpVersion, ServiceEndpoint, Transport, Proxy, Id, timeout); ActiveConnection = new FaultTolerantAmqpObject <AmqpConnection>(connectionFactory, CloseConnection); }
public async Task PartitionReceiverCanRetrievePartitionProperties(EventHubsTransportType transportType) { var partitionCount = 1; await using (EventHubScope scope = await EventHubScope.CreateAsync(partitionCount)) { var cancellationSource = new CancellationTokenSource(TimeSpan.FromSeconds(20)); var connectionString = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName); var receiverOptions = new PartitionReceiverOptions { ConnectionOptions = new EventHubConnectionOptions { TransportType = transportType } }; var partitionId = default(string); await using (var producer = new EventHubProducerClient(connectionString)) { partitionId = (await producer.GetPartitionIdsAsync(cancellationSource.Token)).First(); } await using (var receiver = new PartitionReceiver(EventHubConsumerClient.DefaultConsumerGroupName, partitionId, EventPosition.Earliest, connectionString, receiverOptions)) { var partitionProperties = await receiver.GetPartitionPropertiesAsync(cancellationSource.Token); Assert.That(cancellationSource.IsCancellationRequested, Is.False, "The cancellation token should not have been signaled."); Assert.That(partitionProperties, Is.Not.Null, "A set of partition properties should have been returned."); Assert.That(partitionProperties.Id, Is.EqualTo(partitionId), "The partition identifier should match."); Assert.That(partitionProperties.EventHubName, Is.EqualTo(scope.EventHubName).Using((IEqualityComparer <string>)StringComparer.InvariantCultureIgnoreCase), "The Event Hub path should match."); Assert.That(partitionProperties.BeginningSequenceNumber, Is.Not.EqualTo(default(long)), "The beginning sequence number should have been populated."); Assert.That(partitionProperties.LastEnqueuedSequenceNumber, Is.Not.EqualTo(default(long)), "The last sequence number should have been populated."); Assert.That(partitionProperties.LastEnqueuedOffset, Is.Not.EqualTo(default(long)), "The last offset should have been populated."); } } }
public void IsWebSocketTransportRecognizesSocketTransports(EventHubsTransportType transportType, bool expectedResult) { Assert.That(transportType.IsWebSocketTransport(), Is.EqualTo(expectedResult)); }
/// <summary> /// Determines whether the specified transport makes use of web sockets. /// </summary> /// /// <param name="instance">The instance that this method was invoked on.</param> /// /// <returns><c>true</c> if the transport uses web sockets; otherwise, <c>false</c>.</returns> /// public static bool IsWebSocketTransport(this EventHubsTransportType instance) => (instance == EventHubsTransportType.AmqpWebSockets);