Skip to content

Commit 48e8d11

Browse files
author
Siwei Zhang
committed
server: Add bar chart data provider with /bars endpoint
This commit uses the newly introduced data provider type to support "bar chart" views. It focuses on implementing the /bars endpoint, which will be the second endpoint invoked by viewer. [Added] /bars endpoint for bar chart view
1 parent 1eec412 commit 48e8d11

File tree

16 files changed

+881
-17
lines changed

16 files changed

+881
-17
lines changed

trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests/src/org/eclipse/tracecompass/incubator/trace/server/jersey/rest/core/tests/services/BarChartDataProviderServiceTest.java

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@
1717
import static org.junit.Assert.assertNull;
1818
import static org.junit.Assert.assertTrue;
1919

20+
import java.util.ArrayList;
2021
import java.util.Arrays;
2122
import java.util.Collections;
2223
import java.util.HashMap;
2324
import java.util.List;
2425
import java.util.Map;
26+
import java.util.Set;
2527

2628
import javax.ws.rs.client.Entity;
2729
import javax.ws.rs.client.WebTarget;
@@ -32,10 +34,15 @@
3234
import org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests.stubs.AxisDomainStub;
3335
import org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests.stubs.EntryStub;
3436
import org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests.stubs.ExperimentModelStub;
37+
import org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests.stubs.SamplingStub;
3538
import org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests.stubs.TmfTreeModelWithAxisDescriptorsResponseStub;
3639
import org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests.stubs.TmfTreeModelWithAxisDescriptorsStub;
3740
import org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests.stubs.TmfXYAxisDescriptionStub;
41+
import org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests.stubs.XyModelStub;
42+
import org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests.stubs.XyOutputResponseStub;
43+
import org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests.stubs.XySeriesStub;
3844
import org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests.utils.RestServerTest;
45+
import org.eclipse.tracecompass.tmf.core.model.StyleProperties;
3946
import org.junit.Test;
4047

