datastore: Make the interval package public
[deliverable/tracecompass.git] / statesystem / org.eclipse.tracecompass.datastore.core.tests / src / org / eclipse / tracecompass / internal / provisional / datastore / core / historytree / HTNodeTest.java
CommitLineData
8b03451b
GB
1/*******************************************************************************
2 * Copyright (c) 2017 École Polytechnique de Montréal
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
10package org.eclipse.tracecompass.internal.provisional.datastore.core.historytree;
11
12import static org.junit.Assert.assertEquals;
13import static org.junit.Assert.assertFalse;
14import static org.junit.Assert.assertNotNull;
15import static org.junit.Assert.assertTrue;
16
17import java.io.File;
18import java.io.IOException;
19import java.util.Arrays;
20
dad84716
GB
21import org.eclipse.tracecompass.datastore.core.interval.HTInterval;
22import org.eclipse.tracecompass.datastore.core.interval.IHTInterval;
23import org.eclipse.tracecompass.datastore.core.interval.IHTIntervalReader;
8b03451b
GB
24import org.eclipse.tracecompass.internal.datastore.core.historytree.HtIo;
25import org.eclipse.tracecompass.internal.provisional.datastore.core.historytree.AbstractHistoryTree.IHTNodeFactory;
26import org.eclipse.tracecompass.internal.provisional.datastore.core.historytree.HTNode;
27import org.eclipse.tracecompass.internal.provisional.datastore.core.historytree.HistoryTreeStub;
28import org.eclipse.tracecompass.internal.provisional.datastore.core.historytree.IHTNode;
29import org.eclipse.tracecompass.internal.provisional.datastore.core.historytree.IHTNode.NodeType;
a145e64d 30import org.eclipse.tracecompass.internal.provisional.datastore.core.historytree.classic.ClassicHistoryTreeStub;
fb7125d6 31import org.eclipse.tracecompass.internal.provisional.datastore.core.historytree.overlapping.OverlappingHistoryTreeStub;
8b03451b
GB
32import org.junit.After;
33import org.junit.Test;
34import org.junit.runner.RunWith;
35import org.junit.runners.Parameterized;
36import org.junit.runners.Parameterized.Parameters;
37
38/**
39 * Test the {@link HTNode} base class for nodes. This class has the different
40 * node types as parameter. It tests specifically the leaf node methods.
41 *
42 * @author Geneviève Bastien
43 * @param <E>
44 * The type of element to add in the nodes
45 * @param <N>
46 * The type of node to test
47 */
48@RunWith(Parameterized.class)
49public class HTNodeTest<E extends IHTInterval, N extends HTNode<E>> {
50
51 /**
52 * Factory to create new objects to insert in the nodes
53 *
54 * @param <T>
55 * The type of object to create
56 */
57 protected interface ObjectFactory<T extends IHTInterval> {
58 /**
59 * Create an object that fits in the tree with the given start/end time
60 *
61 * @param start
62 * The start time
63 * @param end
64 * The end time
65 * @return The object
66 */
67 T createObject(long start, long end);
68 }
69
70 /**
71 * A factory to create base objects for test
72 */
73 protected static final ObjectFactory<HTInterval> BASE_OBJ_FACTORY = (s, e) -> new HTInterval(s, e);
74
75 /** The nodes' block size */
76 protected static final int BLOCKSIZE = HtTestUtils.BLOCKSIZE;
77 /** The maximum number of children for the nodes */
78 protected static final int NB_CHILDREN = 3;
79 private static final long TREE_START = 10L;
80
81 /**
82 * @return The arrays of parameters
83 */
84 @Parameters(name = "{index}: {0}")
85 public static Iterable<Object[]> getParameters() {
86 return Arrays.asList(new Object[][] {
87 { "Leaf node",
88 HTNode.COMMON_HEADER_SIZE,
89 HistoryTreeStub.NODE_FACTORY,
90 HtTestUtils.READ_FACTORY, BASE_OBJ_FACTORY
91 },
a145e64d
AM
92 { "Classic leaf node",
93 HTNode.COMMON_HEADER_SIZE,
94 ClassicHistoryTreeStub.CLASSIC_NODE_FACTORY,
95 HtTestUtils.READ_FACTORY,
fb7125d6
LPD
96 BASE_OBJ_FACTORY
97 },
98 { "Overlapping leaf node",
99 HTNode.COMMON_HEADER_SIZE,
100 OverlappingHistoryTreeStub.OVERLAPPING_NODE_FACTORY,
101 HtTestUtils.READ_FACTORY,
102 BASE_OBJ_FACTORY
103 },
8b03451b
GB
104 });
105 }
106
107 private final HtIo<E, N> fHtIo;
108 private final int fHeaderSize;
109 private final NodeType fType;
110 private final IHTIntervalReader<E> fHtObjectReader;
111 private final IHTNodeFactory<E, N> fNodeFactory;
112 private final ObjectFactory<E> fObjectFactory;
113
114 /**
115 * Constructor
116 *
117 * @param name
118 * The name of the test
119 * @param headerSize
120 * The size of the header for this node type
121 * @param factory
122 * The node factory to use
123 * @param objReader
124 * The factory to read element data from disk
125 * @param objFactory
126 * The factory to create objects for this tree
127 * @throws IOException
128 * Any exception occurring with the file
129 */
130 public HTNodeTest(String name,
131 int headerSize,
132 IHTNodeFactory<E, N> factory,
133 IHTIntervalReader<E> objReader,
134 ObjectFactory<E> objFactory) throws IOException {
135 this(name, headerSize, NodeType.LEAF, factory, objReader, objFactory);
136 }
137
138 /**
139 * Constructor
140 *
141 * @param name
142 * The name of the test
143 * @param headerSize
144 * The size of the header for this node
145 * @param type
146 * The node type
147 * @param nodeFactory
148 * The node factory to use
149 * @param objReader
150 * The factory to read element data from disk
151 * @param objFactory
152 * The factory to create objects for this tree
153 * @throws IOException
154 * Any exception occurring with the file
155 */
156 protected HTNodeTest(String name,
157 int headerSize,
158 NodeType type,
159 IHTNodeFactory<E, N> nodeFactory,
160 IHTIntervalReader<E> objReader,
161 ObjectFactory<E> objFactory) throws IOException {
162 File file = File.createTempFile("tmp", null);
163 assertNotNull(file);
164 fHtObjectReader = objReader;
165 fNodeFactory = nodeFactory;
166
167 fHtIo = new HtIo<>(file,
168 HtTestUtils.BLOCKSIZE,
169 NB_CHILDREN,
170 true,
171 objReader,
172 nodeFactory);
173
174 fHeaderSize = headerSize;
175 fType = type;
176 fObjectFactory = objFactory;
177 }
178
179 /**
180 * Get a new node
181 *
182 * @param seqNb
183 * The sequence number
184 * @param parentNb
185 * The parent sequence number
186 * @param nodeStart
187 * The node start
188 * @return A new node, created with the factory sent in parameter in the
189 * constructor
190 */
191 public N newNode(int seqNb, int parentNb, long nodeStart) {
192 return fNodeFactory.createNode(fType, BLOCKSIZE, NB_CHILDREN, seqNb, parentNb, nodeStart);
193 }
194
195 /**
196 * Delete the file after test
197 */
198 @After
199 public void cleanUp() {
200 fHtIo.deleteFile();
201 }
202
203 /**
204 * Fills a node with objects of length 1, going incrementally
205 *
206 * @param node
207 * The node to fill
208 * @param nbObjects
209 * The number of objects to add
210 * @param start
211 * The start time of the objects
212 */
213 protected void fillNode(HTNode<E> node, int nbObjects, long start) {
214 for (int i = 0; i < nbObjects; i++) {
215 node.add(fObjectFactory.createObject(i + start, i + start + 1));
216 }
217 }
218
219 /**
220 * Get the header size of this node
221 *
222 * @return The header size
223 */
224 protected int getHeaderSize() {
225 return fHeaderSize;
226 }
227
228 /**
229 * Create a new object for this type of node
230 *
231 * @param start
232 * The start of the object
233 * @param end
234 * The end of the object
235 * @return The new object
236 */
237 protected E createObject(long start, long end) {
238 return fObjectFactory.createObject(start, end);
239 }
240
241 /**
242 * Write a node to the file
243 *
244 * @param node
245 * Node to write to disk
246 * @throws IOException
247 * Exceptions while writing to file
248 */
249 protected void write(HTNode<E> node) throws IOException {
250 HtIo<E, N> htIo = fHtIo;
251
252 // Close the node and write it to disk
253 node.writeSelf(htIo.getFileWriter(node.getSequenceNumber()).getChannel());
254 }
255
256 /**
257 * Reads a node from the history tree file
258 *
259 * @param seqNb
260 * The sequence number of the node to get
261 * @return The read node
262 * @throws IOException
263 * Exceptions while reading the node
264 */
265 protected HTNode<E> read(int seqNb) throws IOException {
266 HtIo<E, N> htIo = fHtIo;
267
268 return HTNode.readNode(BLOCKSIZE,
269 NB_CHILDREN,
270 htIo.supplyATReader(seqNb).getChannel(),
271 fHtObjectReader,
272 fNodeFactory);
273
274 }
275
276 /**
277 * Test the leaf node methods without adding the node to disk
278 */
279 @Test
280 public void testNodeData() {
281 HTNode<E> node = newNode(0, -1, TREE_START);
282
283 // Test the values at the beginning
284 assertFalse(node.isOnDisk());
285 assertEquals(TREE_START, node.getNodeStart());
286 assertEquals(Long.MAX_VALUE, node.getNodeEnd());
287 assertEquals(0, node.getSequenceNumber());
288 assertEquals(-1, node.getParentSequenceNumber());
289 assertEquals(fHeaderSize, node.getTotalHeaderSize());
290 assertTrue(node.isEmpty());
291 assertEquals(fType, node.getNodeType());
292 assertEquals(HtTestUtils.BLOCKSIZE - fHeaderSize, node.getNodeFreeSpace());
293 assertEquals(0, node.getNodeUsagePercent());
294
295 // Add an element. It is possible to add an element outside the
296 // boundaries of the node
297 E object = fObjectFactory.createObject(0L, 10L);
298 node.add(object);
299 assertEquals(HtTestUtils.BLOCKSIZE - fHeaderSize - object.getSizeOnDisk(), node.getNodeFreeSpace());
300
301 // Fill the node with objects
302 int nbObjects = (HtTestUtils.BLOCKSIZE - fHeaderSize) / object.getSizeOnDisk();
303 fillNode(node, nbObjects - 1, TREE_START);
304 // Check the free space and sizes
305 int expectedSize = HtTestUtils.BLOCKSIZE - fHeaderSize - object.getSizeOnDisk() * nbObjects;
306 assertEquals(expectedSize, node.getNodeFreeSpace());
307 assertEquals(99, node.getNodeUsagePercent());
308 assertEquals(nbObjects, node.getIntervals().size());
309
310 }
311
312 /**
313 * Test adding an element to a full leaf node
314 */
315 @Test(expected = IllegalArgumentException.class)
316 public void testNodeInvalidAdd() {
317 HTNode<E> node = newNode(0, -1, TREE_START);
318 // Fill the node with objects
319 E object = fObjectFactory.createObject(0L, 10L);
320 int nbObjects = (HtTestUtils.BLOCKSIZE - fHeaderSize) / object.getSizeOnDisk();
321 fillNode(node, nbObjects, TREE_START);
322
323 // Add a new object
324 node.add(object);
325 }
326
327 /**
328 * Test closing a node at an invalid end time
329 */
330 @Test(expected = IllegalArgumentException.class)
331 public void testNodeInvalidEnd() {
332 HTNode<E> node = newNode(0, -1, TREE_START);
333 // Fill the node with objects
334 E object = fObjectFactory.createObject(0L, 10L);
335 int nbObjects = (HtTestUtils.BLOCKSIZE - fHeaderSize) / object.getSizeOnDisk();
336 fillNode(node, nbObjects, TREE_START);
337
338 // Close the node at a wrong time
339 node.closeThisNode(TREE_START);
340 }
341
342 /**
343 * Test adding an element to a closed node
344 */
345 @Test
346 public void testAddToCloseNode() {
347 HTNode<E> node = newNode(0, -1, TREE_START);
348 // Fill the node with objects
349 E object = fObjectFactory.createObject(TREE_START, TREE_START + 10);
350 int nbObjects = (HtTestUtils.BLOCKSIZE - fHeaderSize) / object.getSizeOnDisk();
351 fillNode(node, nbObjects - 1, TREE_START);
352
353 // Add a new object
354 node.closeThisNode(TREE_START + nbObjects);
355 // FIXME: shouldn't this fail?
356 node.add(object);
357
358 }
359
360 /**
361 * test closing, writing and reading a leaf node
362 *
363 * @throws IOException
364 * Exception while writing/reading the file
365 */
366 @Test
367 public void testCloseNode() throws IOException {
368 HTNode<E> node = newNode(0, -1, TREE_START);
369 // Fill the node with objects
370 E object = fObjectFactory.createObject(0L, 10L);
371 int nbObjects = (HtTestUtils.BLOCKSIZE - fHeaderSize) / object.getSizeOnDisk();
372 fillNode(node, nbObjects, TREE_START);
373 assertEquals(nbObjects, node.getIntervals().size());
374
375 // Close the node and write it to disk
376 node.closeThisNode(TREE_START + nbObjects + 1);
377 write(node);
378 assertTrue(node.isOnDisk());
379
380 // Read the node and make sure its data is equal to that of the original
381 // node
382 HTNode<E> readNode = read(0);
383 assertTrue(readNode.isOnDisk());
384 assertEquals(node, readNode);
385 }
386
387 /**
388 * Test the {@link HTNode#getNbChildren()} method
389 */
390 @Test
391 public void testNbChildren() {
392 HTNode<E> node = newNode(0, -1, TREE_START);
393 assertEquals(0, node.getNbChildren());
394 }
395
396 /**
397 * Test the {@link HTNode#getChild(int)} method
398 */
399 @Test(expected = IndexOutOfBoundsException.class)
400 public void testGetChild() {
401 HTNode<E> node = newNode(0, -1, TREE_START);
402 node.getChild(0);
403 }
404
405 /**
406 * Test the {@link HTNode#getLatestChild()} method
407 */
408 @Test(expected = UnsupportedOperationException.class)
409 public void testGetLatestChild() {
410 HTNode<E> node = newNode(0, -1, TREE_START);
411 node.getLatestChild();
412 }
413
414 /**
415 * Test the {@link HTNode#linkNewChild(IHTNode)} method
416 *
417 * @throws IOException
418 * Exceptiosn thrown when reading/writing
419 */
420 @SuppressWarnings("unused")
421 @Test(expected = UnsupportedOperationException.class)
422 public void testLinkNewChild() throws IOException {
423 HTNode<E> node = newNode(0, -1, TREE_START);
424 HTNode<E> childNode = newNode(1, 0, TREE_START);
425 node.linkNewChild(childNode);
426 }
427
428}
This page took 0.040867 seconds and 5 git commands to generate.