1
+ namespace Testcontainers . EventHubs ;
2
+
3
+ /// <inheritdoc cref="ContainerBuilder{TBuilderEntity, TContainerEntity, TConfigurationEntity}" />
4
+ [ PublicAPI ]
5
+ public sealed class EventHubsBuilder : ContainerBuilder < EventHubsBuilder , EventHubsContainer , EventHubsConfiguration >
6
+ {
7
+ public const string EventHubsNetworkAlias = "eventhubs-container" ;
8
+
9
+ public const string AzuriteNetworkAlias = "azurite-container" ;
10
+
11
+ public const string EventHubsImage = "mcr.microsoft.com/azure-messaging/eventhubs-emulator:latest" ;
12
+
13
+ public const ushort EventHubsPort = 5672 ;
14
+
15
+ /// <summary>
16
+ /// Initializes a new instance of the <see cref="EventHubsBuilder" /> class.
17
+ /// </summary>
18
+ public EventHubsBuilder ( )
19
+ : this ( new EventHubsConfiguration ( ) )
20
+ {
21
+ DockerResourceConfiguration = Init ( ) . DockerResourceConfiguration ;
22
+ }
23
+
24
+ /// <summary>
25
+ /// Initializes a new instance of the <see cref="EventHubsBuilder" /> class.
26
+ /// </summary>
27
+ /// <param name="resourceConfiguration">The Docker resource configuration.</param>
28
+ private EventHubsBuilder ( EventHubsConfiguration resourceConfiguration )
29
+ : base ( resourceConfiguration )
30
+ {
31
+ DockerResourceConfiguration = resourceConfiguration ;
32
+ }
33
+
34
+ /// <inheritdoc />
35
+ protected override EventHubsConfiguration DockerResourceConfiguration { get ; }
36
+
37
+ /// <inheritdoc />
38
+ protected override string AcceptLicenseAgreementEnvVar { get ; } = "ACCEPT_EULA" ;
39
+
40
+ /// <inheritdoc />
41
+ protected override string AcceptLicenseAgreement { get ; } = "Y" ;
42
+
43
+ /// <inheritdoc />
44
+ protected override string DeclineLicenseAgreement { get ; } = "N" ;
45
+
46
+ /// <summary>
47
+ /// Accepts the license agreement.
48
+ /// </summary>
49
+ /// <remarks>
50
+ /// When <paramref name="acceptLicenseAgreement" /> is set to <c>true</c>, the Azure Event Hubs Emulator <see href="https://github.com/Azure/azure-event-hubs-emulator-installer/blob/main/EMULATOR_EULA.md">license</see> is accepted.
51
+ /// </remarks>
52
+ /// <param name="acceptLicenseAgreement">A boolean value indicating whether the Azure Event Hubs Emulator license agreement is accepted.</param>
53
+ /// <returns>A configured instance of <see cref="EventHubsBuilder" />.</returns>
54
+ public override EventHubsBuilder WithAcceptLicenseAgreement ( bool acceptLicenseAgreement )
55
+ {
56
+ var licenseAgreement = acceptLicenseAgreement ? AcceptLicenseAgreement : DeclineLicenseAgreement ;
57
+ return WithEnvironment ( AcceptLicenseAgreementEnvVar , licenseAgreement ) ;
58
+ }
59
+
60
+ /// <summary>
61
+ /// Sets the dependent Azurite container for the Azure Event Hubs Emulator.
62
+ /// </summary>
63
+ /// <remarks>
64
+ /// This method allows an existing Azurite container to be attached to the Azure Event
65
+ /// Hubs Emulator. The containers must be on the same network to enable communication
66
+ /// between them.
67
+ /// </remarks>
68
+ /// <param name="network">The network to connect the container to.</param>
69
+ /// <param name="container">The Azurite container.</param>
70
+ /// <param name="networkAlias">The Azurite container network alias.</param>
71
+ /// <returns>A configured instance of <see cref="EventHubsBuilder" />.</returns>
72
+ public EventHubsBuilder WithAzuriteContainer (
73
+ INetwork network ,
74
+ AzuriteContainer container ,
75
+ string networkAlias )
76
+ {
77
+ return Merge ( DockerResourceConfiguration , new EventHubsConfiguration ( azuriteContainer : container ) )
78
+ . DependsOn ( container )
79
+ . WithNetwork ( network )
80
+ . WithNetworkAliases ( EventHubsNetworkAlias )
81
+ . WithEnvironment ( "BLOB_SERVER" , networkAlias )
82
+ . WithEnvironment ( "METADATA_SERVER" , networkAlias ) ;
83
+ }
84
+
85
+ /// <summary>
86
+ /// Sets the Azure Event Hubs Emulator configuration.
87
+ /// </summary>
88
+ /// <param name="serviceConfiguration">The service configuration.</param>
89
+ /// <returns>A configured instance of <see cref="EventHubsBuilder" />.</returns>
90
+ public EventHubsBuilder WithConfigurationBuilder ( EventHubsServiceConfiguration serviceConfiguration )
91
+ {
92
+ var resourceContent = Encoding . Default . GetBytes ( serviceConfiguration . Build ( ) ) ;
93
+ return Merge ( DockerResourceConfiguration , new EventHubsConfiguration ( serviceConfiguration : serviceConfiguration ) )
94
+ . WithResourceMapping ( resourceContent , "Eventhubs_Emulator/ConfigFiles/Config.json" ) ;
95
+ }
96
+
97
+ /// <inheritdoc />
98
+ public override EventHubsContainer Build ( )
99
+ {
100
+ Validate ( ) ;
101
+ ValidateLicenseAgreement ( ) ;
102
+
103
+ if ( DockerResourceConfiguration . AzuriteContainer != null )
104
+ {
105
+ return new EventHubsContainer ( DockerResourceConfiguration ) ;
106
+ }
107
+
108
+ // If the user has not provided an existing Azurite container instance,
109
+ // we configure one.
110
+ var network = new NetworkBuilder ( )
111
+ . Build ( ) ;
112
+
113
+ var container = new AzuriteBuilder ( )
114
+ . WithNetwork ( network )
115
+ . WithNetworkAliases ( AzuriteNetworkAlias )
116
+ . Build ( ) ;
117
+
118
+ var eventHubsContainer = WithAzuriteContainer ( network , container , AzuriteNetworkAlias ) ;
119
+ return new EventHubsContainer ( eventHubsContainer . DockerResourceConfiguration ) ;
120
+ }
121
+
122
+ /// <inheritdoc />
123
+ protected override void Validate ( )
124
+ {
125
+ base . Validate ( ) ;
126
+
127
+ _ = Guard . Argument ( DockerResourceConfiguration . ServiceConfiguration , nameof ( DockerResourceConfiguration . ServiceConfiguration ) )
128
+ . NotNull ( )
129
+ . ThrowIf ( argument => ! argument . Value . Validate ( ) , _ => throw new ArgumentException ( "The service configuration of the Azure Event Hubs Emulator is invalid." ) ) ;
130
+ }
131
+
132
+ /// <inheritdoc />
133
+ protected override EventHubsBuilder Init ( )
134
+ {
135
+ return base . Init ( )
136
+ . WithImage ( EventHubsImage )
137
+ . WithPortBinding ( EventHubsPort , true )
138
+ . WithWaitStrategy ( Wait . ForUnixContainer ( )
139
+ . UntilMessageIsLogged ( "Emulator Service is Successfully Up!" )
140
+ . AddCustomWaitStrategy ( new WaitTwoSeconds ( ) ) ) ;
141
+ }
142
+
143
+ /// <inheritdoc />
144
+ protected override EventHubsBuilder Clone ( IResourceConfiguration < CreateContainerParameters > resourceConfiguration )
145
+ {
146
+ return Merge ( DockerResourceConfiguration , new EventHubsConfiguration ( resourceConfiguration ) ) ;
147
+ }
148
+
149
+ /// <inheritdoc />
150
+ protected override EventHubsBuilder Clone ( IContainerConfiguration resourceConfiguration )
151
+ {
152
+ return Merge ( DockerResourceConfiguration , new EventHubsConfiguration ( resourceConfiguration ) ) ;
153
+ }
154
+
155
+ /// <inheritdoc />
156
+ protected override EventHubsBuilder Merge ( EventHubsConfiguration oldValue , EventHubsConfiguration newValue )
157
+ {
158
+ return new EventHubsBuilder ( new EventHubsConfiguration ( oldValue , newValue ) ) ;
159
+ }
160
+
161
+ /// <inheritdoc cref="IWaitUntil" />
162
+ /// <remarks>
163
+ /// This is a workaround to ensure that the wait strategy does not indicate
164
+ /// readiness too early:
165
+ /// https://github.com/Azure/azure-service-bus-emulator-installer/issues/35#issuecomment-2497164533.
166
+ /// </remarks>
167
+ private sealed class WaitTwoSeconds : IWaitUntil
168
+ {
169
+ /// <inheritdoc />
170
+ public async Task < bool > UntilAsync ( IContainer container )
171
+ {
172
+ await Task . Delay ( TimeSpan . FromSeconds ( 2 ) )
173
+ . ConfigureAwait ( false ) ;
174
+
175
+ return true ;
176
+ }
177
+ }
178
+ }
0 commit comments