|
1 | 1 | using System.Collections.Generic;
|
2 |
| -using System.Threading.Tasks; |
| 2 | +using System.Diagnostics; |
| 3 | +using System.Threading; |
3 | 4 | using Moq;
|
4 | 5 | using Segment.Analytics;
|
5 | 6 | using Segment.Analytics.Utilities;
|
@@ -690,4 +691,260 @@ public void TestAliasEnrichment()
|
690 | 691 | Assert.Equal("test", actual[0].AnonymousId);
|
691 | 692 | }
|
692 | 693 | }
|
| 694 | + |
| 695 | + public class DelayedEventsTest |
| 696 | + { |
| 697 | + private readonly Analytics _analytics; |
| 698 | + |
| 699 | + private Settings? _settings; |
| 700 | + |
| 701 | + private readonly Mock<StubEventPlugin> _plugin; |
| 702 | + |
| 703 | + private readonly Mock<StubAfterEventPlugin> _afterPlugin; |
| 704 | + |
| 705 | + private readonly SemaphoreSlim _httpSemaphore; |
| 706 | + private readonly SemaphoreSlim _assertSemaphore; |
| 707 | + private readonly List<RawEvent> _actual; |
| 708 | + |
| 709 | + public DelayedEventsTest() |
| 710 | + { |
| 711 | + _httpSemaphore = new SemaphoreSlim(0); |
| 712 | + _assertSemaphore = new SemaphoreSlim(0); |
| 713 | + _settings = JsonUtility.FromJson<Settings?>( |
| 714 | + "{\"integrations\":{\"Segment.io\":{\"apiKey\":\"1vNgUqwJeCHmqgI9S1sOm9UHCyfYqbaQ\"}},\"plan\":{},\"edgeFunction\":{}}"); |
| 715 | + |
| 716 | + var mockHttpClient = new Mock<HTTPClient>(null, null, null); |
| 717 | + mockHttpClient |
| 718 | + .Setup(httpClient => httpClient.Settings()) |
| 719 | + .Returns(async () => |
| 720 | + { |
| 721 | + // suspend http calls until we tracked events |
| 722 | + // this will force events get into startup queue |
| 723 | + await _httpSemaphore.WaitAsync(); |
| 724 | + return _settings; |
| 725 | + }); |
| 726 | + |
| 727 | + _plugin = new Mock<StubEventPlugin> |
| 728 | + { |
| 729 | + CallBase = true |
| 730 | + }; |
| 731 | + |
| 732 | + _afterPlugin = new Mock<StubAfterEventPlugin> { CallBase = true }; |
| 733 | + _actual = new List<RawEvent>(); |
| 734 | + _afterPlugin.Setup(o => o.Execute(Capture.In(_actual))) |
| 735 | + .Returns((RawEvent e) => |
| 736 | + { |
| 737 | + // since this is an after plugin, when its execute function is called, |
| 738 | + // it is guaranteed that the enrichment closure has been called. |
| 739 | + // so we can release the semaphore on assertions. |
| 740 | + _assertSemaphore.Release(); |
| 741 | + return e; |
| 742 | + }); |
| 743 | + |
| 744 | + var config = new Configuration( |
| 745 | + writeKey: "123", |
| 746 | + storageProvider: new DefaultStorageProvider("tests"), |
| 747 | + autoAddSegmentDestination: false, |
| 748 | + useSynchronizeDispatcher: false, // we need async analytics to buildup events on start queue |
| 749 | + httpClientProvider: new MockHttpClientProvider(mockHttpClient) |
| 750 | + ); |
| 751 | + _analytics = new Analytics(config); |
| 752 | + } |
| 753 | + |
| 754 | + [Fact] |
| 755 | + public void TestTrackEnrichment() |
| 756 | + { |
| 757 | + string expectedEvent = "foo"; |
| 758 | + string expectedAnonymousId = "bar"; |
| 759 | + |
| 760 | + _analytics.Add(_afterPlugin.Object); |
| 761 | + _analytics.Track(expectedEvent, enrichment: @event => |
| 762 | + { |
| 763 | + @event.AnonymousId = expectedAnonymousId; |
| 764 | + return @event; |
| 765 | + }); |
| 766 | + |
| 767 | + // now we have tracked event, i.e. event added to startup queue |
| 768 | + // release the semaphore put on http client, so we startup queue will replay the events |
| 769 | + _httpSemaphore.Release(); |
| 770 | + // now we need to wait for events being fully replayed before making assertions |
| 771 | + _assertSemaphore.Wait(); |
| 772 | + |
| 773 | + Assert.NotEmpty(_actual); |
| 774 | + Assert.IsType<TrackEvent>(_actual[0]); |
| 775 | + var actual = _actual[0] as TrackEvent; |
| 776 | + Debug.Assert(actual != null, nameof(actual) + " != null"); |
| 777 | + Assert.True(actual.Properties.Count == 0); |
| 778 | + Assert.Equal(expectedEvent, actual.Event); |
| 779 | + Assert.Equal(expectedAnonymousId, actual.AnonymousId); |
| 780 | + } |
| 781 | + |
| 782 | + [Fact] |
| 783 | + public void TestIdentifyEnrichment() |
| 784 | + { |
| 785 | + var expected = new JsonObject |
| 786 | + { |
| 787 | + ["foo"] = "bar" |
| 788 | + }; |
| 789 | + string expectedUserId = "newUserId"; |
| 790 | + |
| 791 | + _analytics.Add(_afterPlugin.Object); |
| 792 | + _analytics.Identify(expectedUserId, expected, @event => |
| 793 | + { |
| 794 | + if (@event is IdentifyEvent identifyEvent) |
| 795 | + { |
| 796 | + identifyEvent.Traits["foo"] = "baz"; |
| 797 | + } |
| 798 | + |
| 799 | + return @event; |
| 800 | + }); |
| 801 | + |
| 802 | + // now we have tracked event, i.e. event added to startup queue |
| 803 | + // release the semaphore put on http client, so we startup queue will replay the events |
| 804 | + _httpSemaphore.Release(); |
| 805 | + // now we need to wait for events being fully replayed before making assertions |
| 806 | + _assertSemaphore.Wait(); |
| 807 | + |
| 808 | + string actualUserId = _analytics.UserId(); |
| 809 | + |
| 810 | + Assert.NotEmpty(_actual); |
| 811 | + var actual = _actual[0] as IdentifyEvent; |
| 812 | + Debug.Assert(actual != null, nameof(actual) + " != null"); |
| 813 | + Assert.Equal(expected, actual.Traits); |
| 814 | + Assert.Equal(expectedUserId, actualUserId); |
| 815 | + } |
| 816 | + |
| 817 | + [Fact] |
| 818 | + public void TestScreenEnrichment() |
| 819 | + { |
| 820 | + var expected = new JsonObject |
| 821 | + { |
| 822 | + ["foo"] = "bar" |
| 823 | + }; |
| 824 | + string expectedTitle = "foo"; |
| 825 | + string expectedCategory = "bar"; |
| 826 | + |
| 827 | + _analytics.Add(_afterPlugin.Object); |
| 828 | + _analytics.Screen(expectedTitle, expected, expectedCategory, @event => |
| 829 | + { |
| 830 | + if (@event is ScreenEvent screenEvent) |
| 831 | + { |
| 832 | + screenEvent.Properties["foo"] = "baz"; |
| 833 | + } |
| 834 | + |
| 835 | + return @event; |
| 836 | + }); |
| 837 | + |
| 838 | + // now we have tracked event, i.e. event added to startup queue |
| 839 | + // release the semaphore put on http client, so we startup queue will replay the events |
| 840 | + _httpSemaphore.Release(); |
| 841 | + // now we need to wait for events being fully replayed before making assertions |
| 842 | + _assertSemaphore.Wait(); |
| 843 | + |
| 844 | + Assert.NotEmpty(_actual); |
| 845 | + var actual = _actual[0] as ScreenEvent; |
| 846 | + Debug.Assert(actual != null, nameof(actual) + " != null"); |
| 847 | + Assert.Equal(expected, actual.Properties); |
| 848 | + Assert.Equal(expectedTitle, actual.Name); |
| 849 | + Assert.Equal(expectedCategory, actual.Category); |
| 850 | + } |
| 851 | + |
| 852 | + [Fact] |
| 853 | + public void TestPageEnrichment() |
| 854 | + { |
| 855 | + var expected = new JsonObject |
| 856 | + { |
| 857 | + ["foo"] = "bar" |
| 858 | + }; |
| 859 | + string expectedTitle = "foo"; |
| 860 | + string expectedCategory = "bar"; |
| 861 | + |
| 862 | + _analytics.Add(_afterPlugin.Object); |
| 863 | + _analytics.Page(expectedTitle, expected, expectedCategory, @event => |
| 864 | + { |
| 865 | + if (@event is PageEvent pageEvent) |
| 866 | + { |
| 867 | + pageEvent.Properties["foo"] = "baz"; |
| 868 | + } |
| 869 | + |
| 870 | + return @event; |
| 871 | + }); |
| 872 | + |
| 873 | + // now we have tracked event, i.e. event added to startup queue |
| 874 | + // release the semaphore put on http client, so we startup queue will replay the events |
| 875 | + _httpSemaphore.Release(); |
| 876 | + // now we need to wait for events being fully replayed before making assertions |
| 877 | + _assertSemaphore.Wait(); |
| 878 | + |
| 879 | + Assert.NotEmpty(_actual); |
| 880 | + var actual = _actual[0] as PageEvent; |
| 881 | + Debug.Assert(actual != null, nameof(actual) + " != null"); |
| 882 | + Assert.Equal(expected, actual.Properties); |
| 883 | + Assert.Equal(expectedTitle, actual.Name); |
| 884 | + Assert.Equal(expectedCategory, actual.Category); |
| 885 | + Assert.Equal("page", actual.Type); |
| 886 | + } |
| 887 | + |
| 888 | + [Fact] |
| 889 | + public void TestGroupEnrichment() |
| 890 | + { |
| 891 | + var expected = new JsonObject |
| 892 | + { |
| 893 | + ["foo"] = "bar" |
| 894 | + }; |
| 895 | + string expectedGroupId = "foo"; |
| 896 | + |
| 897 | + _analytics.Add(_afterPlugin.Object); |
| 898 | + _analytics.Group(expectedGroupId, expected, @event => |
| 899 | + { |
| 900 | + if (@event is GroupEvent groupEvent) |
| 901 | + { |
| 902 | + groupEvent.Traits["foo"] = "baz"; |
| 903 | + } |
| 904 | + |
| 905 | + return @event; |
| 906 | + }); |
| 907 | + |
| 908 | + // now we have tracked event, i.e. event added to startup queue |
| 909 | + // release the semaphore put on http client, so we startup queue will replay the events |
| 910 | + _httpSemaphore.Release(); |
| 911 | + // now we need to wait for events being fully replayed before making assertions |
| 912 | + _assertSemaphore.Wait(); |
| 913 | + |
| 914 | + Assert.NotEmpty(_actual); |
| 915 | + var actual = _actual[0] as GroupEvent; |
| 916 | + Debug.Assert(actual != null, nameof(actual) + " != null"); |
| 917 | + Assert.Equal(expected, actual.Traits); |
| 918 | + Assert.Equal(expectedGroupId, actual.GroupId); |
| 919 | + } |
| 920 | + |
| 921 | + [Fact] |
| 922 | + public void TestAliasEnrichment() |
| 923 | + { |
| 924 | + string expected = "bar"; |
| 925 | + |
| 926 | + _analytics.Add(_afterPlugin.Object); |
| 927 | + _analytics.Alias(expected, @event => |
| 928 | + { |
| 929 | + if (@event is AliasEvent aliasEvent) |
| 930 | + { |
| 931 | + aliasEvent.AnonymousId = "test"; |
| 932 | + } |
| 933 | + |
| 934 | + return @event; |
| 935 | + }); |
| 936 | + |
| 937 | + // now we have tracked event, i.e. event added to startup queue |
| 938 | + // release the semaphore put on http client, so we startup queue will replay the events |
| 939 | + _httpSemaphore.Release(); |
| 940 | + // now we need to wait for events being fully replayed before making assertions |
| 941 | + _assertSemaphore.Wait(); |
| 942 | + |
| 943 | + Assert.NotEmpty(_actual); |
| 944 | + var actual = _actual.Find(o => o is AliasEvent) as AliasEvent; |
| 945 | + Debug.Assert(actual != null, nameof(actual) + " != null"); |
| 946 | + Assert.Equal(expected, actual.UserId); |
| 947 | + Assert.Equal("test", actual.AnonymousId); |
| 948 | + } |
| 949 | + } |
693 | 950 | }
|
0 commit comments