package com.orientechnologies.orient.core.iterator; import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx; import com.orientechnologies.orient.core.metadata.schema.OClass; import com.orientechnologies.orient.core.metadata.schema.OSchema; import com.orientechnologies.orient.core.metadata.schema.OType; import com.orientechnologies.orient.core.metadata.schema.clusterselection.ODefaultClusterSelectionStrategy; import com.orientechnologies.orient.core.record.impl.ODocument; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import java.util.HashSet; import java.util.Set; /** * @author Artem Loginov */ @Test public class ClassIteratorTest { private static final boolean RECREATE_DATABASE = true; private static ODatabaseDocumentTx db = null; private Set<String> names; @BeforeMethod public void setUp() throws Exception { initializeDatabase(); // Insert some data names = new HashSet<String>(); names.add("Adam"); names.add("Bob"); names.add("Calvin"); names.add("Daniel"); for (String name : names) { createPerson("Person", name); } } @AfterClass public void tearDown() throws Exception { if (!db.isClosed()) db.close(); } @Test public void testIteratorShouldReuseRecordWithoutNPE() { // Use class iterator. // browseClass() returns all documents in RecordID order // (including subclasses, which shouldn't exist for Person) final ORecordIteratorClass<ODocument> personIter = db.browseClass("Person"); // Setting this to true causes the bug. Setting to false it works fine. personIter.setReuseSameRecord(true); int docNum = 0; // Explicit iterator loop. while (personIter.hasNext()) { final ODocument personDoc = personIter.next(); Assert.assertTrue(names.contains(personDoc.field("First"))); Assert.assertTrue(names.remove(personDoc.field("First"))); System.out.printf("Doc %d: %s\n", docNum++, personDoc.toString()); } Assert.assertTrue(names.isEmpty()); } @Test public void testIteratorShouldReuseRecordWithoutNPEUsingForEach() throws Exception { // Use class iterator. // browseClass() returns all documents in RecordID order // (including subclasses, which shouldn't exist for Person) final ORecordIteratorClass<ODocument> personIter = db.browseClass("Person"); // Setting this to true causes the bug. Setting to false it works fine. personIter.setReuseSameRecord(true); // Shorthand iterator loop. int docNum = 0; for (final ODocument personDoc : personIter) { Assert.assertTrue(names.contains(personDoc.field("First"))); Assert.assertTrue(names.remove(personDoc.field("First"))); System.out.printf("Doc %d: %s\n", docNum++, personDoc.toString()); } Assert.assertTrue(names.isEmpty()); } @Test public void testDescendentOrderIteratorWithMultipleClusters() throws Exception { final OClass personClass = db.getMetadata().getSchema().getClass("Person"); // empty old cluster but keep it attached personClass.truncate(); // reload the data in a new 'test' cluster int testClusterId = db.addCluster("test"); personClass.addClusterId(testClusterId); personClass.setClusterSelection(new ODefaultClusterSelectionStrategy()); personClass.setDefaultClusterId(testClusterId); for (String name : names) { createPerson("Person", name); } // Use descending class iterator. final ORecordIteratorClass<ODocument> personIter = new ORecordIteratorClassDescendentOrder<ODocument>(db, db, "Person", true); personIter.setRange(null, null); // open range int docNum = 0; // Explicit iterator loop. while (personIter.hasNext()) { final ODocument personDoc = personIter.next(); Assert.assertTrue(names.contains(personDoc.field("First"))); Assert.assertTrue(names.remove(personDoc.field("First"))); System.out.printf("Doc %d: %s\n", docNum++, personDoc.toString()); } Assert.assertTrue(names.isEmpty()); } @Test public void testMultipleClusters() throws Exception { final OClass personClass = db.getMetadata().getSchema().createClass("PersonMultipleClusters", 4, null); for (String name : names) { createPerson("PersonMultipleClusters", name); } final ORecordIteratorClass<ODocument> personIter = new ORecordIteratorClass<ODocument>(db, db, "PersonMultipleClusters", true); int docNum = 0; while (personIter.hasNext()) { final ODocument personDoc = personIter.next(); Assert.assertTrue(names.contains(personDoc.field("First"))); Assert.assertTrue(names.remove(personDoc.field("First"))); System.out.printf("Doc %d: %s\n", docNum++, personDoc.toString()); } Assert.assertTrue(names.isEmpty()); } private static void initializeDatabase() { db = new ODatabaseDocumentTx("memory:" + ClassIteratorTest.class.getSimpleName()); if (db.exists() && RECREATE_DATABASE) { db.open("admin", "admin"); db.drop(); System.out.println("Dropped database."); } if (!db.exists()) { db.create(); System.out.println("Created database."); final OSchema schema = db.getMetadata().getSchema(); // Create Person class final OClass personClass = schema.createClass("Person"); personClass.createProperty("First", OType.STRING).setMandatory(true).setNotNull(true).setMin("1"); System.out.println("Created schema."); } else { db.open("admin", "admin"); } } private static void createPerson(final String iClassName, final String first) { // Create Person document final ODocument personDoc = db.newInstance(iClassName); personDoc.field("First", first); personDoc.save(); } }