/*
* 2012-3 Red Hat Inc. and/or its affiliates and other contributors.
*
* 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.
*/
package org.overlord.rtgov.active.collection;
import static org.junit.Assert.*;
import org.junit.Test;
import org.overlord.rtgov.active.collection.ActiveChangeListener;
import org.overlord.rtgov.active.collection.ActiveList;
import org.overlord.rtgov.active.collection.QuerySpec;
import org.overlord.rtgov.active.collection.QuerySpec.Style;
import org.overlord.rtgov.active.collection.QuerySpec.Truncate;
import org.overlord.rtgov.active.collection.predicate.MVEL;
import org.overlord.rtgov.active.collection.predicate.Predicate;
public class ActiveListTest {
private static final String TEST_ACTIVE_COLLECTION = "TestActiveCollection";
private static final String TEST_DERIVED_ACTIVE_COLLECTION = "TestDerivedActiveCollection";
@Test
public void testInsertFirstObject() {
ActiveList list=new ActiveList(TEST_ACTIVE_COLLECTION);
TestActiveChangeListener l=new TestActiveChangeListener();
list.addActiveChangeListener(l);
list.doInsert(null, new TestObject(1));
java.util.Iterator<Object> iter=list.iterator();
if (!iter.hasNext()) {
fail("Should be item in iterator");
}
TestObject obj=(TestObject)iter.next();
if (iter.hasNext()) {
fail("Should NOT be item in iterator");
}
if (obj.getNumber() != 1) {
fail("Incorrect test object");
}
if (l._insertedKey.size() != 1) {
fail("Should be 1 inserted key: "+l._insertedKey.size());
}
if (l._insertedKey.get(0) != null) {
fail("Key should be null (i.e. inserted end of list): "+l._insertedKey.get(0));
}
if (l._insertedValue.size() != 1) {
fail("Should be 1 inserted value: "+l._insertedValue.size());
}
if (((TestObject)l._insertedValue.get(0)).getNumber() != 1) {
fail("Value should be test object 1: "+l._insertedValue.get(0));
}
}
@Test
public void testInsertObjectBetweenOthers() {
ActiveList list=new ActiveList(TEST_ACTIVE_COLLECTION);
TestActiveChangeListener l=new TestActiveChangeListener();
list.addActiveChangeListener(l);
list.doInsert(null, new TestObject(1));
list.doInsert(null, new TestObject(2));
list.doInsert(1, new TestObject(3));
if (list.getSize() != 3) {
fail("Should be 3 objects: "+list.getSize());
}
java.util.Iterator<Object> iter=list.iterator();
TestObject obj1=(TestObject)iter.next();
TestObject obj2=(TestObject)iter.next();
TestObject obj3=(TestObject)iter.next();
if (obj1.getNumber() != 1) {
fail("Obj1 is not correct");
}
if (obj2.getNumber() != 3) {
fail("Obj2 is not correct");
}
if (obj3.getNumber() != 2) {
fail("Obj3 is not correct");
}
if (l._insertedKey.size() != 3) {
fail("Should be 3 inserted keys: "+l._insertedKey.size());
}
if (l._insertedKey.get(0) != null) {
fail("Key0 should be null (i.e. inserted end of list): "+l._insertedKey.get(0));
}
if (l._insertedKey.get(1) != null) {
fail("Key1 should be null (i.e. inserted end of list): "+l._insertedKey.get(1));
}
if (!l._insertedKey.get(2).equals(1)) {
fail("Key2 should be index 1: "+l._insertedKey.get(2));
}
if (l._insertedValue.size() != 3) {
fail("Should be 3 inserted value: "+l._insertedValue.size());
}
if (((TestObject)l._insertedValue.get(0)).getNumber() != 1) {
fail("Value1 should be test object 1: "+l._insertedValue.get(0));
}
if (((TestObject)l._insertedValue.get(1)).getNumber() != 2) {
fail("Value2 should be test object 2: "+l._insertedValue.get(1));
}
if (((TestObject)l._insertedValue.get(2)).getNumber() != 3) {
fail("Value3 should be test object 3: "+l._insertedValue.get(2));
}
}
@Test
public void testCopyOnReadFalse() {
ActiveList list=new ActiveList(TEST_ACTIVE_COLLECTION);
list.setCopyOnRead(false);
long startTime=System.currentTimeMillis();
// Create list entries
for (int i=0; i < 1000000; i++) {
list.doInsert(null, new TestObject(i));
}
long writeTime=System.currentTimeMillis()-startTime;
startTime=System.currentTimeMillis();
int num=0;
for (Object obj : list) {
// Do something
num = ((TestObject)obj).getNumber();
}
long readTime=System.currentTimeMillis()-startTime;
System.out.println("==> NO COPY ON READ: "+readTime+"ms - (initial write time: "+writeTime+"ms)");
if (num != 1000000-1) {
fail("Final number value was unexpected");
}
try {
for (Object obj : list) {
TestObject to=(TestObject)obj;
if (to.getNumber() == 50000) {
// Apply a change to see if throws exception
list.doInsert(null, new TestObject(1000000));
}
}
fail("Expecting it to throw concurrent mod exception");
} catch (java.util.ConcurrentModificationException cme) {
// Ignore
}
}
@Test
public void testCopyOnReadTrue() {
ActiveList list=new ActiveList(TEST_ACTIVE_COLLECTION);
list.setCopyOnRead(true);
long startTime=System.currentTimeMillis();
// Create list entries
for (int i=0; i < 1000000; i++) {
list.doInsert(null, new TestObject(i));
}
long writeTime=System.currentTimeMillis()-startTime;
startTime=System.currentTimeMillis();
int num=0;
for (Object obj : list) {
// Do something
num = ((TestObject)obj).getNumber();
}
long readTime=System.currentTimeMillis()-startTime;
System.out.println("==> COPY ON READ: "+readTime+"ms - (initial write time: "+writeTime+"ms)");
if (num != 1000000-1) {
fail("Final number value was unexpected");
}
try {
for (Object obj : list) {
TestObject to=(TestObject)obj;
if (to.getNumber() == 50000) {
// Apply a change to see if throws exception
list.doInsert(null, new TestObject(1000000));
}
}
} catch (java.util.ConcurrentModificationException cme) {
fail("Not expecting it to throw concurrent mod exception");
}
}
@Test
public void testDerivedList() {
ActiveList list=new ActiveList(TEST_ACTIVE_COLLECTION);
list.setCopyOnRead(true);
// Create initial list entries
for (int i=0; i < 10; i++) {
list.doInsert(null, new TestObject(i));
}
Predicate predicate=new Predicate() {
public boolean evaluate(ActiveCollectionContext context, Object item) {
return (((TestObject)item).getNumber() % 2 == 0);
}
};
ActiveList derived=new ActiveList(TEST_DERIVED_ACTIVE_COLLECTION, list, null, predicate, null);
if (derived.getSize() != 5) {
fail("Should be 5 entries in derived: "+derived.getSize());
}
}
@Test
public void testDerivedListWithInsert() {
ActiveList list=new ActiveList(TEST_ACTIVE_COLLECTION);
list.setCopyOnRead(true);
// Create initial list entries
for (int i=0; i < 10; i++) {
list.doInsert(null, new TestObject(i));
}
Predicate predicate=new Predicate() {
public boolean evaluate(ActiveCollectionContext context, Object item) {
return (((TestObject)item).getNumber() % 2 == 0);
}
};
ActiveList derived=new ActiveList(TEST_DERIVED_ACTIVE_COLLECTION, list, null, predicate, null);
TestActiveChangeListener l=new TestActiveChangeListener();
derived.addActiveChangeListener(l);
list.doInsert(null, new TestObject(11));
list.doInsert(null, new TestObject(12));
if (derived.getSize() != 6) {
fail("Derived list should have 6 items: "+derived.getSize());
}
if (l._insertedValue.size() != 1) {
fail("Listener should have 1 value: "+l._insertedValue.size());
}
if (((TestObject)l._insertedValue.get(0)).getNumber() != 12) {
fail("Expecting test object 12: "+l._insertedValue.get(0));
}
}
@Test
public void testCleanupMaxItems() {
ActiveList list=new ActiveList(TEST_ACTIVE_COLLECTION);
TestActiveChangeListener l=new TestActiveChangeListener();
list.addActiveChangeListener(l);
list.setMaxItems(10);
for (int i=0; i < 15; i++) {
list.doInsert(null, new TestObject(i));
}
if (list.getSize() != 15) {
fail("List should have 15 items: "+list.getSize());
}
list.cleanup();
if (list.getSize() != 10) {
fail("List should have 10 items: "+list.getSize());
}
// Check first item is now the TestObject with i=5
TestObject to=(TestObject)list.iterator().next();
if (to.getNumber() != 5) {
fail("First item in list should have number 5");
}
if (l._removedKey.size() != 5) {
fail("Removed key size should be 5: "+l._removedKey.size());
}
}
@Test
public void testInsertionExpirationPerformance() {
//int testSize=10000000; // TODO: causes heap size problems in jenkins - try config changes
int testSize=10000;
// Run first test without expiration
java.util.List<TestObject> sourceList=new java.util.ArrayList<TestObject>();
for (int i=0; i < testSize; i++) {
sourceList.add(new TestObject(i));
}
System.gc();
// Run first test without expiration
ActiveList list1=new ActiveList(TEST_ACTIVE_COLLECTION, testSize);
long startTime1=System.currentTimeMillis();
for (int i=0; i < testSize; i++) {
list1.doInsert(null, sourceList.get(i));
}
long without=(System.currentTimeMillis()-startTime1);
System.gc();
// Run second test with expiration
ActiveList list2=new ActiveList(TEST_ACTIVE_COLLECTION, testSize);
list2.setItemExpiration(1000);
long startTime2=System.currentTimeMillis();
for (int i=0; i < testSize; i++) {
list2.doInsert(null, sourceList.get(i));
}
long with=(System.currentTimeMillis()-startTime2);
double diff=(double)with/(double)without;
System.out.println("INSERT PERTFORMANCE:\r\nWithout expiry = "
+without+"\r\nWith expiry = "+with
+"\r\nDifference factor = "+diff);
// TODO: BAM-23 Add check after optimizing time based insertion
//if (diff > 4.0) {
// fail("Insert performance with expiration set is too slow!");
//}
}
@Test
public void testCleanupItemExpiration() {
ActiveList list=new ActiveList(TEST_ACTIVE_COLLECTION);
TestActiveChangeListener l=new TestActiveChangeListener();
list.addActiveChangeListener(l);
list.setItemExpiration(2000);
for (int i=0; i < 5; i++) {
list.doInsert(null, new TestObject(i));
}
try {
synchronized (this) {
wait(3000);
}
} catch(Exception e) {
fail("Failed to wait");
}
for (int i=0; i < 10; i++) {
list.doInsert(null, new TestObject(5+i));
}
if (list.getSize() != 15) {
fail("List should have 15 items: "+list.getSize());
}
list.cleanup();
if (list.getSize() != 10) {
fail("List should have 10 items: "+list.getSize());
}
if (l._removedKey.size() != 5) {
fail("Removed key size should be 5: "+l._removedKey.size());
}
}
@Test
public void testAllItemsNormal() {
ActiveList list=new ActiveList(TEST_ACTIVE_COLLECTION);
TestActiveChangeListener l=new TestActiveChangeListener();
list.addActiveChangeListener(l);
for (int i=0; i < 15; i++) {
list.doInsert(null, new TestObject(i));
}
if (list.getSize() != 15) {
fail("List should have 15 items: "+list.getSize());
}
QuerySpec qs=new QuerySpec();
qs.setStyle(Style.Normal);
java.util.List<Object> results=list.query(qs);
if (((TestObject)results.get(0)).getNumber() != 0) {
fail("First item should be obj 0: "+((TestObject)results.get(0)).getNumber());
}
}
@Test
public void testAllItemsReversed() {
ActiveList list=new ActiveList(TEST_ACTIVE_COLLECTION);
TestActiveChangeListener l=new TestActiveChangeListener();
list.addActiveChangeListener(l);
for (int i=0; i < 15; i++) {
list.doInsert(null, new TestObject(i));
}
if (list.getSize() != 15) {
fail("List should have 15 items: "+list.getSize());
}
QuerySpec qs=new QuerySpec();
qs.setStyle(Style.Reversed);
java.util.List<Object> results=list.query(qs);
if (((TestObject)results.get(0)).getNumber() != 14) {
fail("First item should be obj 14: "+((TestObject)results.get(0)).getNumber());
}
}
@Test
public void testMaxItemsGreaterThanSize() {
ActiveList list=new ActiveList(TEST_ACTIVE_COLLECTION);
TestActiveChangeListener l=new TestActiveChangeListener();
list.addActiveChangeListener(l);
for (int i=0; i < 15; i++) {
list.doInsert(null, new TestObject(i));
}
if (list.getSize() != 15) {
fail("List should have 15 items: "+list.getSize());
}
QuerySpec qs=new QuerySpec();
qs.setStyle(Style.Normal);
qs.setMaxItems(20);
java.util.List<Object> results=list.query(qs);
if (results.size() != list.getSize()) {
fail("Result size ("+results.size()+
") should be same as list: "+list.getSize());
}
}
@Test
public void testMaxItemsLessSizeTruncateEnd() {
ActiveList list=new ActiveList(TEST_ACTIVE_COLLECTION);
TestActiveChangeListener l=new TestActiveChangeListener();
list.addActiveChangeListener(l);
for (int i=0; i < 15; i++) {
list.doInsert(null, new TestObject(i));
}
if (list.getSize() != 15) {
fail("List should have 15 items: "+list.getSize());
}
QuerySpec qs=new QuerySpec();
qs.setStyle(Style.Normal);
qs.setMaxItems(5);
qs.setTruncate(Truncate.End);
java.util.List<Object> results=list.query(qs);
if (results.size() != qs.getMaxItems()) {
fail("Result size ("+results.size()+
") should be: "+qs.getMaxItems());
}
if (((TestObject)results.get(0)).getNumber() != 0) {
fail("First item should be obj 0: "+((TestObject)results.get(0)).getNumber());
}
}
@Test
public void testMaxItemsLessSizeTruncateStart() {
ActiveList list=new ActiveList(TEST_ACTIVE_COLLECTION);
TestActiveChangeListener l=new TestActiveChangeListener();
list.addActiveChangeListener(l);
for (int i=0; i < 15; i++) {
list.doInsert(null, new TestObject(i));
}
if (list.getSize() != 15) {
fail("List should have 15 items: "+list.getSize());
}
QuerySpec qs=new QuerySpec();
qs.setStyle(Style.Normal);
qs.setMaxItems(5);
qs.setTruncate(Truncate.Start);
java.util.List<Object> results=list.query(qs);
if (results.size() != qs.getMaxItems()) {
fail("Result size ("+results.size()+
") should be: "+qs.getMaxItems());
}
if (((TestObject)results.get(0)).getNumber() != 10) {
fail("First item should be obj 10: "+((TestObject)results.get(0)).getNumber());
}
}
@Test
public void testMaxItemsLessSizeTruncateEndReversed() {
ActiveList list=new ActiveList(TEST_ACTIVE_COLLECTION);
TestActiveChangeListener l=new TestActiveChangeListener();
list.addActiveChangeListener(l);
for (int i=0; i < 15; i++) {
list.doInsert(null, new TestObject(i));
}
if (list.getSize() != 15) {
fail("List should have 15 items: "+list.getSize());
}
QuerySpec qs=new QuerySpec();
qs.setStyle(Style.Reversed);
qs.setMaxItems(5);
qs.setTruncate(Truncate.End);
java.util.List<Object> results=list.query(qs);
if (results.size() != qs.getMaxItems()) {
fail("Result size ("+results.size()+
") should be: "+qs.getMaxItems());
}
if (((TestObject)results.get(0)).getNumber() != 4) {
fail("First item should be obj 4: "+((TestObject)results.get(0)).getNumber());
}
}
@Test
public void testMaxItemsLessSizeTruncateStartReversed() {
ActiveList list=new ActiveList(TEST_ACTIVE_COLLECTION);
TestActiveChangeListener l=new TestActiveChangeListener();
list.addActiveChangeListener(l);
for (int i=0; i < 15; i++) {
list.doInsert(null, new TestObject(i));
}
if (list.getSize() != 15) {
fail("List should have 15 items: "+list.getSize());
}
QuerySpec qs=new QuerySpec();
qs.setStyle(Style.Reversed);
qs.setMaxItems(5);
qs.setTruncate(Truncate.Start);
java.util.List<Object> results=list.query(qs);
if (results.size() != qs.getMaxItems()) {
fail("Result size ("+results.size()+
") should be: "+qs.getMaxItems());
}
if (((TestObject)results.get(0)).getNumber() != 14) {
fail("First item should be obj 14: "+((TestObject)results.get(0)).getNumber());
}
}
@Test
public void testDerivedListInactive() {
ActiveList list=new ActiveList(TEST_ACTIVE_COLLECTION);
list.setCopyOnRead(true);
// Create initial list entries
for (int i=0; i < 10; i++) {
list.doInsert(null, new TestObject(i));
}
MVEL predicate=new MVEL();
predicate.setExpression("number % 2 == 0");
java.util.Map<String,Object> props=new java.util.HashMap<String, Object>();
props.put("active", false);
ActiveList derived=new ActiveList(TEST_DERIVED_ACTIVE_COLLECTION, list, null, predicate, props);
if (derived.getSize() != 5) {
fail("Should be 5 entries in derived: "+derived.getSize());
}
// Change predicate
predicate.setExpression("number < 3");
if (derived.getSize() != 3) {
fail("NOW Should be 3 entries in derived: "+derived.getSize());
}
java.util.Iterator<Object> iter=derived.iterator();
TestObject to1=(TestObject)iter.next();
TestObject to2=(TestObject)iter.next();
TestObject to3=(TestObject)iter.next();
if (to1.getNumber() != 0) {
fail("First is not 0: "+to1.getNumber());
}
if (to2.getNumber() != 1) {
fail("Second is not 1: "+to2.getNumber());
}
if (to3.getNumber() != 2) {
fail("Third is not 2: "+to3.getNumber());
}
}
public static class TestObject {
private int _number=0;
public TestObject(int num) {
_number = num;
}
public int getNumber() {
return (_number);
}
public int hashCode() {
return (_number);
}
public boolean equals(Object obj) {
boolean ret=false;
if (obj instanceof TestObject) {
ret = (_number == ((TestObject)obj).getNumber());
}
return (ret);
}
public String toString() {
return ("TestObject["+_number+"]");
}
}
public static class TestActiveChangeListener implements ActiveChangeListener {
protected java.util.List<Object> _insertedKey=new java.util.ArrayList<Object>();
protected java.util.List<Object> _insertedValue=new java.util.ArrayList<Object>();
protected java.util.List<Object> _upatedKey=new java.util.ArrayList<Object>();
protected java.util.List<Object> _updatedValue=new java.util.ArrayList<Object>();
protected java.util.List<Object> _removedKey=new java.util.ArrayList<Object>();
protected java.util.List<Object> _removedValue=new java.util.ArrayList<Object>();
public void inserted(Object key, Object value) {
_insertedKey.add(key);
_insertedValue.add(value);
}
public void updated(Object key, Object value) {
_upatedKey.add(key);
_updatedValue.add(value);
}
public void removed(Object key, Object value) {
_removedKey.add(key);
_removedValue.add(value);
}
}
}