/** 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 Jun 9, 2011 */ package com.bigdata.rdf.lexicon; import junit.framework.TestCase2; import org.openrdf.model.Value; import org.openrdf.model.impl.BNodeImpl; import org.openrdf.model.impl.LiteralImpl; import org.openrdf.model.impl.URIImpl; import org.openrdf.model.vocabulary.RDF; import com.bigdata.btree.BTree; import com.bigdata.btree.IIndex; import com.bigdata.btree.keys.IKeyBuilder; import com.bigdata.rawstore.IRawStore; import com.bigdata.rawstore.SimpleMemoryRawStore; import com.bigdata.rdf.internal.IV; import com.bigdata.rdf.internal.VTE; import com.bigdata.rdf.internal.impl.BlobIV; import com.bigdata.rdf.model.BigdataValue; import com.bigdata.rdf.model.BigdataValueFactory; import com.bigdata.rdf.model.BigdataValueFactoryImpl; /** * Test suite for the {@link BlobsWriteTask}. * * @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a> * @version $Id$ */ public class TestBlobsWriteTask extends TestCase2 { /** * */ public TestBlobsWriteTask() { } /** * @param name */ public TestBlobsWriteTask(String name) { super(name); } public void test_add_abc() { // The values that we will be testing with. final Value[] valuesIn = new Value[] {// new LiteralImpl("abc") // }; doAddTermsTest(valuesIn, false/* toldBNodes */); } public void test_add_emptyLiteral() { // The values that we will be testing with. final Value[] valuesIn = new Value[] {// new LiteralImpl("") // }; doAddTermsTest(valuesIn, false/* toldBNodes */); } public void test_add_various_toldBNodes() { // The values that we will be testing with. final Value[] valuesIn = new Value[] {// new LiteralImpl("abc"), // RDF.TYPE,// RDF.PROPERTY,// new LiteralImpl("test"),// new LiteralImpl("test", "en"),// new LiteralImpl("10", new URIImpl("http://www.w3.org/2001/XMLSchema#int")), new LiteralImpl("12", new URIImpl("http://www.w3.org/2001/XMLSchema#float")), new LiteralImpl("12.", new URIImpl("http://www.w3.org/2001/XMLSchema#float")), new LiteralImpl("12.0", new URIImpl("http://www.w3.org/2001/XMLSchema#float")), new LiteralImpl("12.00", new URIImpl("http://www.w3.org/2001/XMLSchema#float")), new BNodeImpl("a"),// new BNodeImpl("12"),// }; doAddTermsTest(valuesIn, true/* toldBNodes */); } /** * Note: Blank nodes are NOT included in this test since the test helper is * not smart enough to verify the blank nodes will not be unified when using * standard bnode semantics. However, {@link TestBlobsIndex} does verify * both standard and told bnode semantics. */ public void test_add_various_standardBNodes() { /* The values that we will be testing with. */ final Value[] valuesIn = new Value[] {// new LiteralImpl("abc"), // RDF.TYPE,// RDF.PROPERTY,// new LiteralImpl("test"),// new LiteralImpl("test", "en"),// new LiteralImpl("10", new URIImpl("http://www.w3.org/2001/XMLSchema#int")), new LiteralImpl("12", new URIImpl("http://www.w3.org/2001/XMLSchema#float")), new LiteralImpl("12.", new URIImpl("http://www.w3.org/2001/XMLSchema#float")), new LiteralImpl("12.0", new URIImpl("http://www.w3.org/2001/XMLSchema#float")), new LiteralImpl("12.00", new URIImpl("http://www.w3.org/2001/XMLSchema#float")), // new BNodeImpl("a"),// // new BNodeImpl("12"),// }; doAddTermsTest(valuesIn, false/* toldBNodes */); } private void doAddTermsTest(final Value[] valuesIn, final boolean toldBNodes) { for(int i=0; i<valuesIn.length; i++) { final Value v = valuesIn[i]; if(v == null) fail("Not expecting null inputs."); if(v instanceof BigdataValue) fail("Not expecting BigdataValue inputs."); } final BlobsIndexHelper h = new BlobsIndexHelper(); final BigdataValueFactory vf = BigdataValueFactoryImpl .getInstance(getName()); final IRawStore store = new SimpleMemoryRawStore(); try { final BTree ndx = TestBlobsIndex.createTermsIndex(store, getName()); /* * Point test the TERMS index for each Value. It should not be * found. */ { for (int i = 0; i < valuesIn.length; i++) { final IV iv = getTermIV(valuesIn[i], h, vf, ndx); assertNull(iv); } } /* * Batch test the TERMS index for each value. It should not be * found. */ { /* * Convert to BigdataValues so IVs will be assigned as a * side-effect by the TermsWriteTask. */ final BigdataValue[] values = new BigdataValue[valuesIn.length]; for (int i = 0; i < valuesIn.length; i++) { values[i] = vf.asValue(valuesIn[i]); } /* * Invoke the task in a read-only mode to unify with the * existing entries in the TERMS index. */ final WriteTaskStats stats = addValues(vf, ndx, true/* readOnly */, toldBNodes, values); for (int i = 0; i < valuesIn.length; i++) { final BigdataValue value = values[i]; final IV iv = value.getIV(); if (iv != null) fail("Not expecting IV for " + value); } } // Write the Value on the TERMS index, noting the assigned IVs. final IV[] expectedIVs = new IV[valuesIn.length]; { /* * Convert to BigdataValues so IVs will be assigned as a * side-effect by the TermsWriteTask. */ final BigdataValue[] values = new BigdataValue[valuesIn.length]; for (int i = 0; i < valuesIn.length; i++) { values[i] = vf.asValue(valuesIn[i]); } /* * Write on the TERMS index, unifying with the existing values * in the index and assigning IVs to new values. */ final WriteTaskStats stats = addValues(vf, ndx, false/* readOnly */, toldBNodes, values); for (int i = 0; i < valuesIn.length; i++) { final BigdataValue value = values[i]; final IV iv = value.getIV(); assertNotNull(iv); if (iv.isNullIV()) fail("Not expecting NullIV for " + value); expectedIVs[i] = iv; } } /* * Batch test the TERMS index for each value. It should now be * found. */ { /* * Convert to BigdataValues so IVs will be assigned as a * side-effect by the TermsWriteTask. */ final BigdataValue[] values = new BigdataValue[valuesIn.length]; for (int i = 0; i < valuesIn.length; i++) { values[i] = vf.asValue(valuesIn[i]); } /* * Invoke the task in a read-only mode to unify with the * existing entries in the TERMS index. */ final WriteTaskStats stats = addValues(vf, ndx, true/* readOnly */, toldBNodes, values); for (int i = 0; i < valuesIn.length; i++) { final BigdataValue value = values[i]; final IV expectedIV = expectedIVs[i]; final IV actualIV = value.getIV(); if (!expectedIV.equals(actualIV)) fail("Value=" + value + ": expected=" + expectedIV + ", but actual=" + actualIV); } } /* * Point test the TERMS index for each Value. It should now be * found. */ { for (int i = 0; i < valuesIn.length; i++) { final Value value = valuesIn[i]; final IV expectedIV = expectedIVs[i]; final IV actualIV = getTermIV(valuesIn[i], h, vf, ndx); if (!expectedIV.equals(actualIV)) fail("Value=" + value + ": expected=" + expectedIV + ", but actual=" + actualIV); } } } finally { store.destroy(); } } /** * Test helper similar to {@link LexiconRelation#getIV(Value)} (point * lookup). * * @param value * @param h * @param vf * @param ndx * @return */ private IV getTermIV(final Value value, final BlobsIndexHelper h, final BigdataValueFactory vf, final IIndex ndx) { final IKeyBuilder keyBuilder = h.newKeyBuilder(); final BigdataValue asValue = vf.asValue(value); final byte[] baseKey = h.makePrefixKey(keyBuilder.reset(), asValue); final byte[] val = vf.getValueSerializer().serialize(asValue); final int counter = h.resolveOrAddValue(ndx, true/* readOnly */, keyBuilder, baseKey, val, null/* tmp */, null/* bucketSize */); if (counter == BlobsIndexHelper.NOT_FOUND) { // Not found. return null; } // final TermId<?> iv = (TermId<?>) IVUtility.decode(key); final BlobIV<?> iv = new BlobIV<BigdataValue>(VTE.valueOf(asValue), asValue.hashCode(), (short) counter); return iv; } /** * Thin wrapper for the {@link BlobsWriteTask} as invoked by the * {@link LexiconRelation}. This can be used to unify the {@link IV}s for * the caller's {@link BigdataValue} with those in the TERMS index and * (optionally) to assign new {@link IV}s (when read-only is * <code>false</code>). * * @param vf * @param ndx * @param readOnly * @param toldBNodes * @param values * @return */ private WriteTaskStats addValues(final BigdataValueFactory vf, final IIndex ndx, final boolean readOnly, final boolean toldBNodes, final BigdataValue[] values) { final WriteTaskStats stats = new WriteTaskStats(); final BlobsWriteTask task = new BlobsWriteTask(ndx, vf, readOnly, toldBNodes, values.length, values, stats); try { task.call(); } catch (Exception e) { throw new RuntimeException(e); } if(log.isInfoEnabled()) log.info(stats); return stats; } }