Commit | Line | Data |
---|---|---|
60cabb56 | 1 | /******************************************************************************* |
b9d50127 | 2 | * Copyright (c) 2016 Ericsson and others |
60cabb56 PT |
3 | * |
4 | * All rights reserved. This program and the accompanying materials are | |
5 | * made available under the terms of the Eclipse Public License v1.0 which | |
6 | * accompanies this distribution, and is available at | |
7 | * http://www.eclipse.org/legal/epl-v10.html | |
8 | *******************************************************************************/ | |
9 | ||
10 | package org.eclipse.tracecompass.statesystem.core.tests.backend; | |
11 | ||
12 | import static org.junit.Assert.assertEquals; | |
d844f14b | 13 | import static org.junit.Assert.assertNotNull; |
60cabb56 PT |
14 | import static org.junit.Assert.assertTrue; |
15 | import static org.junit.Assert.fail; | |
16 | ||
17 | import java.io.IOException; | |
18 | import java.util.ArrayList; | |
19 | import java.util.List; | |
20 | ||
21 | import org.eclipse.jdt.annotation.Nullable; | |
22 | import org.eclipse.tracecompass.statesystem.core.backend.IStateHistoryBackend; | |
23 | import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException; | |
a510d2da | 24 | import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException; |
60cabb56 PT |
25 | import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval; |
26 | import org.eclipse.tracecompass.statesystem.core.interval.TmfStateInterval; | |
a510d2da | 27 | import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue; |
60cabb56 | 28 | import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue; |
d69a6555 | 29 | import org.eclipse.tracecompass.statesystem.core.tests.stubs.statevalues.CustomStateValueStub; |
60cabb56 PT |
30 | import org.junit.Test; |
31 | ||
a510d2da GB |
32 | import com.google.common.collect.ImmutableList; |
33 | ||
60cabb56 | 34 | /** |
a510d2da GB |
35 | * Abstract class to test implementations of the {@link IStateHistoryBackend} |
36 | * interface. | |
60cabb56 PT |
37 | * |
38 | * @author Patrick Tasse | |
a510d2da | 39 | * @author Geneviève Bastien |
60cabb56 PT |
40 | */ |
41 | public abstract class StateHistoryBackendTestBase { | |
42 | ||
a510d2da GB |
43 | /* Some state values of each type */ |
44 | private static final ITmfStateValue INT_VAL1 = TmfStateValue.newValueInt(-42); | |
45 | private static final ITmfStateValue INT_VAL2 = TmfStateValue.newValueInt(675893); | |
46 | private static final ITmfStateValue LONG_VAL1 = TmfStateValue.newValueLong(-78L); | |
47 | private static final ITmfStateValue LONG_VAL2 = TmfStateValue.newValueLong(2234L); | |
48 | private static final ITmfStateValue DOUBLE_VAL1 = TmfStateValue.newValueDouble(-9.87); | |
49 | private static final ITmfStateValue DOUBLE_VAL2 = TmfStateValue.newValueDouble(50324.131643); | |
50 | private static final ITmfStateValue STR_VAL1 = TmfStateValue.newValueString("A string"); | |
51 | private static final ITmfStateValue STR_VAL2 = TmfStateValue.newValueString("Another éèstr"); | |
52 | ||
60cabb56 PT |
53 | /** |
54 | * Gets the backend to be used for building. | |
55 | * | |
56 | * @param startTime | |
57 | * The start time of the history | |
58 | * | |
59 | * @return The backend to be used for building. | |
60 | * @throws IOException | |
61 | * if an exception occurs | |
62 | */ | |
63 | protected abstract IStateHistoryBackend getBackendForBuilding(long startTime) throws IOException; | |
64 | ||
65 | /** | |
66 | * Gets the backend to be used for querying. The default implementation | |
67 | * returns the backend that was used for building. | |
68 | * <p> | |
69 | * Only the returned backend should be used after calling this method. The | |
70 | * one sent in parameter might have been disposed. | |
71 | * | |
72 | * @param backend | |
73 | * The backend that was used for building | |
74 | * @return The backend to be used for querying. | |
75 | * @throws IOException | |
76 | * if an exception occurs | |
77 | */ | |
78 | @SuppressWarnings("unused") | |
79 | protected IStateHistoryBackend getBackendForQuerying(IStateHistoryBackend backend) throws IOException { | |
80 | return backend; | |
81 | } | |
82 | ||
83 | /** | |
84 | * Prepares a backend to be used in tests. The specified intervals will be | |
85 | * inserted in the backend, and then the backend will be closed. | |
86 | * | |
87 | * @param startTime | |
88 | * The start time of the history | |
89 | * @param endTime | |
90 | * The end time at which to close the history | |
91 | * @param intervals | |
92 | * The intervals to insert in the history backend | |
93 | * @return The backend to be used for querying. | |
94 | */ | |
d844f14b | 95 | protected final @Nullable IStateHistoryBackend prepareBackend(long startTime, long endTime, |
60cabb56 PT |
96 | List<ITmfStateInterval> intervals) { |
97 | ||
98 | try { | |
99 | IStateHistoryBackend backend = getBackendForBuilding(startTime); | |
100 | insertIntervals(backend, intervals); | |
101 | backend.finishedBuilding(Math.max(endTime, backend.getEndTime())); | |
102 | return getBackendForQuerying(backend); | |
103 | } catch (IOException e) { | |
104 | fail(e.getMessage()); | |
105 | return null; | |
106 | } | |
107 | } | |
108 | ||
109 | /** | |
110 | * Insert the specified intervals in the provided backend. | |
111 | * | |
112 | * @param backend | |
113 | * The backend to be used | |
114 | * @param intervals | |
115 | * The intervals to insert in the history backend | |
116 | */ | |
117 | protected static void insertIntervals(IStateHistoryBackend backend, List<ITmfStateInterval> intervals) { | |
118 | for (ITmfStateInterval interval : intervals) { | |
119 | backend.insertPastState(interval.getStartTime(), interval.getEndTime(), interval.getAttribute(), interval.getStateValue()); | |
120 | } | |
121 | } | |
122 | ||
a510d2da GB |
123 | /** |
124 | * Initializes a list for the number of attributes in the backend and | |
125 | * associates a null value for each | |
126 | * | |
127 | * @param nbAttrib | |
128 | * The number of attributes in the backend | |
129 | * @return A list of null values for each attribute | |
130 | */ | |
131 | private static List<@Nullable ITmfStateInterval> prepareIntervalList(int nbAttrib) { | |
132 | List<@Nullable ITmfStateInterval> intervals = new ArrayList<>(nbAttrib); | |
133 | for (int i = 0; i < nbAttrib; i++) { | |
134 | intervals.add(null); | |
135 | } | |
136 | return intervals; | |
137 | } | |
138 | ||
60cabb56 PT |
139 | /** |
140 | * Test the integrity of a backend by first building the backend with the | |
141 | * specified intervals, closing it, and then querying at every single | |
142 | * timestamp, making sure that all returned intervals intersect with the | |
143 | * query time. The backend start and end time will be checked. | |
144 | * <p> | |
145 | * If <code>allowNull</code> is false, the specified intervals must cover | |
146 | * the full range for all attributes. The method will make sure that no null | |
147 | * intervals are returned. | |
148 | * | |
149 | * @param startTime | |
150 | * The start time of the history | |
151 | * @param endTime | |
152 | * The end time of the history | |
153 | * @param nbAttr | |
154 | * The number of attributes | |
155 | * @param intervals | |
156 | * The list of intervals to insert | |
157 | * @param allowNull | |
158 | * True if null intervals are allowed, false otherwise | |
159 | * @return The backend to be used for querying. | |
160 | */ | |
161 | protected final IStateHistoryBackend buildAndQueryFullRange(long startTime, long endTime, int nbAttr, List<ITmfStateInterval> intervals, boolean allowNull) { | |
162 | ||
163 | final IStateHistoryBackend backend = prepareBackend(startTime, endTime, intervals); | |
d844f14b | 164 | assertNotNull(backend); |
60cabb56 PT |
165 | |
166 | try { | |
167 | /* | |
168 | * Query at every valid time stamp, making sure only the expected | |
169 | * intervals are returned. | |
170 | */ | |
171 | for (long t = backend.getStartTime(); t <= backend.getEndTime(); t++) { | |
a510d2da | 172 | List<@Nullable ITmfStateInterval> stateInfo = prepareIntervalList(nbAttr); |
60cabb56 PT |
173 | backend.doQuery(stateInfo, t); |
174 | for (int attr = 0; attr < stateInfo.size(); attr++) { | |
175 | ITmfStateInterval interval = stateInfo.get(attr); | |
176 | if (!allowNull) { | |
177 | assertTrue("null interval at t=" + t + " for attr=" + attr, interval != null); | |
178 | } | |
179 | if (interval != null) { | |
180 | assertTrue(interval + " does not intersect t=" + t, interval.intersects(t)); | |
181 | } | |
182 | } | |
183 | } | |
184 | ||
185 | assertEquals(startTime, backend.getStartTime()); | |
186 | assertEquals(endTime, backend.getEndTime()); | |
187 | } catch (StateSystemDisposedException e) { | |
188 | fail(e.getMessage()); | |
60cabb56 PT |
189 | } |
190 | return backend; | |
191 | } | |
192 | ||
193 | /** | |
194 | * Test the full query method by filling a small backend with intervals | |
195 | * placed in a "stair-like" fashion, like this: | |
196 | * | |
197 | * <pre> | |
198 | * |x----x----x---x| | |
199 | * |xx----x----x--x| | |
200 | * |x-x----x----x-x| | |
201 | * |x--x----x----xx| | |
202 | * | ... | | |
203 | * </pre> | |
204 | * | |
205 | * and then querying at every single timestamp, making sure all, and only, | |
206 | * the expected intervals are returned. | |
207 | */ | |
208 | @Test | |
209 | public void testCascadingIntervals() { | |
210 | final int nbAttr = 10; | |
211 | final long duration = 10; | |
212 | final long startTime = 0; | |
213 | final long endTime = 1000; | |
214 | ||
215 | List<ITmfStateInterval> intervals = new ArrayList<>(); | |
216 | for (long t = startTime + 1; t <= endTime + duration; t++) { | |
217 | intervals.add(new TmfStateInterval( | |
218 | Math.max(startTime, t - duration), | |
219 | Math.min(endTime, t - 1), | |
220 | (int) t % nbAttr, | |
221 | TmfStateValue.newValueLong(t))); | |
222 | } | |
223 | ||
224 | buildAndQueryFullRange(startTime, endTime, nbAttr, intervals, false); | |
225 | } | |
226 | ||
227 | /** | |
228 | * Test the full query method by filling a small backend with intervals that | |
229 | * take the full time range, like this: | |
230 | * | |
231 | * <pre> | |
232 | * |x-------------x| | |
233 | * |x-------------x| | |
234 | * |x-------------x| | |
235 | * |x-------------x| | |
236 | * | ... | | |
237 | * </pre> | |
238 | * | |
239 | * and then querying at every single timestamp, making sure all, and only, | |
240 | * the expected intervals are returned. | |
241 | */ | |
242 | @Test | |
243 | public void testFullIntervals() { | |
244 | final int nbAttr = 1000; | |
245 | final long startTime = 0; | |
246 | final long endTime = 1000; | |
247 | ||
248 | List<ITmfStateInterval> intervals = new ArrayList<>(); | |
249 | for (int attr = 0; attr < nbAttr; attr++) { | |
250 | intervals.add(new TmfStateInterval( | |
251 | startTime, | |
252 | endTime, | |
253 | attr, | |
254 | TmfStateValue.newValueLong(attr))); | |
255 | } | |
256 | ||
257 | buildAndQueryFullRange(startTime, endTime, nbAttr, intervals, false); | |
258 | } | |
a510d2da GB |
259 | |
260 | /** | |
261 | * Test inserting values of different types and querying them right after | |
262 | */ | |
263 | @Test | |
264 | public void testInsertQueryStateValues() { | |
265 | /* Test specific data initialization */ | |
266 | long startTime = 10; | |
267 | long timeStep = 5; | |
268 | int intQuark = 0; | |
269 | int longQuark = 1; | |
270 | int doubleQuark = 2; | |
271 | int strQuark = 3; | |
d69a6555 GB |
272 | int customQuark = 4; |
273 | /* Register custom factory and create a custom state value */ | |
274 | CustomStateValueStub.registerFactory(); | |
275 | ITmfStateValue customVal = new CustomStateValueStub(10, "a string"); | |
a510d2da GB |
276 | |
277 | try { | |
278 | IStateHistoryBackend backend = getBackendForBuilding(startTime); | |
279 | assertNotNull(backend); | |
280 | ||
281 | /* Int interval */ | |
282 | backend.insertPastState(startTime, startTime + timeStep, intQuark, INT_VAL1); | |
283 | ITmfStateInterval interval = backend.doSingularQuery(startTime, intQuark); | |
284 | ||
285 | assertEquals("Int interval start time", startTime, interval.getStartTime()); | |
286 | assertEquals("Int interval end time", startTime + timeStep, interval.getEndTime()); | |
287 | assertEquals("Int interval value", INT_VAL1, interval.getStateValue()); | |
288 | ||
289 | /* Long interval */ | |
290 | backend.insertPastState(startTime, startTime + timeStep, longQuark, LONG_VAL1); | |
291 | interval = backend.doSingularQuery(startTime, longQuark); | |
292 | ||
293 | assertEquals("Long interval start time", startTime, interval.getStartTime()); | |
294 | assertEquals("Long interval end time", startTime + timeStep, interval.getEndTime()); | |
295 | assertEquals("Long interval value", LONG_VAL1, interval.getStateValue()); | |
296 | ||
297 | /* Double interval */ | |
298 | backend.insertPastState(startTime, startTime + timeStep, doubleQuark, DOUBLE_VAL1); | |
299 | interval = backend.doSingularQuery(startTime, doubleQuark); | |
300 | ||
301 | assertEquals("Double interval start time", startTime, interval.getStartTime()); | |
302 | assertEquals("Double interval end time", startTime + timeStep, interval.getEndTime()); | |
303 | assertEquals("Double interval value", DOUBLE_VAL1, interval.getStateValue()); | |
304 | ||
305 | /* String interval */ | |
306 | backend.insertPastState(startTime, startTime + timeStep, strQuark, STR_VAL1); | |
307 | interval = backend.doSingularQuery(startTime, strQuark); | |
308 | ||
309 | assertEquals("String interval start time", startTime, interval.getStartTime()); | |
310 | assertEquals("String interval end time", startTime + timeStep, interval.getEndTime()); | |
311 | assertEquals("String interval value", STR_VAL1, interval.getStateValue()); | |
312 | ||
d69a6555 GB |
313 | /* Custom state values */ |
314 | backend.insertPastState(startTime, startTime + timeStep, customQuark, customVal); | |
315 | interval = backend.doSingularQuery(startTime, customQuark); | |
316 | ||
317 | assertEquals("Custom interval start time", startTime, interval.getStartTime()); | |
318 | assertEquals("Custom interval end time", startTime + timeStep, interval.getEndTime()); | |
319 | assertEquals("Custom interval value", customVal, interval.getStateValue()); | |
320 | ||
a510d2da GB |
321 | /* |
322 | * Add other intervals for the int quark and query at different | |
323 | * times | |
324 | */ | |
325 | backend.insertPastState(startTime + timeStep + 1, startTime + (2 * timeStep), intQuark, INT_VAL2); | |
326 | backend.insertPastState(startTime + (2 * timeStep) + 1, startTime + (3 * timeStep), intQuark, INT_VAL1); | |
327 | ||
328 | interval = backend.doSingularQuery(startTime + timeStep, intQuark); | |
329 | assertEquals("Int interval value", INT_VAL1, interval.getStateValue()); | |
330 | ||
331 | interval = backend.doSingularQuery(startTime + timeStep + 1, intQuark); | |
332 | assertEquals("Int interval value", INT_VAL2, interval.getStateValue()); | |
333 | ||
334 | interval = backend.doSingularQuery(startTime + (2 * timeStep), intQuark); | |
335 | assertEquals("Int interval value", INT_VAL2, interval.getStateValue()); | |
336 | ||
337 | interval = backend.doSingularQuery(startTime + (2 * timeStep) + 1, intQuark); | |
338 | assertEquals("Int interval value", INT_VAL1, interval.getStateValue()); | |
339 | ||
ed48dc75 | 340 | } catch (TimeRangeException | StateSystemDisposedException | IOException e) { |
a510d2da GB |
341 | fail(e.getMessage()); |
342 | } | |
343 | } | |
344 | ||
345 | /** | |
346 | * Test querying various state value types after the state system has been | |
347 | * built and finished | |
348 | */ | |
349 | @Test | |
350 | public void testBuildNowQueryLaterStateValues() { | |
351 | /* Test specific data initialization */ | |
352 | long startTime = 10; | |
353 | long timeStep = 5; | |
354 | int intQuark = 0; | |
355 | int longQuark = 1; | |
356 | int doubleQuark = 2; | |
357 | int strQuark = 3; | |
d69a6555 GB |
358 | int customQuark = 4; |
359 | int nbAttribs = 5; | |
360 | /* Register custom factory and create custom state values */ | |
361 | CustomStateValueStub.registerFactory(); | |
362 | ITmfStateValue customVal = new CustomStateValueStub(10, "a string"); | |
363 | ITmfStateValue customVal2 = new CustomStateValueStub(Short.MAX_VALUE, "another string"); | |
a510d2da GB |
364 | |
365 | try { | |
366 | IStateHistoryBackend backend = getBackendForBuilding(startTime); | |
367 | assertNotNull(backend); | |
368 | ||
369 | long firstEnd = startTime + timeStep; | |
370 | long nextStart = firstEnd + 1; | |
371 | long endTime = nextStart + timeStep; | |
372 | ||
373 | insertIntervals(backend, ImmutableList.of(new TmfStateInterval(startTime, startTime + timeStep, intQuark, INT_VAL1), | |
374 | new TmfStateInterval(startTime, startTime + timeStep, longQuark, LONG_VAL1), | |
375 | new TmfStateInterval(startTime, startTime + timeStep, doubleQuark, DOUBLE_VAL1), | |
376 | new TmfStateInterval(startTime, startTime + timeStep, strQuark, STR_VAL1), | |
d69a6555 | 377 | new TmfStateInterval(startTime, startTime + timeStep, customQuark, customVal), |
a510d2da GB |
378 | new TmfStateInterval(nextStart, endTime, intQuark, INT_VAL2), |
379 | new TmfStateInterval(nextStart, endTime, longQuark, LONG_VAL2), | |
380 | new TmfStateInterval(nextStart, endTime, doubleQuark, DOUBLE_VAL2), | |
d69a6555 GB |
381 | new TmfStateInterval(nextStart, endTime, strQuark, STR_VAL2), |
382 | new TmfStateInterval(nextStart, endTime, customQuark, customVal2))); | |
a510d2da GB |
383 | |
384 | backend.finishedBuilding(endTime); | |
385 | ||
386 | /* Make sure the end time corresponds to the backend end time */ | |
387 | assertEquals(endTime, backend.getEndTime()); | |
388 | ||
389 | IStateHistoryBackend backendQuery = getBackendForQuerying(backend); | |
390 | ||
391 | /* Verify start and end times */ | |
392 | assertEquals("Backend start time", startTime, backendQuery.getStartTime()); | |
393 | assertEquals("Backend end time", endTime, backendQuery.getEndTime()); | |
394 | ||
395 | List<@Nullable ITmfStateInterval> intervals = prepareIntervalList(nbAttribs); | |
396 | ||
397 | /* Do a full query at start and verify the values */ | |
398 | backendQuery.doQuery(intervals, startTime); | |
399 | ||
400 | ITmfStateInterval interval = intervals.get(intQuark); | |
401 | assertNotNull(interval); | |
402 | assertEquals("Int value after read", INT_VAL1, interval.getStateValue()); | |
403 | interval = intervals.get(longQuark); | |
404 | assertNotNull(interval); | |
405 | assertEquals("Long value after read", LONG_VAL1, interval.getStateValue()); | |
406 | interval = intervals.get(doubleQuark); | |
407 | assertNotNull(interval); | |
408 | assertEquals("Double value after read", DOUBLE_VAL1, interval.getStateValue()); | |
409 | interval = intervals.get(strQuark); | |
410 | assertNotNull(interval); | |
411 | assertEquals("String value after read", STR_VAL1, interval.getStateValue()); | |
d69a6555 GB |
412 | /* Custom */ |
413 | interval = intervals.get(customQuark); | |
414 | assertNotNull(interval); | |
415 | assertEquals("String value after read", customVal, interval.getStateValue()); | |
a510d2da GB |
416 | |
417 | /* Do a full query at the end and verify the values */ | |
418 | backendQuery.doQuery(intervals, endTime); | |
419 | ||
420 | interval = intervals.get(intQuark); | |
421 | assertNotNull(interval); | |
422 | assertEquals("Int value after read", INT_VAL2, interval.getStateValue()); | |
423 | interval = intervals.get(longQuark); | |
424 | assertNotNull(interval); | |
425 | assertEquals("Long value after read", LONG_VAL2, interval.getStateValue()); | |
426 | interval = intervals.get(doubleQuark); | |
427 | assertNotNull(interval); | |
428 | assertEquals("Double value after read", DOUBLE_VAL2, interval.getStateValue()); | |
429 | interval = intervals.get(strQuark); | |
430 | assertNotNull(interval); | |
431 | assertEquals("String value after read", STR_VAL2, interval.getStateValue()); | |
d69a6555 GB |
432 | /* Custom */ |
433 | interval = intervals.get(customQuark); | |
434 | assertNotNull(interval); | |
435 | assertEquals("String value after read", customVal2, interval.getStateValue()); | |
a510d2da GB |
436 | |
437 | } catch (TimeRangeException | IOException | StateSystemDisposedException e) { | |
438 | fail(e.getMessage()); | |
439 | } | |
440 | } | |
60cabb56 | 441 | } |