99using Ocelot . Configuration ;
1010using Ocelot . Configuration . File ;
1111using Ocelot . DependencyInjection ;
12+ using Ocelot . Infrastructure . Extensions ;
1213using Ocelot . LoadBalancer . Balancers ;
1314using Ocelot . Logging ;
1415using Ocelot . Provider . Kubernetes ;
@@ -40,7 +41,7 @@ public KubernetesServiceDiscoveryTests()
4041
4142 [ Theory ]
4243 [ InlineData ( nameof ( Kube ) ) ]
43- /* [InlineData(nameof(PollKube))] TODO Fails now. Bug 2304? -> https://github.com/ThreeMammals/Ocelot/issues/2304 */
44+ [ InlineData ( nameof ( PollKube ) ) ] // Bug 2304 -> https://github.com/ThreeMammals/Ocelot/issues/2304
4445 [ InlineData ( nameof ( WatchKube ) ) ]
4546 public void ShouldReturnServicesFromK8s ( string discoveryType )
4647 {
@@ -108,27 +109,31 @@ public void ShouldReturnServicesByPortNameAsDownstreamScheme(string downstreamSc
108109
109110 [ Theory ]
110111 [ Trait ( "Bug" , "2110" ) ]
111- [ InlineData ( 1 , 30 ) ]
112- [ InlineData ( 2 , 50 ) ]
113- [ InlineData ( 3 , 50 ) ]
114- [ InlineData ( 4 , 50 ) ]
115- [ InlineData ( 5 , 50 ) ]
116- [ InlineData ( 6 , 99 ) ]
117- [ InlineData ( 7 , 99 ) ]
118- [ InlineData ( 8 , 99 ) ]
119- [ InlineData ( 9 , 999 ) ]
120- [ InlineData ( 10 , 999 ) ]
121- public void ShouldHighlyLoadOnStableKubeProvider_WithRoundRobinLoadBalancing ( int totalServices , int totalRequests )
112+ [ InlineData ( 1 , 30 , null ) ]
113+ [ InlineData ( 2 , 50 , null ) ]
114+ [ InlineData ( 3 , 50 , null ) ]
115+ [ InlineData ( 4 , 50 , null ) ]
116+ [ InlineData ( 5 , 50 , null ) ]
117+ [ InlineData ( 6 , 99 , null ) ]
118+ [ InlineData ( 7 , 99 , null ) ]
119+ [ InlineData ( 8 , 99 , null ) ]
120+ [ InlineData ( 9 , 999 , null ) ]
121+ [ InlineData ( 10 , 999 , nameof ( Kube ) ) ]
122+ [ InlineData ( 10 , 999 , nameof ( PollKube ) ) ]
123+ [ InlineData ( 10 , 999 , nameof ( WatchKube ) ) ]
124+ public void ShouldHighlyLoadOnStableKubeProvider_WithRoundRobinLoadBalancing ( int totalServices , int totalRequests , string discoveryType )
122125 {
123126 // Skip in MacOS because the test is very unstable
124127 if ( RuntimeInformation . IsOSPlatform ( OSPlatform . OSX ) ) // the test is stable in Linux and Windows only
125128 return ;
126129
127- const int ZeroGeneration = 0 ;
128- var ( endpoints , servicePorts ) = GivenServiceDiscoveryAndLoadBalancing ( totalServices ) ;
130+ int zeroGeneration = 0 , k8sCount = totalRequests ;
131+ var ( endpoints , servicePorts ) = GivenServiceDiscoveryAndLoadBalancing ( totalServices , discoveryType ?? nameof ( Kube ) ) ;
129132 GivenThereIsAFakeKubernetesProvider ( endpoints ) ; // stable, services will not be removed from the list
133+ if ( discoveryType == nameof ( WatchKube ) )
134+ k8sCount = GivenWatchReceivedEvent ( ) ; // 1
130135
131- HighlyLoadOnKubeProviderAndRoundRobinBalancer ( totalRequests , ZeroGeneration ) ;
136+ HighlyLoadOnKubeProviderAndRoundRobinBalancer ( totalRequests , zeroGeneration , k8sCount ) ;
132137
133138 int bottom = totalRequests / totalServices ,
134139 top = totalRequests - ( bottom * totalServices ) + bottom ;
@@ -138,28 +143,37 @@ public void ShouldHighlyLoadOnStableKubeProvider_WithRoundRobinLoadBalancing(int
138143
139144 [ Theory ]
140145 [ Trait ( "Bug" , "2110" ) ]
141- [ InlineData ( 5 , 50 , 1 ) ]
142- [ InlineData ( 5 , 50 , 2 ) ]
143- [ InlineData ( 5 , 50 , 3 ) ]
144- [ InlineData ( 5 , 50 , 4 ) ]
145- public void ShouldHighlyLoadOnUnstableKubeProvider_WithRoundRobinLoadBalancing ( int totalServices , int totalRequests , int k8sGeneration )
146+ [ InlineData ( 5 , 50 , 1 , null ) ]
147+ [ InlineData ( 5 , 50 , 2 , null ) ]
148+ [ InlineData ( 5 , 50 , 3 , null ) ]
149+ [ InlineData ( 5 , 50 , 4 , nameof ( Kube ) ) ]
150+ [ InlineData ( 5 , 50 , 4 , nameof ( PollKube ) ) ]
151+ [ InlineData ( 5 , 50 , 4 , nameof ( WatchKube ) ) ]
152+ public void ShouldHighlyLoadOnUnstableKubeProvider_WithRoundRobinLoadBalancing ( int totalServices , int totalRequests , int k8sGeneration , string discoveryType )
146153 {
147154 // Skip in MacOS because the test is very unstable
148155 if ( RuntimeInformation . IsOSPlatform ( OSPlatform . OSX ) ) // the test is stable in Linux and Windows only
149156 return ;
150157
151- int failPerThreads = ( totalRequests / k8sGeneration ) - 1 ; // k8sGeneration means number of offline services
152- var ( endpoints , servicePorts ) = GivenServiceDiscoveryAndLoadBalancing ( totalServices ) ;
158+ int failPerThreads = ( totalRequests / k8sGeneration ) - 1 , // k8sGeneration means number of offline services
159+ k8sCount = totalRequests ;
160+ var ( endpoints , servicePorts ) = GivenServiceDiscoveryAndLoadBalancing ( totalServices , discoveryType ?? nameof ( Kube ) ) ;
153161 GivenThereIsAFakeKubernetesProvider ( endpoints , false , k8sGeneration , failPerThreads ) ; // false means unstable, k8sGeneration services will be removed from the list
162+ if ( discoveryType == nameof ( WatchKube ) )
163+ {
164+ k8sCount = GivenWatchReceivedEvent ( ) ; // 1
165+ k8sGeneration = 0 ;
166+ }
154167
155- HighlyLoadOnKubeProviderAndRoundRobinBalancer ( totalRequests , k8sGeneration ) ;
168+ HighlyLoadOnKubeProviderAndRoundRobinBalancer ( totalRequests , k8sGeneration , k8sCount ) ;
156169
157170 ThenAllServicesCalledOptimisticAmountOfTimes ( _roundRobinAnalyzer ) ; // with unstable checkings
158171 ThenServiceCountersShouldMatchLeasingCounters ( _roundRobinAnalyzer , servicePorts , totalRequests ) ;
159172 }
160173
161174 [ Theory ]
162175 [ InlineData ( nameof ( Kube ) ) ]
176+ [ InlineData ( nameof ( PollKube ) ) ] // Bug 2304 -> https://github.com/ThreeMammals/Ocelot/issues/2304
163177 [ InlineData ( nameof ( WatchKube ) ) ]
164178 [ Trait ( "Feat" , "2256" ) ]
165179 public void ShouldReturnServicesFromK8s_AddKubernetesWithNullConfigureOptions ( string discoveryType )
@@ -238,7 +252,7 @@ public void ShouldReturnServicesFromK8s_OneWatchRequestUpdatesServicesInfo()
238252 [ Trait ( "Feat" , "2319" ) ]
239253 [ Trait ( "PR" , "2324" ) ] // https://github.com/ThreeMammals/Ocelot/pull/2324
240254 [ InlineData ( nameof ( Kube ) ) ]
241- /* [InlineData(nameof(PollKube))] // Bug 2304 -> https://github.com/ThreeMammals/Ocelot/issues/2304 */
255+ [ InlineData ( nameof ( PollKube ) ) ] // Bug 2304 -> https://github.com/ThreeMammals/Ocelot/issues/2304
242256 [ InlineData ( nameof ( WatchKube ) ) ]
243257 public void ShouldApplyGlobalLoadBalancerOptions_ForAllDynamicRoutes ( string discoveryType )
244258 {
@@ -260,7 +274,11 @@ static void ConfigureDynamicRouting(FileConfiguration configuration)
260274 var upstreamPath = $ "/{ ServiceNamespace ( ) } .{ ServiceName ( ) } /";
261275 WhenIGetUrlOnTheApiGatewayConcurrently ( upstreamPath , 50 ) ;
262276
263- _k8sCounter . ShouldBe ( discoveryType == nameof ( WatchKube ) ? 1 : 50 ) ;
277+ if ( discoveryType == nameof ( PollKube ) )
278+ _k8sCounter . ShouldBeGreaterThanOrEqualTo ( 50 ) ; // can be 50, 51 and sometimes 52
279+ else
280+ _k8sCounter . ShouldBe ( discoveryType == nameof ( WatchKube ) ? 1 : 50 ) ;
281+
264282 _k8sServiceGeneration . ShouldBe ( 0 ) ;
265283 ThenAllStatusCodesShouldBe ( HttpStatusCode . OK ) ;
266284 ThenAllServicesShouldHaveBeenCalledTimes ( 50 ) ;
@@ -293,21 +311,21 @@ private void AddKubernetesWithNullConfigureOptions(IServiceCollection services)
293311 downstreams . ForEach ( ds => GivenSubsetAddress ( ds , subset ) ) ;
294312 var endpoints = GivenEndpoints ( subset , serviceName ) ; // totalServices service instances with different ports
295313 var route = GivenRouteWithServiceName ( serviceName , loadBalancerType ) ; // !!!
296- var configuration = GivenKubeConfiguration ( route , discoveryType ) ;
314+ var configuration = GivenKubeConfiguration ( route , discoveryType . IfEmpty ( nameof ( Kube ) ) ) ;
297315 configure ? . Invoke ( configuration ) ;
298316 GivenMultipleServiceInstancesAreRunning ( downstreamUrls , downstreamResponses ) ;
299317 GivenThereIsAConfiguration ( configuration ) ;
300318 GivenOcelotIsRunning ( services ?? WithKubernetesAndRoundRobin ) ;
301319 return ( endpoints , servicePorts ) ;
302320 }
303321
304- private void HighlyLoadOnKubeProviderAndRoundRobinBalancer ( int totalRequests , int k8sGenerationNo )
322+ private void HighlyLoadOnKubeProviderAndRoundRobinBalancer ( int totalRequests , int k8sGenerationNo , int ? k8sCount = null )
305323 {
306324 // Act
307325 WhenIGetUrlOnTheApiGatewayConcurrently ( "/" , totalRequests ) ; // load by X parallel requests
308326
309327 // Assert
310- _k8sCounter . ShouldBeGreaterThanOrEqualTo ( totalRequests ) ; // integration endpoint called times
328+ _k8sCounter . ShouldBeGreaterThanOrEqualTo ( k8sCount ?? totalRequests ) ; // integration endpoint called times
311329 _k8sServiceGeneration . ShouldBe ( k8sGenerationNo ) ;
312330 ThenAllStatusCodesShouldBe ( HttpStatusCode . OK ) ;
313331 ThenAllServicesShouldHaveBeenCalledTimes ( totalRequests ) ;
@@ -373,7 +391,7 @@ private FileConfiguration GivenKubeConfiguration(FileRoute route, string type, s
373391 Host = u . Host ,
374392 Port = u . Port ,
375393 Type = type ,
376- PollingInterval = 0 ,
394+ PollingInterval = 3 , // 3ms is very fast polling, make sense for PollKube provider only
377395 Namespace = ServiceNamespace ( ) ,
378396 Token = token ?? "Test" ,
379397 } ;
@@ -442,7 +460,7 @@ private void GivenThereIsAFakeKubernetesProvider(ResourceEventV1<EndpointsV1>[]
442460 handler . GivenThereIsAServiceRunningOn ( _kubernetesUrl , ( c ) => GivenHandleWatchRequest ( c , events , namespaces , serviceName ) ) ;
443461 }
444462
445- private void GivenWatchReceivedEvent ( ) => _k8sWatchResetEvent . Set ( ) ;
463+ private int GivenWatchReceivedEvent ( ) => _k8sWatchResetEvent . Set ( ) ? 1 : 0 ;
446464 private static Task GivenDelay ( int milliseconds ) => Task . Delay ( TimeSpan . FromMilliseconds ( milliseconds ) ) ;
447465
448466 private async Task GivenHandleWatchRequest ( HttpContext context ,
0 commit comments