4148
/**
@@ -47,7 +54,11 @@
4754
public class BarChartDataProviderServiceTest extends RestServerTest {
4855
private static final String DATA_PROVIDER_RESPONSE_FAILED_MSG = "There should be a positive response for the data provider";
4956
private static final String MODEL_NULL_MSG = "The model is null, maybe the analysis did not run long enough?";
57+
private static final String REQUESTED_ITEMS_KEY = "requested_items";
58+
private static final String REQUESTED_SAMPLING_KEY = "requested_sampling";
5059
private static final int MAX_ITER = 40;
60+
private static final long TRACE_START_TIME = 1450193697034689597L;
61+
private static final long TRACE_END_TIME = 1450193745774189602L;
5162
private static final List<EntryStub> EXPECTED_ENTRIES = List.of(
5263
new EntryStub(Arrays.asList("ust"), 0, -1, true, null),
5364
new EntryStub(Arrays.asList("UNKNOWN_PID"), 1, 0, true, null));
@@ -99,6 +110,30 @@ public void testBarChartDataProvider() throws InterruptedException {
99110
assertNotNull("Y axis description should not be null", yAxis);
100111
List<EntryStub> entries = model.getEntries();
101112
assertFalse(entries.isEmpty());
113+
114+
// Test getting the bars endpoint with descriptors for bar chart
115+
WebTarget barsEnpoint = getBarChartBarsEndpoint(exp.getUUID().toString(), CALL_STACK_BAR_CHART_DATAPROVIDER_ID);
116+
parameters = new HashMap<>();
117+
List<Integer> items = new ArrayList<>();
118+
for (EntryStub entry : entries) {
119+
items.add(entry.getId());
120+
}
121+
parameters.put(REQUESTED_ITEMS_KEY, items);
122+
parameters.put(REQUESTED_TIMES_KEY, List.of(TRACE_START_TIME, TRACE_END_TIME));
123+
List<List<Number>> ranges = new ArrayList<>();
124+
ranges.add(List.of(1L, 100L));
125+
ranges.add(List.of(101L, 10000L));
126+
ranges.add(List.of(10001L, 1000000L));
127+
parameters.put(REQUESTED_SAMPLING_KEY, ranges);
128+
try (Response series = barsEnpoint.request().post(Entity.json(new QueryParameters(parameters, Collections.emptyList())))) {
129+
assertEquals(DATA_PROVIDER_RESPONSE_FAILED_MSG, 200, series.getStatus());
130+
XyOutputResponseStub xyModelResponse = series.readEntity(XyOutputResponseStub.class);
131+
assertNotNull(xyModelResponse);
132+
133+
XyModelStub xyModel = xyModelResponse.getModel();
134+
Set<XySeriesStub> xySeries = xyModel.getSeries();
135+
assertFalse(xySeries.isEmpty());
136+
}
102137
}
103138

104139
/**
@@ -185,5 +220,66 @@ public void testCallStackBarChartDataProvider() throws InterruptedException {
185220
assertEquals("Labels mismatch at index " + i, expected.getLabels(), actual.getLabels());
186221
assertEquals("Style mismatch at index " + i, expected.getStyle(), actual.getStyle());
187222
}
223+
224+
/*
225+
* Test the data in bars end point.
226+
*/
227+
WebTarget barsEnpoint = getBarChartBarsEndpoint(exp.getUUID().toString(), CALL_STACK_BAR_CHART_DATAPROVIDER_ID);
228+
parameters = new HashMap<>();
229+
List<Integer> items = new ArrayList<>();
230+
for (EntryStub entry : actualEntries) {
231+
items.add(entry.getId());
232+
}
233+
parameters.put(REQUESTED_ITEMS_KEY, items);
234+
List<List<Number>> ranges = List.of(
235+
List.of(1L, 100L),
236+
List.of(101L, 10_000L),
237+
List.of(10_001L, 1_000_000L),
238+
List.of(1_000_001L, 1_000_000_000L),
239+
List.of(1_000_000_001L, 1_000_000_000_000L)
240+
);
241+
parameters.put(REQUESTED_SAMPLING_KEY, ranges);
242+
parameters.put(REQUESTED_TIMES_KEY, List.of(TRACE_START_TIME, TRACE_END_TIME));
243+
XyOutputResponseStub xyModelResponse;
244+
try (Response series = barsEnpoint.request().post(Entity.json(new QueryParameters(parameters, Collections.emptyList())))) {
245+
assertEquals(DATA_PROVIDER_RESPONSE_FAILED_MSG, 200, series.getStatus());
246+
xyModelResponse = series.readEntity(XyOutputResponseStub.class);
247+
}
248+
assertNotNull(xyModelResponse);
249+
XyModelStub xyModel = xyModelResponse.getModel();
250+
Set<XySeriesStub> xySeries = xyModel.getSeries();
251+
assertEquals("Number of series mismatch", 1, xySeries.size());
252+
XySeriesStub seriesStub = xySeries.iterator().next();
253+
254+
// Validate fields
255+
assertEquals("Name mismatch", "UNKNOWN_PID", seriesStub.getName());
256+
assertEquals("ID mismatch", 1, seriesStub.getId());
257+
List<Double> actualYValues = seriesStub.getYValues();
258+
List<Double> expectedYValues = Arrays.asList(1.0, 0.0, 1764.0, 178.0, 5.0);
259+
assertEquals("Y values size mismatch", expectedYValues.size(), actualYValues.size());
260+
for (int i = 0; i < expectedYValues.size(); i++) {
261+
assertEquals("Y value mismatch at index " + i, expectedYValues.get(i), actualYValues.get(i), 0.000001);
262+
}
263+
264+
// Validate xValues
265+
SamplingStub xValues = seriesStub.getXValues();
266+
assertTrue("xValues should be a RangesStub", xValues instanceof SamplingStub.RangesStub);
267+
List<SamplingStub.RangesStub.RangeStub> actualRanges = ((SamplingStub.RangesStub) xValues).getRanges();
268+
List<SamplingStub.RangesStub.RangeStub> expectedRanges = Arrays.asList(
269+
new SamplingStub.RangesStub.RangeStub(1L, 100L),
270+
new SamplingStub.RangesStub.RangeStub(101L, 10_000L),
271+
new SamplingStub.RangesStub.RangeStub(10_001L, 1_000_000L),
272+
new SamplingStub.RangesStub.RangeStub(1_000_001L, 1_000_000_000L),
273+
new SamplingStub.RangesStub.RangeStub(1_000_000_001L, 1_000_000_000_000L)
274+
);
275+
assertEquals("Range size mismatch", expectedRanges.size(), actualRanges.size());
276+
for (int i = 0; i < expectedRanges.size(); i++) {
277+
assertEquals("Range mismatch at index " + i, expectedRanges.get(i), actualRanges.get(i));
278+
}
279+
280+
// Validate style
281+
assertNotNull("Style should not be null", seriesStub.getStyle());
282+
assertEquals("Series type should be bar", "bar",
283+
seriesStub.getStyle().getStyleValues().get(StyleProperties.SERIES_TYPE));
188284
}
189285
}

trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests/src/org/eclipse/tracecompass/incubator/trace/server/jersey/rest/core/tests/stubs/AxisDomainStub.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
/**
2525
* A stub class for AxisDomain which can be either Categorical or TimeRange.
26-
* Matches the trace server protocol schema for AxisDomain.
26+
* Matches the trace server protocol schema for <code>AxisDomain</code>.
2727
*
2828
* @author Siwei Zhang
2929
*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
/**********************************************************************
2+
* Copyright (c) 2025 Ericsson
3+
*
4+
* All rights reserved. This program and the accompanying materials are
5+
* made available under the terms of the Eclipse Public License 2.0 which
6+
* accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
**********************************************************************/
11+
package org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests.stubs;
12+
13+
import java.io.Serializable;
14+
import java.util.Arrays;
15+
import java.util.List;
16+
import java.util.Objects;
17+
18+
import org.eclipse.jdt.annotation.Nullable;
19+
20+
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
21+
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
22+
import org.eclipse.tracecompass.tmf.core.model.barchart.Sampling;
23+
24+
/**
25+
* Stub version of {@link Sampling}.
26+
*
27+
* @author Siwei Zhang
28+
*/
29+
@JsonSerialize(using = SamplingStubSerializer.class)
30+
@JsonDeserialize(using = SamplingStubDeserializer.class)
31+
public sealed interface SamplingStub extends Serializable permits
32+
SamplingStub.TimestampsStub,
33+
SamplingStub.CategoriesStub,
34+
SamplingStub.RangesStub {
35+
36+
/**
37+
* Get the number of sampling points
38+
*
39+
* @return number of points
40+
*/
41+
int size();
42+
43+
/**
44+
* Timestamp-based sampling.
45+
*/
46+
final class TimestampsStub implements SamplingStub {
47+
private static final long serialVersionUID = -8242136490356720296L;
48+
49+
private final long[] fTimestamps;
50+
51+
public TimestampsStub(long[] timestamps) {
52+
this.fTimestamps = Objects.requireNonNull(timestamps);
53+
}
54+
55+
public long[] getTimestamps() {
56+
return fTimestamps;
57+
}
58+
59+
@Override
60+
public int size() {
61+
return fTimestamps.length;
62+
}
63+
64+
@Override
65+
public boolean equals(@Nullable Object obj) {
66+
return (this == obj) || (obj instanceof TimestampsStub other &&
67+
Arrays.equals(this.fTimestamps, other.fTimestamps));
68+
}
69+
70+
@Override
71+
public int hashCode() {
72+
return Arrays.hashCode(fTimestamps);
73+
}
74+
75+
@Override
76+
public String toString() {
77+
return "Timestamps" + Arrays.toString(fTimestamps); //$NON-NLS-1$
78+
}
79+
}
80+
81+
/**
82+
* Categorical sampling (e.g., names).
83+
*/
84+
final class CategoriesStub implements SamplingStub {
85+
private static final long serialVersionUID = 3751152643508688051L;
86+
87+
private final List<String> fCategories;
88+
89+
public CategoriesStub(List<String> categories) {
90+
this.fCategories = Objects.requireNonNull(categories);
91+
}
92+
93+
public List<String> getCategories() {
94+
return fCategories;
95+
}
96+
97+
@Override
98+
public int size() {
99+
return fCategories.size();
100+
}
101+
102+
@Override
103+
public boolean equals(@Nullable Object obj) {
104+
return (this == obj) || (obj instanceof CategoriesStub other &&
105+
Objects.equals(this.fCategories, other.fCategories));
106+
}
107+
108+
@Override
109+
public int hashCode() {
110+
return Objects.hash(fCategories);
111+
}
112+
113+
@Override
114+
public String toString() {
115+
return "Categories" + fCategories.toString(); //$NON-NLS-1$
116+
}
117+
}
118+
119+
/**
120+
* Range sampling, representing start-end pairs.
121+
*/
122+
final class RangesStub implements SamplingStub {
123+
private static final long serialVersionUID = 3434126540189939098L;
124+
125+
private final List<RangeStub> fRanges;
126+
127+
public RangesStub(List<RangeStub> ranges) {
128+
this.fRanges = Objects.requireNonNull(ranges);
129+
}
130+
131+
public List<RangeStub> getRanges() {
132+
return fRanges;
133+
}
134+
135+
@Override
136+
public int size() {
137+
return fRanges.size();
138+
}
139+
140+
@Override
141+
public boolean equals(@Nullable Object obj) {
142+
return (this == obj) || (obj instanceof RangesStub other &&
143+
Objects.equals(this.fRanges, other.fRanges));
144+
}
145+
146+
@Override
147+
public int hashCode() {
148+
return Objects.hash(fRanges);
149+
}
150+
151+
@Override
152+
public String toString() {
153+
return "Ranges" + fRanges.toString(); //$NON-NLS-1$
154+
}
155+
156+
/**
157+
* Stub representing a range.
158+
*/
159+
public static final class RangeStub implements Serializable {
160+
private static final long serialVersionUID = 1L;
161+
162+
private final long fStart;
163+
private final long fEnd;
164+
165+
public RangeStub(long start, long end) {
166+
this.fStart = start;
167+
this.fEnd = end;
168+
}
169+
170+
public long getStart() {
171+
return fStart;
172+
}
173+
174+
public long getEnd() {
175+
return fEnd;
176+
}
177+
178+
@Override
179+
public boolean equals(@Nullable Object obj) {
180+
return (this == obj) || (obj instanceof RangeStub other &&
181+
fStart == other.fStart && fEnd == other.fEnd);
182+
}
183+
184+
@Override
185+
public int hashCode() {
186+
return Objects.hash(fStart, fEnd);
187+
}
188+
189+
@Override
190+
public String toString() {
191+
return "[" + fStart + ", " + fEnd + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
192+
}
193+
}
194+
}
195+
}

0 commit comments

Comments
 (0)