diff --git a/src/Aspire.Dashboard/Components/Pages/TraceDetail.razor.cs b/src/Aspire.Dashboard/Components/Pages/TraceDetail.razor.cs index 195ff568cf9..48218220e22 100644 --- a/src/Aspire.Dashboard/Components/Pages/TraceDetail.razor.cs +++ b/src/Aspire.Dashboard/Components/Pages/TraceDetail.razor.cs @@ -76,11 +76,12 @@ protected override void OnInitialized() } } - private ValueTask> GetData(GridItemsProviderRequest request) + // Internal to be used in unit tests + internal ValueTask> GetData(GridItemsProviderRequest request) { Debug.Assert(_spanWaterfallViewModels != null); - var visibleViewModels = new HashSet(); + var visibleViewModels = new SortedSet(Comparer.Create((a, b) => a.Span.StartTime.CompareTo(b.Span.StartTime))); foreach (var viewModel in _spanWaterfallViewModels) { if (!viewModel.IsHidden && viewModel.MatchesFilter(_filter, GetResourceName, out var matchedDescendents)) diff --git a/tests/Aspire.Dashboard.Components.Tests/Pages/TraceDetailsTests.cs b/tests/Aspire.Dashboard.Components.Tests/Pages/TraceDetailsTests.cs index 9e6ea12175a..53d9f4c64b1 100644 --- a/tests/Aspire.Dashboard.Components.Tests/Pages/TraceDetailsTests.cs +++ b/tests/Aspire.Dashboard.Components.Tests/Pages/TraceDetailsTests.cs @@ -137,6 +137,62 @@ public async Task Render_ChangeTrace_RowsRendered() await AsyncTestHelpers.AssertIsTrueRetryAsync(() => rows.Count == 2, "Expected rows to be rendered."); } + [Fact] + public async Task Render_SpansOrderedByStartTime_RowsRenderedInCorrectOrder() + { + // Arrange + SetupTraceDetailsServices(); + + var viewport = new ViewportInformation(IsDesktop: true, IsUltraLowHeight: false, IsUltraLowWidth: false); + + var dimensionManager = Services.GetRequiredService(); + dimensionManager.InvokeOnViewportInformationChanged(viewport); + + var telemetryRepository = Services.GetRequiredService(); + telemetryRepository.AddTraces(new AddContext(), + new RepeatedField + { + new ResourceSpans + { + Resource = CreateResource(), + ScopeSpans = + { + new ScopeSpans + { + Scope = CreateScope(), + Spans = + { + CreateSpan(traceId: "1", spanId: "1-1", + startTime: s_testTime.AddMinutes(1), + endTime: s_testTime.AddMinutes(10)), + CreateSpan(traceId: "1", spanId: "1-2", + startTime: s_testTime.AddMinutes(5), + endTime: s_testTime.AddMinutes(10), parentSpanId: "1-1"), + CreateSpan(traceId: "1", spanId: "1-3", + startTime: s_testTime.AddMinutes(2), + endTime: s_testTime.AddMinutes(6), parentSpanId: "1-1") + } + } + } + } + }); + + // Act + var traceId = Convert.ToHexString(Encoding.UTF8.GetBytes("1")); + var cut = RenderComponent(builder => + { + builder.Add(p => p.TraceId, traceId); + builder.AddCascadingValue(viewport); + }); + + var data = await cut.Instance.GetData(new GridItemsProviderRequest()); + + Assert.Collection(data.Items, + item => Assert.Equal("Test span. Id: 1-1", item.Span.Name), + item => Assert.Equal("Test span. Id: 1-3", item.Span.Name), + item => Assert.Equal("Test span. Id: 1-2", item.Span.Name)); + } + private void SetupTraceDetailsServices() { var version = typeof(FluentMain).Assembly.GetName().Version!;