-
-
Notifications
You must be signed in to change notification settings - Fork 301
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Add Azure Event Hubs module #1342
base: develop
Are you sure you want to change the base?
feat: Add Azure Event Hubs module #1342
Conversation
# Conflicts: # Directory.Packages.props # Testcontainers.sln
This reverts commit 79d4b40.
…to event hubs emulator
✅ Deploy Preview for testcontainers-dotnet ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
TODO:
|
@HofmeisterAn ; Can you please help here with assigning relevant maintainers for review. Thanks. |
[Fact] | ||
[Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))] | ||
|
||
public async Task SendEvents() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add tests for Kafka Send/Receive as well? Refer the Emulator Kafka sample for more details.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can do it and also include in the documentation :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did the test & documentation but I need your help in there, its not working unfortunately. Maybe I did something wrong, but i'm not familiar with Kafka.
…ture/add-azure-event-hubs
…ture/add-azure-event-hubs
… into fork/rafek1241/feature/add-azure-event-hubs
I reviewed most of the PR and created a PR with a few suggestions. See: rafek1241#1. |
…azure-event-hubs Fork/rafek1241/feature/add azure event hubs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR once again! I have a few small change requests. I'm happy to merge the PR afterward. Thanks 🙏.
src/Testcontainers.EventHubs/Configuration/ConfigurationBuilder.cs
Outdated
Show resolved
Hide resolved
/// <inheritdoc /> | ||
private sealed class WaitTwoSeconds : IWaitUntil | ||
{ | ||
/// <inheritdoc /> | ||
public async Task<bool> UntilAsync(IContainer container) | ||
{ | ||
await Task.Delay(TimeSpan.FromSeconds(2)) | ||
.ConfigureAwait(false); | ||
|
||
return true; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this additional wait strategy necessary for Event Hubs too? Is there an upstream issue we can refer to, similar to what we do for the Service Bus module?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe its not needed, we need to test it out because I copied that from service bus emulator, actually.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe @krishankumar95 has some insights. A proper way to detect the readiness of the service is crucial for TC.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tests are working without that so we have to wait and if there will be no response, I advice to revert that change (remove waiting strategy )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is due to the TFM. We can simply use IReadOnlyCollection
and don't need the additional dependency.
namespace Testcontainers.EventHubs;
[PublicAPI]
public record RootConfiguration(UserConfig UserConfig)
{
public UserConfig UserConfig { get; } = UserConfig;
}
[PublicAPI]
public record UserConfig(IReadOnlyCollection<NamespaceConfig> NamespaceConfig, LoggingConfig LoggingConfig)
{
public IReadOnlyCollection<NamespaceConfig> NamespaceConfig { get; } = NamespaceConfig;
public LoggingConfig LoggingConfig { get; } = LoggingConfig;
}
[PublicAPI]
public record NamespaceConfig(string Type, string Name, IReadOnlyCollection<Entity> Entities)
{
public string Type { get; } = Type;
public string Name { get; } = Name;
public IReadOnlyCollection<Entity> Entities { get; } = Entities;
}
[PublicAPI]
public record Entity(string Name, int PartitionCount, IReadOnlyCollection<ConsumerGroup> ConsumerGroups)
{
public string Name { get; } = Name;
public int PartitionCount { get; } = PartitionCount;
public IReadOnlyCollection<ConsumerGroup> ConsumerGroups { get; } = ConsumerGroups;
}
[PublicAPI]
public record ConsumerGroup(string Name)
{
public string Name { get; } = Name;
}
[PublicAPI]
public record LoggingConfig(string Type)
{
public string Type { get; } = Type;
}
[PublicAPI]
public sealed class EventHubsServiceConfiguration
{
private readonly NamespaceConfig _namespaceConfig;
private EventHubsServiceConfiguration(NamespaceConfig namespaceConfig)
{
_namespaceConfig = namespaceConfig;
}
public static EventHubsServiceConfiguration Create()
{
var namespaceConfig = new NamespaceConfig("EventHub", "ns-1", Array.Empty<Entity>());
return new EventHubsServiceConfiguration(namespaceConfig);
}
public EventHubsServiceConfiguration WithEntity(string name, int partitionCount, params string[] consumerGroups)
{
return WithEntity(name, partitionCount, new ReadOnlyCollection<string>(consumerGroups));
}
public EventHubsServiceConfiguration WithEntity(string name, int partitionCount, IEnumerable<string> consumerGroups)
{
var entity = new Entity(name, partitionCount, new ReadOnlyCollection<ConsumerGroup>(consumerGroups.Select(consumerGroup => new ConsumerGroup(consumerGroup)).ToList()));
var entities = new ReadOnlyCollection<Entity>(_namespaceConfig.Entities.Append(entity).ToList());
return new EventHubsServiceConfiguration(new NamespaceConfig(_namespaceConfig.Type, _namespaceConfig.Name, entities));
}
public bool Validate()
{
return _namespaceConfig.Entities.All(entity => entity.PartitionCount is > 0 and <= 32 && entity.ConsumerGroups.Count is > 0 and <= 20);
}
public string Build()
{
var rootConfiguration = new RootConfiguration(new UserConfig([_namespaceConfig], new LoggingConfig("file")));
return JsonSerializer.Serialize(rootConfiguration);
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the changes. I think we just need to address the remaining leftovers, and then we're good to merge.
var kafkaPort = _eventHubsContainer.GetMappedPublicPort(EventHubsBuilder.KafkaPort); | ||
var bootstrapServer = $"localhost:{kafkaPort}"; | ||
var connectionString = _eventHubsContainer.GetConnectionString(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we move this to EventHubsContainer
:
/// <summary>
/// Gets the broker address.
/// </summary>
/// <returns>The broker address.</returns>
public string GetBootstrapAddress()
{
return new UriBuilder("PLAINTEXT", Hostname, GetMappedPublicPort(EventHubsBuilder.KafkaPort)).ToString();
}
/// <summary> | ||
/// Gets the Event Hubs connection string. | ||
/// </summary> | ||
/// <returns>The Event Hubs connection string.</returns> | ||
public string GetConnectionString() | ||
{ | ||
var properties = new Dictionary<string, string> | ||
{ | ||
{ | ||
"Endpoint", | ||
new UriBuilder(Uri.UriSchemeHttp, Hostname, GetMappedPublicPort(EventHubsBuilder.EventHubsPort)) | ||
.ToString() | ||
}, | ||
{ "DefaultEndpointsProtocol", Uri.UriSchemeHttp }, | ||
{ "SharedAccessKeyName", "RootManageSharedAccessKey" }, | ||
{ "SharedAccessKey", "SAS_KEY_VALUE" }, | ||
{ "UseDevelopmentEmulator", "true" }, | ||
}; | ||
return string.Join(";", properties.Select(property => string.Join("=", property.Key, property.Value))); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// <summary> | |
/// Gets the Event Hubs connection string. | |
/// </summary> | |
/// <returns>The Event Hubs connection string.</returns> | |
public string GetConnectionString() | |
{ | |
var properties = new Dictionary<string, string> | |
{ | |
{ | |
"Endpoint", | |
new UriBuilder(Uri.UriSchemeHttp, Hostname, GetMappedPublicPort(EventHubsBuilder.EventHubsPort)) | |
.ToString() | |
}, | |
{ "DefaultEndpointsProtocol", Uri.UriSchemeHttp }, | |
{ "SharedAccessKeyName", "RootManageSharedAccessKey" }, | |
{ "SharedAccessKey", "SAS_KEY_VALUE" }, | |
{ "UseDevelopmentEmulator", "true" }, | |
}; | |
return string.Join(";", properties.Select(property => string.Join("=", property.Key, property.Value))); | |
} | |
/// <summary> | |
/// Gets the Event Hubs connection string. | |
/// </summary> | |
/// <returns>The Event Hubs connection string.</returns> | |
public string GetConnectionString() | |
{ | |
var properties = new Dictionary<string, string>(); | |
properties.Add("Endpoint", new UriBuilder(Uri.UriSchemeHttp, Hostname, GetMappedPublicPort(EventHubsBuilder.EventHubsPort)).ToString()); | |
properties.Add("DefaultEndpointsProtocol", Uri.UriSchemeHttp); | |
properties.Add("SharedAccessKeyName", "RootManageSharedAccessKey"); | |
properties.Add("SharedAccessKey", "SAS_KEY_VALUE"); | |
properties.Add("UseDevelopmentEmulator", "true"); | |
return string.Join(";", properties.Select(property => string.Join("=", property.Key, property.Value))); | |
} |
Can we please keep it as it was? It is much easier for me to maintain the repository when the projects and modules are aligned. This helps me maintain an overview and refactor things more efficiently.
First version of PR was made by @WakaToa at #1183
What does this PR do?
Add support for Azure EventHubs emulator.
Info
You need to provide an Azurite (emulator) instance/endpoint to start the EventHub emulator. This can be done using the EventHubsConfiguration.
You need to specify the following configuration file when starting the emulator.
It will be dynamically mapped and i have built a floating builder so that the user can set the configuration as easily as possible.
The namespace "emulatorNs1" is mandatory and it is the only one currently supported by the emulator.
Related issues