diff --git a/orientdb/pom.xml b/orientdb/pom.xml index 0613b0f8838df12088c8fe9fe81aca951dc5b539..3f10a675cb8259f50dfa19834f3e53224b7a5523 100644 --- a/orientdb/pom.xml +++ b/orientdb/pom.xml @@ -47,5 +47,11 @@ LICENSE file. <artifactId>orientdb-core</artifactId> <version>1.7.10</version> </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.12</version> + <scope>test</scope> + </dependency> </dependencies> </project> diff --git a/orientdb/src/test/java/com/yahoo/ycsb/db/OrientDBClientTest.java b/orientdb/src/test/java/com/yahoo/ycsb/db/OrientDBClientTest.java new file mode 100644 index 0000000000000000000000000000000000000000..bd1f3fd73f57c041cad31edd887d0c807cc4b28b --- /dev/null +++ b/orientdb/src/test/java/com/yahoo/ycsb/db/OrientDBClientTest.java @@ -0,0 +1,236 @@ +/** + * Copyright (c) 2015 YCSB contributors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you + * may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. See accompanying + * LICENSE file. + */ + +package com.yahoo.ycsb.db; + +import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx; +import com.orientechnologies.orient.core.dictionary.ODictionary; +import com.orientechnologies.orient.core.record.ORecordInternal; +import com.orientechnologies.orient.core.record.impl.ODocument; +import com.yahoo.ycsb.ByteIterator; +import com.yahoo.ycsb.DBException; +import com.yahoo.ycsb.StringByteIterator; + +import org.junit.*; +import java.util.*; + +import static org.junit.Assert.*; + +/** + * Created by kruthar on 12/29/15. + */ +public class OrientDBClientTest { + // TODO: This must be copied because it is private in OrientDBClient, but this should defer to table property. + private static final String CLASS = "usertable"; + private static final int FIELD_LENGTH = 32; + private static final String FIELD_PREFIX = "FIELD"; + private static final String KEY_PREFIX = "user"; + private static final int NUM_FIELDS = 3; + private static final String TEST_DB_URL = "memory:test"; + + private static ODatabaseDocumentTx orientDBConnection = null; + private static ODictionary<ORecordInternal<?>> orientDBDictionary; + private static OrientDBClient orientDBClient = null; + + @Before + public void setup() throws DBException { + orientDBClient = new OrientDBClient(); + + Properties p = new Properties(); + // TODO: Extract the property names into final variables in OrientDBClient + p.setProperty("orientdb.url", TEST_DB_URL); + + orientDBClient.setProperties(p); + orientDBClient.init(); + orientDBConnection = new ODatabaseDocumentTx(TEST_DB_URL).open("admin","admin"); + orientDBDictionary = orientDBConnection.getMetadata().getIndexManager().getDictionary(); + } + + @After + public void teardown() throws DBException { + if (orientDBConnection != null) { + orientDBConnection.close(); + } + + if (orientDBClient != null) { + orientDBClient.cleanup(); + } + } + + /* + This is a copy of buildDeterministicValue() from core:com.yahoo.ycsb.workloads.CoreWorkload.java. + That method is neither public nor static so we need a copy. + */ + private String buildDeterministicValue(String key, String fieldkey) { + int size = FIELD_LENGTH; + StringBuilder sb = new StringBuilder(size); + sb.append(key); + sb.append(':'); + sb.append(fieldkey); + while (sb.length() < size) { + sb.append(':'); + sb.append(sb.toString().hashCode()); + } + sb.setLength(size); + + return sb.toString(); + } + + /* + Inserts a row of deterministic values for the given insertKey using the orientDBClient. + */ + private Map<String, ByteIterator> insertRow(String insertKey) { + HashMap<String, ByteIterator> insertMap = new HashMap<>(); + for (int i = 0; i < 3; i++) { + insertMap.put(FIELD_PREFIX + i, new StringByteIterator(buildDeterministicValue(insertKey, FIELD_PREFIX + i))); + } + orientDBClient.insert(CLASS, insertKey, insertMap); + + return insertMap; + } + + @Test + public void insertTest() { + String insertKey = "user0"; + Map<String, ByteIterator> insertMap = insertRow(insertKey); + + ODocument result = orientDBDictionary.get(insertKey); + + assertTrue("Assert a row was inserted.", result != null); + + for (int i = 0; i < NUM_FIELDS; i++) { + assertEquals("Assert all inserted columns have correct values.", result.field(FIELD_PREFIX + i), insertMap.get(FIELD_PREFIX + i).toString()); + } + } + + @Test + public void updateTest() { + String preupdateString = "preupdate"; + String user0 = "user0"; + String user1 = "user1"; + String user2 = "user2"; + + // Manually insert three documents + for(String key: Arrays.asList(user0, user1, user2)) { + ODocument doc = new ODocument(CLASS); + for (int i = 0; i < NUM_FIELDS; i++) { + doc.field(FIELD_PREFIX + i, preupdateString); + } + doc.save(); + orientDBDictionary.put(key, doc); + } + + HashMap<String, ByteIterator> updateMap = new HashMap<>(); + for (int i = 0; i < NUM_FIELDS; i++) { + updateMap.put(FIELD_PREFIX + i, new StringByteIterator(buildDeterministicValue(user1, FIELD_PREFIX + i))); + } + + orientDBClient.update(CLASS, user1, updateMap); + + // Ensure that user0 record was not changed + ODocument result = orientDBDictionary.get(user0); + for (int i = 0; i < NUM_FIELDS; i++) { + assertEquals("Assert first row fields contain preupdateString", result.field(FIELD_PREFIX + i), preupdateString); + } + + // Check that all the columns have expected values for user1 record + result = orientDBDictionary.get(user1); + for (int i = 0; i < NUM_FIELDS; i++) { + assertEquals("Assert updated row fields are correct", result.field(FIELD_PREFIX + i), updateMap.get(FIELD_PREFIX + i).toString()); + } + + // Ensure that user2 record was not changed + result = orientDBDictionary.get(user2); + for (int i = 0; i < NUM_FIELDS; i++) { + assertEquals("Assert third row fields contain preupdateString", result.field(FIELD_PREFIX + i), preupdateString); + } + } + + @Test + public void readTest() { + String insertKey = "user0"; + Map<String, ByteIterator> insertMap = insertRow(insertKey); + HashSet<String> readFields = new HashSet<>(); + HashMap<String, ByteIterator> readResultMap = new HashMap<>(); + + // Test reading a single field + readFields.add("FIELD0"); + orientDBClient.read(CLASS, insertKey, readFields, readResultMap); + assertEquals("Assert that result has correct number of fields", readFields.size(), readResultMap.size()); + for (String field: readFields) { + assertEquals("Assert " + field + " was read correctly", insertMap.get(field).toString(), readResultMap.get(field).toString()); + } + + readResultMap = new HashMap<>(); + + // Test reading all fields + readFields.add("FIELD1"); + readFields.add("FIELD2"); + orientDBClient.read(CLASS, insertKey, readFields, readResultMap); + assertEquals("Assert that result has correct number of fields", readFields.size(), readResultMap.size()); + for (String field: readFields) { + assertEquals("Assert " + field + " was read correctly", insertMap.get(field).toString(), readResultMap.get(field).toString()); + } + } + + @Test + public void deleteTest() { + String user0 = "user0"; + String user1 = "user1"; + String user2 = "user2"; + + insertRow(user0); + insertRow(user1); + insertRow(user2); + + orientDBClient.delete(CLASS, user1); + + assertNotNull("Assert user0 still exists", orientDBDictionary.get(user0)); + assertNull("Assert user1 does not exist", orientDBDictionary.get(user1)); + assertNotNull("Assert user2 still exists", orientDBDictionary.get(user2)); + } + + @Test + public void scanTest() { + Map<String, Map<String, ByteIterator>> keyMap = new HashMap<>(); + for (int i = 0; i < 5; i++) { + String insertKey = KEY_PREFIX + i; + keyMap.put(insertKey, insertRow(insertKey)); + } + + Set<String> fieldSet = new HashSet<>(); + fieldSet.add("FIELD0"); + fieldSet.add("FIELD1"); + int startIndex = 1; + int resultRows = 3; + + Vector<HashMap<String, ByteIterator>> resultVector = new Vector<>(); + orientDBClient.scan(CLASS, KEY_PREFIX + startIndex, resultRows, fieldSet, resultVector); + + // Check the resultVector is the correct size + assertEquals("Assert the correct number of results rows were returned", resultRows, resultVector.size()); + // Check each vector row to make sure we have the correct fields + int testIndex = startIndex; + for (HashMap<String, ByteIterator> result: resultVector) { + assertEquals("Assert that this row has the correct number of fields", fieldSet.size(), result.size()); + for (String field: fieldSet) { + assertEquals("Assert this field is correct in this row", keyMap.get(KEY_PREFIX + testIndex).get(field).toString(), result.get(field).toString()); + } + testIndex++; + } + } +}