/**
Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved.
Contact:
SYSTAP, LLC DBA Blazegraph
2501 Calvert ST NW #106
Washington, DC 20008
licenses@blazegraph.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Created on Aug 27, 2010
*/
package com.bigdata.bop.util;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.FutureTask;
import junit.framework.TestCase2;
import com.bigdata.bop.BOp;
import com.bigdata.bop.BOpBase;
import com.bigdata.bop.BOpContext;
import com.bigdata.bop.BOpUtility;
import com.bigdata.bop.BadBOpIdTypeException;
import com.bigdata.bop.Constant;
import com.bigdata.bop.DuplicateBOpIdException;
import com.bigdata.bop.IBindingSet;
import com.bigdata.bop.IVariable;
import com.bigdata.bop.NV;
import com.bigdata.bop.NotPipelineOpException;
import com.bigdata.bop.PipelineOp;
import com.bigdata.bop.Var;
/**
* Unit tests for {@link BOpUtility}.
*
* @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
* @version $Id$
*/
public class TestBOpUtility extends TestCase2 {
/**
*
*/
public TestBOpUtility() {
}
/**
* @param name
*/
public TestBOpUtility(String name) {
super(name);
}
/**
* Unit test for {@link BOpUtility#getArgumentVariables(BOp)} and
* {@link BOpUtility#getArgumentVariableCount(BOp)}.
*
* @todo unit test for iterator over arguments first, then over annotations
* which are bops, then over bop with annotations and finally over
* depth first recursion of (bop) and (bop+annotation bops).
* Everything else should just build on that. Declare what order is
* obeyed by those iterators, e.g., visitation order is pre-order or
* post-order for the argument hierarchy.
*
* @todo test methods which do recursion to verify annotations handled if
* null or never null.
*/
public void test_getArgumentVariables() {
{
final BOp op1 = new BOpBase(new BOp[] { Var.var("y") }, null/* annotations */);
assertEquals(1, op1.arity());
assertSameIterator(new Object[] { Var.var("y") }, op1.argIterator());
assertSameIterator(new Object[] { Var.var("y") }, BOpUtility
.getArgumentVariables(op1));
assertEquals(1, BOpUtility.getArgumentVariableCount(op1));
}
{
final BOp op2 = new BOpBase(
new BOp[] { Var.var("x"), Var.var("y") }, null/* annotations */);
assertEquals(2,op2.arity());
assertSameIterator(new Object[] { Var.var("x"), Var.var("y") }, op2
.argIterator());
assertSameIterator(new Object[] { Var.var("x"), Var.var("y") },
BOpUtility.getArgumentVariables(op2));
assertEquals(2, BOpUtility.getArgumentVariableCount(op2));
}
{
final BOp op3 = new BOpBase(new BOp[] { new Constant<String>("x"),
Var.var("y") }, null/* annotations */);
assertSameIterator(new Object[] { new Constant<String>("x"),
Var.var("y") }, op3.argIterator());
assertSameIterator(new Object[] { Var.var("y") }, BOpUtility
.getArgumentVariables(op3));
assertEquals(1, BOpUtility.getArgumentVariableCount(op3));
}
}
/**
* Unit test for {@link BOpUtility#preOrderIterator(BOp)}.
*/
public void test_preOrderIterator() {
// final Stack<INodeOrAttribute> context = new Stack<INodeOrAttribute>();
final BOp op2 = new BOpBase(new BOp[] { Var.var("x") }, null/* annotations */);
// root
final BOp root = new BOpBase(new BOp[] { // root args[]
new Constant<String>("x"), Var.var("y"), op2 }, null/* annotations */);
final Object[] expected = new Object[]{//
root,//
new Constant<String>("x"),//
Var.var("y"),//
op2,//
Var.var("x"),//
};
int i = 0;
final Iterator<BOp> itr = BOpUtility.preOrderIterator(root);
while (itr.hasNext()) {
final BOp t = itr.next();
if (log.isInfoEnabled())
log.info(i + " : " + t);
assertTrue("index=" + i + ", expected=" + expected[i] + ", actual="
+ t, expected[i].equals(t));
i++;
}
assertEquals(i, expected.length);
assertSameIterator(expected, BOpUtility.preOrderIterator(root));
}
/**
* Unit test for {@link BOpUtility#postOrderIterator(BOp)}.
*/
public void test_postOrderIterator() {
final BOp op2 = new BOpBase(new BOp[] { Var.var("x") }, null/* annotations */);
// root
final BOp root = new BOpBase(new BOp[] { // root args[]
new Constant<String>("x"), Var.var("y"), op2 }, null/* annotations */);
final Object[] expected = new Object[]{//
new Constant<String>("x"),//
Var.var("y"),//
Var.var("x"),//
op2,//
root,//
};
int i = 0;
final Iterator<BOp> itr = BOpUtility.postOrderIterator(root);
while (itr.hasNext()) {
final BOp t = itr.next();
if (log.isInfoEnabled())
log.info(i + " : " + t);
assertTrue("index=" + i + ", expected=" + expected[i] + ", actual="
+ t, expected[i].equals(t));
i++;
}
assertEquals(i, expected.length);
assertSameIterator(expected, BOpUtility.postOrderIterator(root));
}
/**
* Unit test for {@link BOpUtility#annotationOpIterator(BOp)}.
* <p>
* Note: This test depends on the LinkedHashMap imposing the ordering in
* which the annotations are declared.
*/
public void test_annotationOpIterator() {
/*
* Verify that we get an empty iterator for an operator without any
* annotations.
*/
{
final BOp a1 = new BOpBase(new BOp[] { Var.var("a") }, null/* annotations */);
assertFalse(BOpUtility.annotationOpIterator(a1).hasNext());
}
/*
* Verify that we get an empty iterator for an operator without any
* annotations which are themselves operators.
*/
{
final BOp a1 = new BOpBase(new BOp[] { Var.var("a") }, // annotations
NV.asMap(new NV[] {//
new NV("baz", "3"),//
}));
assertFalse(BOpUtility.annotationOpIterator(a1).hasNext());
}
/*
* Verify that we get we visit the annotations which are themselves
* operators, but not non-operator annotations.
*/
{
final BOp op = new BOpBase(//
// children
new BOp[] {},//
// annotations
NV.asMap(new NV[] {//
new NV("foo", Var.var("x")),//
new NV("bar", new Constant<String>("2")),//
new NV("baz", "3"),//
}));
final BOp[] expected = new BOp[] {//
Var.var("x"),//
new Constant<String>("2"),//
};
int i = 0;
final Iterator<BOp> itr = BOpUtility.annotationOpIterator(op);
while (itr.hasNext()) {
final BOp t = itr.next();
if(log.isInfoEnabled())
log.info(i + " : " + t);
assertTrue("index=" + i + ", expected=" + expected[i]
+ ", actual=" + t, expected[i].equals(t));
i++;
}
assertEquals(i, expected.length);
assertSameIterator(expected, BOpUtility.annotationOpIterator(op));
}
}
// /**
// * Unit test for {@link BOpUtility#annotationOpPreOrderIterator(BOp)}
// * (pre-order traversal of the operator annotations of the given operator
// * without recursion through the children of the given operator)).
// * <p>
// * Note: This test depends on the LinkedHashMap imposing the ordering in
// * which the annotations are declared.
// */
// public void test_annotationOpPreOrderIterator() {
//
// final BOp a1 = new BOpBase(new BOp[]{Var.var("a")},null/*annotations*/);
// final BOp a2 = new BOpBase(new BOp[]{Var.var("b")},null/*annotations*/);
// // Note: [a3] tests recursion (annotations of annotations).
// final BOp a3 = new BOpBase(new BOp[] { Var.var("z") }, NV
// .asMap(
// new NV[] { //
// new NV("baz", a2),//
// new NV("baz2", "skip")//
// }//
// ));
//
// final BOp op2 = new BOpBase(new BOp[] { Var.var("x") }, NV.asMap(new NV[]{//
// new NV("foo1",a1),//
// new NV("foo2",a3),//
// new NV("foo3", "skip"),//
// }));
//
// final Object[] expected = new Object[]{//
// op2,//
// a1,//
// Var.var("a"),//
// a3,//
// a2,//
// Var.var("b"),//
// Var.var("z"),//
// Var.var("x"),//
// };
// int i = 0;
// final Iterator<BOp> itr = BOpUtility
// .annotationOpPreOrderIterator(op2);
// while (itr.hasNext()) {
// final BOp t = itr.next();
//// System.out.println(i + " : " + t);
//// assertTrue("index=" + i + ", expected=" + expected[i] + ", actual="
//// + t, expected[i].equals(t));
// i++;
// }
// assertEquals(i, expected.length);
//
// assertSameIterator(expected, BOpUtility
// .annotationOpPreOrderIterator(op2));
//
// }
/**
* Unit test for {@link BOpUtility#preOrderIteratorWithAnnotations(BOp)}.
* <p>
* Note: This test depends on the LinkedHashMap imposing the ordering in
* which the annotations are declared.
*/
public void test_preOrderIteratorWithAnnotations() {
final BOp a1 = new BOpBase(new BOp[]{Var.var("a")},null/*annotations*/);
final BOp a2 = new BOpBase(new BOp[]{Var.var("b")},null/*annotations*/);
// Note: [a3] tests recursion (annotations of annotations).
final BOp a3 = new BOpBase(new BOp[] { Var.var("z") }, NV
.asMap(
new NV[] { //
new NV("baz", a2),//
new NV("baz2", "skip")//
}//
));
final BOp op2 = new BOpBase(new BOp[] { Var.var("x") }, NV.asMap(new NV[]{//
new NV("foo1",a1),//
new NV("foo2",a3),//
new NV("foo3", "skip"),//
}));
// root
final BOp root = new BOpBase(new BOp[] { // root args[]
new Constant<String>("12"), Var.var("y"), op2 }, null/* annotations */);
final Object[] expected = new Object[]{//
root,//
new Constant<String>("12"),//
Var.var("y"),//
op2,//
a1,//
Var.var("a"),//
a3,//
a2,//
Var.var("b"),//
Var.var("z"),//
Var.var("x"),//
};
int i = 0;
final Iterator<BOp> itr = BOpUtility
.preOrderIteratorWithAnnotations(root);
while (itr.hasNext()) {
final BOp t = itr.next();
if(log.isInfoEnabled())
log.info(i + " : " + t);
assertTrue("index=" + i + ", expected=" + expected[i] + ", actual="
+ t, expected[i].equals(t));
i++;
}
assertEquals(i, expected.length);
assertSameIterator(expected, BOpUtility
.preOrderIteratorWithAnnotations(root));
}
/**
* Unit test for {@link BOpUtility#postOrderIteratorWithAnnotations(BOp)}.
* <p>
* Note: This test depends on the LinkedHashMap imposing the ordering in
* which the annotations are declared.
*
* @see <a href="http://trac.bigdata.com/ticket/1210" >
* BOpUtility.postOrderIteratorWithAnnotations() is has wrong visitation
* order. </a>
*/
public void test_postOrderIteratorWithAnnotations() {
final BOp a1 = new BOpBase(new BOp[]{Var.var("a")},null/*annotations*/);
final BOp a2 = new BOpBase(new BOp[]{Var.var("b")},null/*annotations*/);
// Note: [a3] tests recursion (annotations of annotations).
final BOp a3 = new BOpBase(new BOp[] { Var.var("z") }, NV
.asMap(
new NV[] { //
new NV("baz", a2),//
new NV("baz2", "skip")//
}//
));
final BOp op2 = new BOpBase(new BOp[] { Var.var("x") }, NV.asMap(new NV[]{//
new NV("foo1",a1),//
new NV("foo2",a3),//
new NV("foo3", "skip"),//
}));
// root
final BOp root = new BOpBase(new BOp[] { // root args[]
new Constant<String>("12"), Var.var("y"), op2 }, null/* annotations */);
// final BOp[] expectedMGC = new BOp[] {// MGC - Arguments THEN Annotation
//
// // root annotations {}
//
// // root arguments {"12", ?y, op2}
// new Constant<String>("12"), // root[0]
// Var.var("y"), // root[1]
//
// // op2 annotations {a1, a3}
// // a1 children
// Var.var("x"), // op2[0]
// Var.var("a"), // a1[0]
// a1, // op2 anno
//
// // a3 arguments {?z}
// Var.var("z"), // a3[0]
// Var.var("b"), // a2[0]
// a2, // a3 anno
// a3, // op2 anno
//
// op2, // root[2]
//
// root,//
// };
final BOp[] expected = new BOp[] { // Annotations THEN Arguments
// root annotations {}
// root arguments {"12", ?y, op2}
new Constant<String>("12"),//
Var.var("y"),//
// op2 annotations {a1, a3}
// a1 children
Var.var("a"),//
a1,//
// a3 annotations {a2}
// a2 children {b}
Var.var("b"),//
a2,//
// a3 arguments {?z}
Var.var("z"),//
a3,//
// op2 arguments.
Var.var("x"),//
op2,//
root,//
};
final Object[] actual = unwrap(BOpUtility.postOrderIteratorWithAnnotations(root));
assertTrue(actual.length == expected.length);
for (int i = 0; i < expected.length; i++){
assertTrue("index=" + i + ", expected=" + expected[i] + ", actual="
+ actual[i], expected[i].equals(actual[i]));
}
}
private Object[] unwrap(Iterator<BOp> iter) {
final ArrayList<BOp> array = new ArrayList<BOp>();
while (iter.hasNext()) {
array.add(iter.next());
}
return array.toArray();
}
/**
* Unit test for {@link BOpUtility#getSpannedVariables(BOp)}.
*/
public void test_getSpannedVariables() {
final BOp a1 = new BOpBase(new BOp[]{Var.var("a")},null/*annotations*/);
final BOp a2 = new BOpBase(new BOp[]{Var.var("b")},null/*annotations*/);
// Note: [a3] tests recursion (annotations of annotations).
final BOp a3 = new BOpBase(new BOp[] { Var.var("z") }, NV
.asMap(
new NV[] { //
new NV("baz", a2),//
new NV("baz2", "skip")//
}//
));
final BOp op2 = new BOpBase(new BOp[] { Var.var("x") }, NV.asMap(new NV[]{//
new NV("foo1",a1),//
new NV("foo2",a3),//
new NV("foo3", "skip"),//
}));
// root
final BOp root = new BOpBase(new BOp[] { // root args[]
new Constant<String>("12"), Var.var("y"), op2 }, null/* annotations */);
final Object[] expected = new Object[]{//
Var.var("y"),//
Var.var("a"),//
Var.var("b"),//
Var.var("z"),//
Var.var("x"),//
};
int i = 0;
final Iterator<IVariable<?>> itr = BOpUtility
.getSpannedVariables(root);
while (itr.hasNext()) {
final BOp t = itr.next();
if(log.isInfoEnabled())
log.info(i + " : " + t);
assertTrue("index=" + i + ", expected=" + expected[i] + ", actual="
+ t, expected[i].equals(t));
i++;
}
assertEquals(i, expected.length);
assertSameIterator(expected, BOpUtility
.getSpannedVariables(root));
}
/**
* Unit test for {@link BOpUtility#getIndex(BOp)} using valid inputs.
*/
public void test_getIndex() {
final BOp op1 = new MockPipelineOp(new BOp[] {}, NV.asMap(new NV[] {//
new NV(BOp.Annotations.BOP_ID, 1),//
}));
final BOp op2 = new MockPipelineOp(new BOp[] { op1 },
NV.asMap(new NV[] { //
new NV(BOp.Annotations.BOP_ID, 2),//
}));
final BOp op3 = new MockPipelineOp(new BOp[] { op2 },
NV.asMap(new NV[] {//
new NV(BOp.Annotations.BOP_ID, 3),//
}));
// root
final BOp root = new MockPipelineOp(new BOp[] { // root args[]
op3 }, NV.asMap(new NV[] {//
new NV(BOp.Annotations.BOP_ID, 4),//
}));
// index the operator tree.
final Map<Integer, BOp> map = BOpUtility.getIndex(root);
assertTrue(op1 == map.get(1));
assertTrue(op2 == map.get(2));
assertTrue(op3 == map.get(3));
assertTrue(root == map.get(4));
assertNull(map.get(5));
assertEquals(4, map.size());
// verify map is immutable.
try {
map.put(Integer.valueOf(1),op1);
fail("Expecting: "+UnsupportedOperationException.class);
} catch(UnsupportedOperationException ex) {
if(log.isInfoEnabled())
log.info("Ignoring expected exception: "+ex);
}
}
/**
* Unit test verifies that annotations are not indexed (they are outside of
* the pipeline).
*/
public void test_getIndex_doesNotIndexAnnotations() {
// Should not be indexed since only appears as annotation.
final BOp a2 = new MockPipelineOp(new BOp[]{},NV.asMap(new NV[]{//
new NV(BOp.Annotations.BOP_ID,1),//
}));
// References [a2] as an annotation.
final BOp a3 = new MockPipelineOp(new BOp[] {}, NV.asMap(new NV[] { //
new NV(BOp.Annotations.BOP_ID, 2),//
new NV("baz", a2),//
new NV("baz2", "skip") //
}//
));
// index the operator tree (should succeed).
final Map<Integer, BOp> map = BOpUtility.getIndex(a3);
assertNull(map.get(1)); // annotation was not indexed.
assertEquals(a3, map.get(2)); // other operators were indexed.
assertEquals(1, map.size()); // map contained just the indexed ops.
}
/**
* Unit test for {@link BOpUtility#getIndex(BOp)} in which we verify that
* it rejects operator trees having duplicate operator ids.
*/
public void test_getIndex_rejectsDuplicateBOpIds() {
final BOp op2 = new MockPipelineOp(new BOp[] {}, NV.asMap(new NV[] {//
new NV(BOp.Annotations.BOP_ID, 4),//
}));
// root
final BOp root = new MockPipelineOp(new BOp[] { // root args[]
op2 }, NV.asMap(new NV[] {//
new NV(BOp.Annotations.BOP_ID, 4),//
}));
try {
BOpUtility.getIndex(root);
fail("Expecting: " + DuplicateBOpIdException.class);
} catch (DuplicateBOpIdException ex) {
if (log.isInfoEnabled())
log.info("Ignoring expected exception: " + ex);
}
}
/**
* Unit test for {@link BOpUtility#getIndex(BOp)} in which we verify that it
* rejects operator trees with operator ids which are not {@link Integer}s.
*/
public void test_getIndex_rejectsNonIntegerIds() {
// root
final BOp root = new MockPipelineOp(new BOp[] {}, NV.asMap(new NV[] {//
new NV(BOp.Annotations.BOP_ID, "4"),//
}));
try {
BOpUtility.getIndex(root);
fail("Expecting: " + BadBOpIdTypeException.class);
} catch (BadBOpIdTypeException ex) {
if (log.isInfoEnabled())
log.info("Ignoring expected exception: " + ex);
}
}
/*
* Note: Since annotations are not indexed it is no longer possible to
* encounter the same operator more than once in the pipeline.
*/
// /**
// * Unit test for {@link BOpUtility#getIndex(BOp)} in which we verify that it
// * rejects operator trees in which the same {@link BOp} reference appears
// * more than once but allows duplicate {@link IVariable}s and
// * {@link IConstant}s.
// */
// public void test_getIndex_rejectsDuplicateBOps() {
//
// final IConstant<Long> c1 = new Constant<Long>(12L);
// final IVariable<?> v1 = Var.var("y");
//
// /*
// * Operator tree with duplicate variable and duplicate constant refs.
// */
// {
// // root
// final BOp root = new BOpBase(new BOp[] { // root args[]
// c1, v1 }, NV.asMap(new NV[] {//
// new NV(BOp.Annotations.BOP_ID, 4),//
// new NV("foo", v1), // duplicate variable.
// new NV("bar", c1) // duplicate variable.
// }));
//
// // should be Ok.
// final Map<Integer, BOp> map = BOpUtility.getIndex(root);
//
// assertTrue(root == map.get(4));
//
// }
//
//// /*
//// * Operator tree with duplicate bop which is neither a var nor or a
//// * constant.
//// */
//// {
////
//// /*
//// * bop w/o bopId is used to verify correct detection of duplicate
//// * references (it has to be a PipelineOp).
//// */
//// final BOp op2 = new PipelineOp(new BOp[]{}, null/*annotations*/) {
////
//// private static final long serialVersionUID = 1L;
////
//// @Override
//// public FutureTask<Void> eval(BOpContext<IBindingSet> context) {
//// throw new UnsupportedOperationException();
//// }
////
//// };
////
//// // root
//// final BOp root = new BOpBase(new BOp[] { // root args[]
//// op2, op2 }, NV.asMap(new NV[] {//
//// new NV(BOp.Annotations.BOP_ID, 4),//
//// }));
////
//// try {
//// BOpUtility.getIndex(root);
//// fail("Expecting: " + DuplicateBOpException.class);
//// } catch (DuplicateBOpException ex) {
//// if (log.isInfoEnabled())
//// log.info("Ignoring expected exception: " + ex);
//// }
//// }
//
// }
/**
* Unit test verifies that non-pipeline operators are rejected.
*/
public void test_getIndex_rejectsNonPipelineOps() {
final BOp a1 = new BOpBase(new BOp[] { Var.var("a") },
NV.asMap(new NV[] {//
new NV(BOp.Annotations.BOP_ID, 1),//
}));
final BOp a2 = new MockPipelineOp(new BOp[] { a1 }, NV.asMap(new NV[] {//
new NV(BOp.Annotations.BOP_ID, 2),//
}));
final BOp a3 = new MockPipelineOp(new BOp[] { Var.var("a") },
NV.asMap(new NV[] {//
new NV(BOp.Annotations.BOP_ID, 1),//
}));
final BOp a4 = new MockPipelineOp(
new BOp[] { new Constant<String>("a") }, NV.asMap(new NV[] {//
new NV(BOp.Annotations.BOP_ID, 1),//
}));
// non-pipeline op.
try {
BOpUtility.getIndex(a1);
fail("Expecting: " + NotPipelineOpException.class);
} catch (NotPipelineOpException ex) {
if (log.isInfoEnabled())
log.info("Ignoring expected exception: " + ex);
}
// pipeline op with non-pipeline child.
try {
BOpUtility.getIndex(a2);
fail("Expecting: " + NotPipelineOpException.class);
} catch (NotPipelineOpException ex) {
if (log.isInfoEnabled())
log.info("Ignoring expected exception: " + ex);
}
// pipeline op with non-pipeline child which is a variable.
try {
BOpUtility.getIndex(a3);
fail("Expecting: " + NotPipelineOpException.class);
} catch (NotPipelineOpException ex) {
if (log.isInfoEnabled())
log.info("Ignoring expected exception: " + ex);
}
// pipeline op with non-pipeline child which is a constant.
try {
BOpUtility.getIndex(a4);
fail("Expecting: " + NotPipelineOpException.class);
} catch (NotPipelineOpException ex) {
if (log.isInfoEnabled())
log.info("Ignoring expected exception: " + ex);
}
}
private static class MockPipelineOp extends PipelineOp {
private static final long serialVersionUID = 1L;
public MockPipelineOp(BOp[] args, Map<String, Object> annotations) {
super(args, annotations);
}
public MockPipelineOp(MockPipelineOp op) {
super(op);
}
@Override
public FutureTask<Void> eval(BOpContext<IBindingSet> context) {
throw new UnsupportedOperationException();
}
}
// /**
// * A conditional join group:
// *
// * <pre>
// * (a b)
// * optional {
// * (b c)
// * (c d)
// * }
// * </pre>
// *
// * where the groupId for the optional join group is ONE (1). The test should
// * locate the first {@link PipelineJoin} in that join group, which is the
// * one reading on the <code>(b c)</code> access path.
// */
// public void test_getFirstBOpIdForConditionalGroup() {
//
// final String namespace = "kb";
//
// final int startId = 1; //
// final int joinId1 = 2; // : base join group.
// final int predId1 = 3; // (a b)
// final int joinId2 = 4; // : joinGroup1
// final int predId2 = 5; // (b c)
// final int joinId3 = 6; // : joinGroup1
// final int predId3 = 7; // (c d)
// final int sliceId = 8; //
//
// final IVariable<?> a = Var.var("a");
// final IVariable<?> b = Var.var("b");
// final IVariable<?> c = Var.var("c");
// final IVariable<?> d = Var.var("d");
//
// final Integer joinGroup1 = Integer.valueOf(1);
//
// final PipelineOp startOp = new StartOp(new BOp[] {},
// NV.asMap(new NV[] {//
// new NV(Predicate.Annotations.BOP_ID, startId),//
// new NV(SliceOp.Annotations.EVALUATION_CONTEXT,
// BOpEvaluationContext.CONTROLLER),//
// }));
//
// final Predicate<?> pred1Op = new Predicate<E>(
// new IVariableOrConstant[] { a, b }, NV
// .asMap(new NV[] {//
// new NV(Predicate.Annotations.RELATION_NAME,
// new String[] { namespace }),//
// new NV(Predicate.Annotations.BOP_ID, predId1),//
// new NV(Annotations.TIMESTAMP, ITx.READ_COMMITTED),//
// }));
//
// final Predicate<?> pred2Op = new Predicate<E>(
// new IVariableOrConstant[] { b, c }, NV
// .asMap(new NV[] {//
// new NV(Predicate.Annotations.RELATION_NAME,
// new String[] { namespace }),//
// new NV(Predicate.Annotations.BOP_ID, predId2),//
// new NV(Annotations.TIMESTAMP, ITx.READ_COMMITTED),//
// }));
//
// final Predicate<?> pred3Op = new Predicate<E>(
// new IVariableOrConstant[] { c, d }, NV
// .asMap(new NV[] {//
// new NV(Predicate.Annotations.RELATION_NAME,
// new String[] { namespace }),//
// new NV(Predicate.Annotations.BOP_ID, predId3),//
// new NV(Annotations.TIMESTAMP, ITx.READ_COMMITTED),//
// }));
//
// final PipelineOp join1Op = new PipelineJoin<E>(//
// new BOp[]{startOp},//
// new NV(Predicate.Annotations.BOP_ID, joinId1),//
// new NV(PipelineJoin.Annotations.PREDICATE,pred1Op));
//
// final PipelineOp join2Op = new PipelineJoin<E>(//
// new BOp[] { join1Op },//
// new NV(Predicate.Annotations.BOP_ID, joinId2),//
// new NV(PipelineOp.Annotations.CONDITIONAL_GROUP, joinGroup1),//
// new NV(PipelineJoin.Annotations.PREDICATE, pred2Op),//
// // join is optional.
// new NV(PipelineJoin.Annotations.OPTIONAL, true),//
// // optional target is the same as the default target.
// new NV(PipelineOp.Annotations.ALT_SINK_REF, sliceId));
//
// final PipelineOp join3Op = new PipelineJoin<E>(//
// new BOp[] { join2Op },//
// new NV(Predicate.Annotations.BOP_ID, joinId3),//
// new NV(PipelineOp.Annotations.CONDITIONAL_GROUP, joinGroup1),//
// new NV(PipelineJoin.Annotations.PREDICATE, pred3Op),//
// // join is optional.
// new NV(PipelineJoin.Annotations.OPTIONAL, true),//
// // optional target is the same as the default target.
// new NV(PipelineOp.Annotations.ALT_SINK_REF, sliceId));
//
// final PipelineOp sliceOp = new SliceOp(//
// new BOp[]{join3Op},
// NV.asMap(new NV[] {//
// new NV(BOp.Annotations.BOP_ID, sliceId),//
// new NV(BOp.Annotations.EVALUATION_CONTEXT,
// BOpEvaluationContext.CONTROLLER),//
// }));
//
// final PipelineOp query = sliceOp;
//
// // verify found.
// assertEquals(Integer.valueOf(joinId2), BOpUtility
// .getFirstBOpIdForConditionalGroup(query, joinGroup1));
//
// // verify not-found.
// assertEquals(null, BOpUtility.getFirstBOpIdForConditionalGroup(query,
// Integer.valueOf(2)/* groupId */));
//
// }
/**
* Unit test for {@link BOpUtility#getParent(BOp, BOp)}.
*/
public void test_getParent() {
final BOp a1 = new BOpBase(new BOp[]{Var.var("a")},NV.asMap(new NV[]{//
new NV(BOp.Annotations.BOP_ID,1),//
}));
final BOp a2 = new BOpBase(new BOp[]{Var.var("b")},NV.asMap(new NV[]{//
new NV(BOp.Annotations.BOP_ID,2),//
}));
// Note: [a3] tests recursion (annotations of annotations).
final BOp a3 = new BOpBase(new BOp[] { Var.var("z") , a1}, NV
.asMap(
new NV[] { //
new NV("baz", a2),//
new NV("baz2", "skip")//
}//
));
final BOp op2 = new BOpBase(new BOp[] { Var.var("x") , a3 }, NV.asMap(new NV[]{//
new NV("foo1",a1),//
new NV("foo3", "skip"),//
new NV(BOp.Annotations.BOP_ID,3),//
}));
// root
final BOp root = new BOpBase(new BOp[] { // root args[]
new Constant<String>("12"), Var.var("y"), op2 }, NV.asMap(new NV[]{//
new NV(BOp.Annotations.BOP_ID, 4),//
}));
assertTrue(root == BOpUtility.getParent(root, op2));
assertTrue(op2 == BOpUtility.getParent(root, Var.var("x")));
assertTrue(op2 == BOpUtility.getParent(root, a3));
assertTrue(a3 == BOpUtility.getParent(root, a1));
try {
BOpUtility.getParent(null/* root */, op2);
fail("Expecting: " + IllegalArgumentException.class);
} catch (IllegalArgumentException ex) {
if (log.isInfoEnabled())
log.info("Ignoring expected exception: " + ex);
}
try {
BOpUtility.getParent(root, null/* op */);
fail("Expecting: " + IllegalArgumentException.class);
} catch (IllegalArgumentException ex) {
if (log.isInfoEnabled())
log.info("Ignoring expected exception: " + ex);
}
}
/**
* Unit test for locating the left-deep child at which pipeline evaluation
* should begin.
*/
public void test_getPipelineStart() {
final int aid = 0;
final int bid = 1;
final int cid = 2;
final BOp a = new BOpBase(new BOp[] {}, NV.asMap(new NV[] { new NV(
BOp.Annotations.BOP_ID, aid) }));
final BOp b = new BOpBase(new BOp[] {}, NV.asMap(new NV[] { new NV(
BOp.Annotations.BOP_ID, bid) }));
final BOp c = new BOpBase(new BOp[] { a, b }, NV
.asMap(new NV[] { new NV(BOp.Annotations.BOP_ID, cid) }));
assertEquals(a, BOpUtility.getPipelineStart(a));
assertEquals(b, BOpUtility.getPipelineStart(b));
assertEquals(a, BOpUtility.getPipelineStart(c));
}
/**
* Unit tests for extracting the left-deep evaluation order for the query
* pipeline.
* <p>
* - test when the 1st operator is a control operator.
* <p>
* - test when there is an embedded control operator (subquery).
* <p>
* Note: this is not testing with left/right branches in the query plan.
* That sort of plan is not currently supported by pipeline evaluation.
*/
public void test_getEvaluationOrder() {
final BOp op2 = new MyPipelineOp(new BOp[]{},NV.asMap(//
new NV(BOp.Annotations.BOP_ID,1)//
// new NV(BOp.Annotations.CONTROLLER,false)//
));
final BOp op1 = new MyPipelineOp(new BOp[]{op2},NV.asMap(//
new NV(BOp.Annotations.BOP_ID,2)//
// new NV(BOp.Annotations.CONTROLLER,false)//
));
final BOp op3 = new MyPipelineOp(new BOp[]{op1},NV.asMap(//
new NV(BOp.Annotations.BOP_ID,3),//
new NV(BOp.Annotations.CONTROLLER,true)//
));
assertEquals(new Integer[]{1,2,3},BOpUtility.getEvaluationOrder(op3));
}
private static class MyPipelineOp extends PipelineOp {
private static final long serialVersionUID = 1L;
/** Deep copy constructor. */
protected MyPipelineOp(MyPipelineOp op) {
super(op);
}
/** Shallow copy constructor. */
protected MyPipelineOp(BOp[] args, Map<String, Object> annotations) {
super(args, annotations);
}
@Override
public FutureTask<Void> eval(BOpContext<IBindingSet> context) {
return null;
}
}
}