blob: 917ebe05a346a932031e309e7a749ec50279c4e9 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2017 École Polytechnique de Montréal
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License 2.0 which
* accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.tracecompass.internal.provisional.datastore.core.historytree;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.util.Arrays;
import org.eclipse.tracecompass.internal.provisional.datastore.core.historytree.AbstractHistoryTree.IHTNodeFactory;
import org.eclipse.tracecompass.datastore.core.interval.IHTInterval;
import org.eclipse.tracecompass.datastore.core.interval.IHTIntervalReader;
import org.eclipse.tracecompass.internal.provisional.datastore.core.historytree.HTNode;
import org.eclipse.tracecompass.internal.provisional.datastore.core.historytree.HistoryTreeStub;
import org.eclipse.tracecompass.internal.provisional.datastore.core.historytree.IHTNode.NodeType;
import org.eclipse.tracecompass.internal.provisional.datastore.core.historytree.classic.ClassicHistoryTreeStub;
import org.eclipse.tracecompass.internal.provisional.datastore.core.historytree.overlapping.OverlappingHistoryTreeStub;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
/**
* Basic test class for core nodes. These tests will test nodes with children.
* We are testing only the current node, so it does not matter if children are
* core or leaf nodes (here they would be core). Specific implementations of
* core nodes can extend this method to add specific tests for their use cases.
*
* @author Geneviève Bastien
* @param <E>
* The type of element to add in the nodes
* @param <N>
* The type of node to test
*/
@RunWith(Parameterized.class)
public class HTCoreNodeTest<E extends IHTInterval, N extends HTNode<E>> extends HTNodeTest<E, N> {
/**
* @return The arrays of parameters
*/
@Parameters(name = "{index}: {0}")
public static Iterable<Object[]> getParameters() {
return Arrays.asList(new Object[][] {
{ "Core node",
HTNode.COMMON_HEADER_SIZE + Integer.BYTES + Integer.BYTES * NB_CHILDREN,
HistoryTreeStub.NODE_FACTORY,
HtTestUtils.READ_FACTORY,
HTNodeTest.BASE_OBJ_FACTORY
},
{ "Classic core node",
HTNode.COMMON_HEADER_SIZE + Integer.BYTES + Integer.BYTES * NB_CHILDREN + Long.BYTES * NB_CHILDREN,
ClassicHistoryTreeStub.CLASSIC_NODE_FACTORY,
HtTestUtils.READ_FACTORY,
HTNodeTest.BASE_OBJ_FACTORY
},
{ "Overlapping core node",
HTNode.COMMON_HEADER_SIZE + Integer.BYTES + Integer.BYTES * NB_CHILDREN + 2 * Long.BYTES * NB_CHILDREN,
OverlappingHistoryTreeStub.OVERLAPPING_NODE_FACTORY,
HtTestUtils.READ_FACTORY,
HTNodeTest.BASE_OBJ_FACTORY
},
});
}
/**
* Constructor
*
* @param name
* The name of the test
* @param headerSize
* The size of the header for this node type
* @param factory
* The node factory to use
* @param readFactory
* The factory to read element data from disk
* @param objFactory
* The factory to create objects for this tree
* @throws IOException
* Any exception occurring with the file
*/
public HTCoreNodeTest(String name,
int headerSize,
IHTNodeFactory<E, N> factory,
IHTIntervalReader<E> readFactory,
ObjectFactory<E> objFactory) throws IOException {
super(name, headerSize, NodeType.CORE, factory, readFactory, objFactory);
}
/**
* Test getting existing children
*/
@Test
public void testGetChild2() {
long start = 10L;
HTNode<E> node = newNode(0, -1, 10L);
assertEquals(0, node.getNbChildren());
// Add the child node to the parent and make sure it can be retrieved
HTNode<E> childNode = newNode(1, 0, start);
node.linkNewChild(childNode);
assertEquals(1, node.getNbChildren());
assertEquals(childNode.getSequenceNumber(), node.getChild(0));
// Add a second child and retrieve both children
HTNode<E> childNode2 = newNode(2, 0, start);
node.linkNewChild(childNode2);
assertEquals(2, node.getNbChildren());
assertEquals(childNode.getSequenceNumber(), node.getChild(0));
assertEquals(childNode2.getSequenceNumber(), node.getChild(1));
// Add a third child with a non-sequential number and retrieve all
// children
HTNode<E> childNode3 = newNode(10, 0, start);
node.linkNewChild(childNode3);
assertEquals(3, node.getNbChildren());
assertEquals(childNode.getSequenceNumber(), node.getChild(0));
assertEquals(childNode2.getSequenceNumber(), node.getChild(1));
assertEquals(childNode3.getSequenceNumber(), node.getChild(2));
}
/**
* Test getting the latest child from a childless node
*/
@Test(expected = IndexOutOfBoundsException.class)
@Override
public void testGetLatestChild() {
super.testGetLatestChild();
}
/**
* Test the {@link HTNode#getLatestChild()} method with children
*/
@Test
public void testGetLatestChild2() {
long start = 10L;
HTNode<E> node = newNode(0, -1, 10L);
assertEquals(0, node.getNbChildren());
// Add the child node to the parent and make sure it can be retrieved
HTNode<E> childNode = newNode(1, 0, start);
node.linkNewChild(childNode);
assertEquals(1, node.getNbChildren());
assertEquals(childNode.getSequenceNumber(), node.getLatestChild());
// Add a second child that becomes the latest child
HTNode<E> childNode2 = newNode(2, 0, start);
node.linkNewChild(childNode2);
assertEquals(2, node.getNbChildren());
assertEquals(childNode2.getSequenceNumber(), node.getLatestChild());
// Add a third child that becomes the latest child
HTNode<E> childNode3 = newNode(10, 0, start);
node.linkNewChild(childNode3);
assertEquals(3, node.getNbChildren());
assertEquals(childNode3.getSequenceNumber(), node.getLatestChild());
}
@Test
@Override
public void testLinkNewChild() throws IOException {
E object = createObject(10L, 11L);
long time = 10L;
// Create and fill 2 nodes
int nbObjects = (HtTestUtils.BLOCKSIZE - getHeaderSize()) / object.getSizeOnDisk();
HTNode<E> node = newNode(0, -1, time);
fillNode(node, nbObjects, time);
HTNode<E> childNode = newNode(1, 0, time);
fillNode(childNode, nbObjects, time);
// Add the child node to the parent and make sure it was added
node.linkNewChild(childNode);
assertEquals(0, childNode.getNbChildren());
assertEquals(1, node.getNbChildren());
// Close the first child, then fill and add a second one
time = time + nbObjects + 1;
childNode.closeThisNode(time);
HTNode<E> childNode2 = newNode(2, 0, time);
fillNode(childNode2, nbObjects, time);
node.linkNewChild(childNode2);
assertEquals(0, childNode2.getNbChildren());
assertEquals(2, node.getNbChildren());
// Close the second child, then fill and add a third one
time = time + nbObjects + 1;
childNode2.closeThisNode(time);
HTNode<E> childNode3 = newNode(3, 0, time);
fillNode(childNode3, nbObjects, time);
node.linkNewChild(childNode3);
assertEquals(0, childNode3.getNbChildren());
assertEquals(3, node.getNbChildren());
time = time + nbObjects + 1;
// Try to add a 4th child, there should be no place for it
HTNode<E> noPlace = newNode(4, 0, time);
Exception exception = null;
try {
node.linkNewChild(noPlace);
} catch (IllegalStateException e) {
exception = e;
}
assertNotNull(exception);
// Close the last child and first node
childNode3.closeThisNode(time);
node.closeThisNode(time);
// Write them all to disk
write(node);
write(childNode);
write(childNode2);
write(childNode3);
assertTrue(node.isOnDisk());
assertTrue(childNode.isOnDisk());
assertTrue(childNode2.isOnDisk());
assertTrue(childNode3.isOnDisk());
// Read the node and make sure its data is equal to that of the original
// node
HTNode<E> readNode = read(0);
HTNode<E> readChildNode = read(1);
HTNode<E> readChildNode2 = read(2);
HTNode<E> readChildNode3 = read(3);
assertTrue(readNode.isOnDisk());
assertEquals(node, readNode);
assertTrue(readChildNode.isOnDisk());
assertEquals(childNode, readChildNode);
assertTrue(readChildNode2.isOnDisk());
assertEquals(childNode2, readChildNode2);
assertTrue(readChildNode3.isOnDisk());
assertEquals(childNode3, readChildNode3);
}
}