|
2 | 2 | // The .NET Foundation licenses this file to you under the Apache 2.0 License. |
3 | 3 | // See the LICENSE file in the project root for more information. |
4 | 4 |
|
| 5 | +using System.Globalization; |
5 | 6 | using System.Net; |
6 | 7 | using FluentAssertions.Extensions; |
7 | 8 | using Microsoft.AspNetCore.Builder; |
@@ -655,38 +656,127 @@ public async Task ApplicationEventsFireAfterFetch() |
655 | 656 | webApplication.Services.GetRequiredService<HttpClientHandlerFactory>().Using(handler); |
656 | 657 |
|
657 | 658 | var discoveryClient = webApplication.Services.GetRequiredService<EurekaDiscoveryClient>(); |
658 | | - int applicationsEventCount = 0; |
659 | 659 | ApplicationsFetchedEventArgs? applicationsEventArgs = null; |
660 | | - int instancesEventCount = 0; |
| 660 | + int applicationsEventCount = 0; |
661 | 661 | DiscoveryInstancesFetchedEventArgs? instancesEventArgs = null; |
| 662 | + int instancesEventCount = 0; |
662 | 663 |
|
663 | 664 | discoveryClient.ApplicationsFetched += (_, args) => |
664 | 665 | { |
665 | | - applicationsEventCount++; |
666 | 666 | applicationsEventArgs = args; |
| 667 | + Interlocked.Increment(ref applicationsEventCount); |
667 | 668 | }; |
668 | 669 |
|
669 | 670 | discoveryClient.InstancesFetched += (_, args) => |
670 | 671 | { |
671 | | - instancesEventCount++; |
672 | 672 | instancesEventArgs = args; |
| 673 | + Interlocked.Increment(ref instancesEventCount); |
673 | 674 | }; |
674 | 675 |
|
675 | 676 | await discoveryClient.FetchRegistryAsync(true, TestContext.Current.CancellationToken); |
676 | 677 | SpinWait.SpinUntil(() => applicationsEventCount == 1 && instancesEventCount == 1, 5.Seconds()).Should().BeTrue(); |
677 | 678 |
|
| 679 | + applicationsEventArgs.Should().NotBeNull(); |
| 680 | + InstanceInfo oldInstanceFromAppEvent = applicationsEventArgs.Applications.Should().ContainSingle().Which.Instances.Should().ContainSingle().Which; |
| 681 | + oldInstanceFromAppEvent.ActionType.Should().Be(ActionType.Added); |
| 682 | + |
| 683 | + instancesEventArgs.Should().NotBeNull(); |
| 684 | + IServiceInstance oldInstanceFromEvent = instancesEventArgs.InstancesByServiceId.Should().ContainKey("foo").WhoseValue.Should().ContainSingle().Which; |
| 685 | + oldInstanceFromEvent.Uri.ToString().Should().Be("http://localhost:8080/"); |
| 686 | + |
| 687 | + IList<IServiceInstance> oldInstancesFromGet = await discoveryClient.GetInstancesAsync("foo", TestContext.Current.CancellationToken); |
| 688 | + oldInstancesFromGet.Should().ContainSingle().Which.Uri.Should().Be(oldInstanceFromEvent.Uri); |
| 689 | + |
678 | 690 | await discoveryClient.FetchRegistryAsync(false, TestContext.Current.CancellationToken); |
679 | 691 | SpinWait.SpinUntil(() => applicationsEventCount == 2 && instancesEventCount == 2, 5.Seconds()).Should().BeTrue(); |
680 | 692 |
|
| 693 | + InstanceInfo newInstanceFromAppEvent = applicationsEventArgs.Applications.Should().ContainSingle().Which.Instances.Should().ContainSingle().Which; |
| 694 | + newInstanceFromAppEvent.ActionType.Should().Be(ActionType.Modified); |
| 695 | + |
| 696 | + IServiceInstance newInstanceFromEvent = instancesEventArgs.InstancesByServiceId.Should().ContainKey("foo").WhoseValue.Should().ContainSingle().Which; |
| 697 | + newInstanceFromEvent.Uri.ToString().Should().Be("http://modified-host:8080/"); |
| 698 | + |
| 699 | + IList<IServiceInstance> newInstancesFromGet = await discoveryClient.GetInstancesAsync("foo", TestContext.Current.CancellationToken); |
| 700 | + newInstancesFromGet.Should().ContainSingle().Which.Uri.Should().Be(newInstanceFromEvent.Uri); |
| 701 | + |
681 | 702 | handler.Mock.VerifyNoOutstandingExpectation(); |
| 703 | + } |
682 | 704 |
|
683 | | - applicationsEventArgs.Should().NotBeNull(); |
684 | | - InstanceInfo newInstanceInfo = applicationsEventArgs.Applications.Should().ContainSingle().Which.Instances.Should().ContainSingle().Which; |
685 | | - newInstanceInfo.ActionType.Should().Be(ActionType.Modified); |
| 705 | + [Theory] |
| 706 | + [InlineData(false)] |
| 707 | + [InlineData(true)] |
| 708 | + public async Task InstancesFetched_returns_same_data_as_GetInstancesAsync(bool filterOnlyUpInstances) |
| 709 | + { |
| 710 | + const string registryJson = """ |
| 711 | + { |
| 712 | + "applications": { |
| 713 | + "application": [ |
| 714 | + { |
| 715 | + "name": "ignored", |
| 716 | + "instance": [ |
| 717 | + { |
| 718 | + "instanceId": "id1", |
| 719 | + "hostName": "h1", |
| 720 | + "app": "app1", |
| 721 | + "ipAddr": "10.0.0.1", |
| 722 | + "status": "UP", |
| 723 | + "dataCenterInfo": { |
| 724 | + "@class": "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo", |
| 725 | + "name": "MyOwn" |
| 726 | + }, |
| 727 | + "vipAddress": "vapp1" |
| 728 | + }, |
| 729 | + { |
| 730 | + "instanceId": "id2", |
| 731 | + "hostName": "h2", |
| 732 | + "app": "app1", |
| 733 | + "ipAddr": "10.0.0.2", |
| 734 | + "status": "DOWN", |
| 735 | + "dataCenterInfo": { |
| 736 | + "@class": "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo", |
| 737 | + "name": "MyOwn" |
| 738 | + }, |
| 739 | + "vipAddress": "vapp1" |
| 740 | + } |
| 741 | + ] |
| 742 | + } |
| 743 | + ] |
| 744 | + } |
| 745 | + } |
| 746 | + """; |
686 | 747 |
|
687 | | - instancesEventArgs.Should().NotBeNull(); |
688 | | - IServiceInstance newServiceInstance = instancesEventArgs.InstancesByServiceId.Should().ContainKey("foo").WhoseValue.Should().ContainSingle().Which; |
689 | | - newServiceInstance.Uri.ToString().Should().Be("http://modified-host:8080/"); |
| 748 | + var appSettings = new Dictionary<string, string?> |
| 749 | + { |
| 750 | + ["Eureka:Client:ShouldFetchRegistry"] = "false", |
| 751 | + ["Eureka:Client:ShouldRegisterWithEureka"] = "false", |
| 752 | + ["Eureka:Client:ShouldFilterOnlyUpInstances"] = filterOnlyUpInstances.ToString(CultureInfo.InvariantCulture) |
| 753 | + }; |
| 754 | + |
| 755 | + WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create(); |
| 756 | + builder.Configuration.AddInMemoryCollection(appSettings); |
| 757 | + builder.Services.AddEurekaDiscoveryClient(); |
| 758 | + |
| 759 | + var handler = new DelegateToMockHttpClientHandler(); |
| 760 | + handler.Mock.Expect(HttpMethod.Get, "http://localhost:8761/eureka/apps").Respond("application/json", registryJson); |
| 761 | + |
| 762 | + await using WebApplication webApplication = builder.Build(); |
| 763 | + webApplication.Services.GetRequiredService<HttpClientHandlerFactory>().Using(handler); |
| 764 | + |
| 765 | + var discoveryClient = webApplication.Services.GetRequiredService<EurekaDiscoveryClient>(); |
| 766 | + DiscoveryInstancesFetchedEventArgs? eventArgs = null; |
| 767 | + discoveryClient.InstancesFetched += (_, args) => eventArgs = args; |
| 768 | + |
| 769 | + await discoveryClient.FetchRegistryAsync(true, TestContext.Current.CancellationToken); |
| 770 | + SpinWait.SpinUntil(() => eventArgs != null, 5.Seconds()).Should().BeTrue(); |
| 771 | + |
| 772 | + eventArgs.Should().NotBeNull(); |
| 773 | + |
| 774 | + IList<IServiceInstance> instancesFromGet = await discoveryClient.GetInstancesAsync("vapp1", TestContext.Current.CancellationToken); |
| 775 | + IReadOnlyList<IServiceInstance> instancesFromEvent = eventArgs.InstancesByServiceId.Should().ContainKey("vapp1").WhoseValue; |
| 776 | + |
| 777 | + instancesFromEvent.Should().BeEquivalentTo(instancesFromGet); |
| 778 | + |
| 779 | + handler.Mock.VerifyNoOutstandingExpectation(); |
690 | 780 | } |
691 | 781 |
|
692 | 782 | private sealed class ExtraRequestHeadersDelegatingHandler : DelegatingHandler |
|
0 commit comments