// $Id: QueueTest.java,v 1.23 2006/09/14 13:24:33 belaban Exp $
package org.jgroups.tests;
import junit.framework.TestCase;
import org.jgroups.TimeoutException;
import org.jgroups.util.Queue;
import org.jgroups.util.QueueClosedException;
import org.jgroups.util.Util;
import java.util.LinkedList;
import java.util.ArrayList;
public class QueueTest extends TestCase {
private Queue queue=null;
public QueueTest(String Name_) {
super(Name_);
}
public void setUp() throws Exception {
super.setUp();
queue=new Queue();
}
public void tearDown() throws Exception {
super.tearDown();
if(queue != null) {
queue.reset();
}
}
public void testQueue() {
try {
queue.add("Q1");
queue.add("Q2");
queue.add("Q3");
assertEquals("Q1", queue.peek());
assertEquals("Q1", queue.remove());
assertEquals("Q2", queue.peek());
assertEquals("Q2", queue.remove());
queue.addAtHead("Q4");
queue.add("Q5");
assertEquals("Q4", queue.peek());
assertEquals("Q4", queue.remove());
queue.close(true);
try {
queue.add("Q6");
fail("should not get here");
}
catch(org.jgroups.util.QueueClosedException qc) {
assertTrue(true);
}
int size=queue.size();
queue.removeElement("Q5");
assertEquals((size - 1), queue.size());
assertEquals("Q3", queue.peek());
assertEquals("Q3", queue.remove());
assertTrue(queue.closed());
System.out.println("Everything is ok");
}
catch(Exception x) {
System.out.println(x);
fail();
}
}
public void testCloseWithoutFlush() {
queue.close(false);
try {
queue.remove();
fail("we should have gotten a QueueClosedException trying to remove an element from a closed queue");
}
catch(QueueClosedException e) {
assertTrue("queue is closed, this is okay", queue.closed());
}
}
public void testCloseWithFlush() {
queue.close(true);
try {
queue.remove();
fail("we should have gotten a QueueClosedException trying to remove an element from a closed queue");
}
catch(QueueClosedException e) {
assertTrue("queue is closed, this is okay", queue.closed());
}
}
public void testCloseWithFlush2() throws QueueClosedException {
queue.add(new Integer(1));
queue.add(new Integer(2));
queue.add(new Integer(3));
queue.close(true);
try {
for(int i=1; i <= 3; i++) {
Object obj=queue.remove();
assertNotNull(obj);
assertEquals(obj, new Integer(i));
}
queue.remove();
fail("we should have gotten a QueueClosedException trying to remove an element from a closed queue");
}
catch(QueueClosedException e) {
assertTrue("queue is closed, this is okay", queue.closed());
}
}
public void testValues() throws QueueClosedException {
queue.add(new Integer(1));
queue.add(new Integer(3));
queue.add(new Integer(99));
queue.add(new Integer(8));
System.out.println("queue: " + Util.dumpQueue(queue));
int size=queue.size();
assertEquals(4, size);
LinkedList values=queue.values();
assertEquals(size, values.size());
}
public void testLargeInsertion() {
String element="MyElement";
long start, stop;
try {
System.out.println("Inserting 100000 elements");
start=System.currentTimeMillis();
for(int i=0; i < 100000; i++)
queue.add(element);
stop=System.currentTimeMillis();
System.out.println("Took " + (stop - start) + " msecs");
System.out.println("Removing 100000 elements");
start=System.currentTimeMillis();
while(queue.size() > 0)
queue.remove();
stop=System.currentTimeMillis();
System.out.println("Took " + (stop - start) + " msecs");
}
catch(Exception ex) {
System.err.println(ex);
fail();
}
}
public void testEmptyQueue() {
assertNull(queue.getFirst());
assertNull(queue.getLast());
assertEquals(queue.getFirst(), queue.getLast()); // both are null; they're equal
}
public void testAddAll() throws QueueClosedException {
ArrayList l=new ArrayList();
l.add("one");
l.add("two");
l.add("three");
queue.addAll(l);
System.out.println("queue is " + queue);
assertEquals(3, queue.size());
assertEquals("one", queue.remove());
assertEquals(2, queue.size());
assertEquals("two", queue.remove());
assertEquals(1, queue.size());
assertEquals("three", queue.remove());
assertEquals(0, queue.size());
}
public void testInsertionAndRemoval() throws Exception {
String s1="Q1", s2="Q2";
queue.add(s1);
assertTrue(queue.getFirst() != null);
assertTrue(queue.getLast() != null);
assertEquals(queue.getFirst(), queue.getLast());
queue.add(s2);
assertTrue(queue.getFirst() != queue.getLast());
Object o1=queue.peek();
Object o2=queue.getFirst();
System.out.println("o1=" + o1 + ", o2=" + o2 + ", o1.equals(o2)=" + o1.equals(o2));
assertEquals(queue.peek(), queue.getFirst());
queue.remove();
assertEquals(1, queue.size());
assertEquals(queue.getFirst(), queue.getLast());
queue.remove();
assertEquals(0, queue.size());
assertTrue(queue.getFirst() == null);
assertTrue(queue.getLast() == null);
}
public void testWaitUntilClosed() {
queue.close(true);
queue.waitUntilClosed(0);
assertEquals(0, queue.size());
}
public void testWaitUntilClosed2() {
queue.close(true);
try {
queue.peek();
fail("peek() should throw a QueueClosedException");
}
catch(QueueClosedException e) {
assertTrue(e != null);
}
assertEquals(0, queue.size());
}
public void testWaitUntilClosed3() throws QueueClosedException {
queue.add("one");
queue.close(true);
Object obj=queue.peek();
assertEquals("one", obj);
assertEquals(1, queue.size());
queue.remove();
try {
queue.peek();
fail("peek() should throw a QueueClosedException");
}
catch(QueueClosedException e) {
assertTrue(e != null);
}
assertEquals(0, queue.size());
}
public void testWaitUntilClosed4() throws QueueClosedException {
for(int i=0; i < 10; i++)
queue.add(new Integer(i));
new Thread() {
public void run() {
while(!queue.closed()) {
try {
System.out.println("-- removed " + queue.remove());
Util.sleep(200);
}
catch(QueueClosedException e) {
break;
}
}
}
}.start();
queue.close(true);
queue.waitUntilClosed(0);
assertEquals(0, queue.size());
}
public void testWaitUntilClosed5() throws QueueClosedException {
for(int i=0; i < 10; i++)
queue.add(new Integer(i));
new Thread() {
public void run() {
while(!queue.closed()) {
try {
System.out.println("-- removed " + queue.remove());
Util.sleep(200);
}
catch(QueueClosedException e) {
System.out.println("-- queue is closed, cannot remove element");
break;
}
}
}
}.start();
Util.sleep(600);
queue.close(false);
queue.waitUntilClosed(0);
assertTrue(queue.size() > 0);
}
public void testRemoveElementNoElement() {
String s1="Q1";
try {
queue.removeElement(s1);
assertFalse(queue.closed());
assertEquals(0, queue.size());
}
catch(QueueClosedException ex) {
fail(ex.toString());
}
}
public void testRemoveElementOneElement() {
String s1="Q1";
try {
queue.add(s1);
queue.removeElement(s1);
assertEquals(0, queue.size());
assertTrue(queue.getFirst() == null);
assertTrue(queue.getLast() == null);
}
catch(QueueClosedException ex) {
fail(ex.toString());
}
}
public void testRemoveElementTwoElementsFirstFound() {
String s1="Q1", s2="Q2";
try {
queue.add(s1);
queue.add(s2);
queue.removeElement(s1);
assertEquals(1, queue.size());
assertEquals(queue.getFirst(), s2);
assertEquals(queue.getLast(), s2);
assertEquals(queue.getFirst(), queue.getLast());
}
catch(QueueClosedException ex) {
fail(ex.toString());
}
}
public void testRemoveElementTwoElementsSecondFound() {
String s1="Q1", s2="Q2";
try {
queue.add(s1);
queue.add(s2);
queue.removeElement(s2);
assertEquals(1, queue.size());
assertEquals(queue.getFirst(), s1);
assertEquals(queue.getLast(), s1);
assertEquals(queue.getFirst(), queue.getLast());
}
catch(QueueClosedException ex) {
fail(ex.toString());
}
}
public void testRemoveElementThreeElementsFirstFound() {
String s1="Q1", s2="Q2", s3="Q3";
try {
queue.add(s1);
queue.add(s2);
queue.add(s3);
queue.removeElement(s1);
assertEquals(2, queue.size());
assertEquals(queue.getFirst(), s2);
assertEquals(queue.getLast(), s3);
}
catch(QueueClosedException ex) {
fail(ex.toString());
}
}
public void testRemoveElementThreeElementsSecondFound() {
String s1="Q1", s2="Q2", s3="Q3";
try {
queue.add(s1);
queue.add(s2);
queue.add(s3);
queue.removeElement(s2);
assertEquals(2, queue.size());
assertEquals(queue.getFirst(), s1);
assertEquals(queue.getLast(), s3);
}
catch(QueueClosedException ex) {
fail(ex.toString());
}
}
public void testRemoveElementThreeElementsThirdFound() {
String s1="Q1", s2="Q2", s3="Q3";
try {
queue.add(s1);
queue.add(s2);
queue.add(s3);
queue.removeElement(s3);
assertEquals(2, queue.size());
assertEquals(queue.getFirst(), s1);
assertEquals(queue.getLast(), s2);
}
catch(QueueClosedException ex) {
fail(ex.toString());
}
}
public void testRemoveAndClose() {
try {
new Thread() {
public void run() {
Util.sleep(1000);
queue.close(true); // close gracefully
}
}.start();
queue.remove();
fail("we should not be able to remove an object from a closed queue");
}
catch(QueueClosedException ex) {
assertTrue(ex instanceof QueueClosedException); // of course, stupid comparison...
}
}
public void testRemoveAndCloseWithTimeout() throws TimeoutException {
try {
new Thread() {
public void run() {
Util.sleep(1000);
queue.close(true); // close gracefully
}
}.start();
queue.remove(5000);
fail("we should not be able to remove an object from a closed queue");
}
catch(QueueClosedException ex) {
assertTrue(ex instanceof QueueClosedException); // of course, stupid comparison...
}
catch(TimeoutException timeout) {
fail("we should not get a TimeoutException, but a QueueClosedException here");
}
}
public void testInterruptAndRemove() throws QueueClosedException {
Thread.currentThread().interrupt();
Object el=null;
try {
el=queue.remove(2000);
fail("we should not get here");
}
catch(TimeoutException e) {
assertNull(el);
}
}
public void testRemoveAndInterrupt() {
Thread closer=new Thread() {
public void run() {
Util.sleep(1000);
System.out.println("-- closing queue");
queue.close(false);
}
};
closer.start();
System.out.println("-- removing element");
try {
queue.remove();
fail("we should not get here, as the queue is closed");
}
catch(QueueClosedException e) {
System.out.println("-- received queue closed exception - as expected");
}
}
public void testClear() throws QueueClosedException {
queue.add("one");
queue.add("two");
assertEquals(2, queue.size());
queue.close(true);
assertEquals(2, queue.size());
queue.clear();
assertEquals(0, queue.size());
queue=new Queue();
queue.add("one");
queue.add("two");
queue.clear();
assertEquals(0, queue.size());
queue.add("one");
queue.add("two");
assertEquals(2, queue.size());
queue.clear();
assertEquals(0, queue.size());
}
// public void testWaitUntilEmpty() {
// try {
// queue.add("one");
// queue.add("two");
// queue.add("three");
//
// new Thread() {
// public void run() {
// try {
// sleep(1000);
// queue.remove();
// queue.remove();
// queue.remove();
// }
// catch(Exception e) {
// }
// }
// }.start();
//
// queue.waitUntilEmpty(0);
// assertEquals(queue.size(), 0);
// }
// catch(Exception e) {
// e.printStackTrace();
// fail(e.toString());
// }
// }
//
// public void testWaitUntilEmpty2() {
// try {
// queue.add("one");
// queue.add("two");
// queue.add("three");
//
// new Thread() {
// public void run() {
// try {
// sleep(1000);
// queue.remove();
// queue.remove();
// }
// catch(Exception e) {
// }
// }
// }.start();
//
// queue.waitUntilEmpty(3000);
// fail("shouldn't get here; we should have caught a TimeoutException");
// }
// catch(TimeoutException timeout) {
// assertTrue(true);
// }
// catch(Exception e) {
// e.printStackTrace();
// fail(e.toString());
// }
// }
//
//
// public void testWaitUntilQueueClosed() {
// try {
// queue.add("one");
// queue.add("two");
// queue.add("three");
//
// new Thread() {
// public void run() {
// try {
// sleep(1000);
// queue.close(false);
// }
// catch(Exception e) {
// }
// }
// }.start();
//
// queue.waitUntilEmpty(0);
// fail("shouldn't get here; we should have caught a QueueClosedException");
// }
// catch(TimeoutException timeout) {
// fail("we should not have gottem here");
// }
// catch(QueueClosedException ex2) {
// assertTrue(true);
// }
// catch(Exception e) {
// e.printStackTrace();
// fail();
// }
// }
/** Multiple threads call remove(), one threads then adds an element. Only 1 thread should actually terminate
* (the one that has the element) */
public void testBarrier() {
RemoveOneItem[] removers=new RemoveOneItem[10];
int num_dead=0;
for(int i=0; i < removers.length; i++) {
removers[i]=new RemoveOneItem(i);
removers[i].start();
}
Util.sleep(1000);
System.out.println("-- adding element 99");
try {
queue.add(new Long(99));
}
catch(Exception ex) {
System.err.println(ex);
}
Util.sleep(5000);
System.out.println("-- adding element 100");
try {
queue.add(new Long(100));
}
catch(Exception ex) {
System.err.println(ex);
}
Util.sleep(1000);
for(int i=0; i < removers.length; i++) {
System.out.println("remover #" + i + " is " + (removers[i].isAlive() ? "alive" : "terminated"));
if(!removers[i].isAlive()) {
num_dead++;
}
}
assertEquals(2, num_dead);
}
/** Multiple threads call remove(), one threads then adds an element. Only 1 thread should actually terminate
* (the one that has the element) */
public void testBarrierWithTimeOut()
{
RemoveOneItemWithTimeout[] removers = new RemoveOneItemWithTimeout[10];
int num_dead = 0;
for (int i = 0; i < removers.length; i++)
{
removers[i] = new RemoveOneItemWithTimeout(i, 1000);
removers[i].start();
}
Util.sleep(5000);
System.out.println("-- adding element 99");
try
{
queue.add(new Long(99));
}
catch (Exception ex)
{
System.err.println(ex);
}
Util.sleep(5000);
System.out.println("-- adding element 100");
try
{
queue.add(new Long(100));
}
catch (Exception ex)
{
System.err.println(ex);
}
Util.sleep(1000);
for (int i = 0; i < removers.length; i++)
{
System.out.println("remover #" + i + " is " + (removers[i].isAlive() ? "alive" : "terminated"));
if (!removers[i].isAlive())
{
num_dead++;
}
}
assertEquals(2, num_dead);
queue.close(false); // will cause all threads still blocking on peek() to return
Util.sleep(2000);
num_dead = 0;
for (int i = 0; i < removers.length; i++)
{
System.out.println("remover #" + i + " is " + (removers[i].isAlive() ? "alive" : "terminated"));
if (!removers[i].isAlive())
{
num_dead++;
}
}
assertEquals(10, num_dead);
}
/** Multiple threads add one element, one thread read them all.
* (the one that has the element) */
public void testMultipleWriterOneReader()
{
AddOneItem[] adders = new AddOneItem[10];
int num_dead = 0;
int num_items = 0;
int items = 1000;
for (int i = 0; i < adders.length; i++)
{
adders[i] = new AddOneItem(i, items);
adders[i].start();
}
while (num_items < (adders.length*items))
{
try
{
queue.remove();
num_items++;
}
catch (Exception ex)
{
System.err.println(ex);
}
}
Util.sleep(1000);
for (int i = 0; i < adders.length; i++)
{
System.out.println("adder #" + i + " is " + (adders[i].isAlive() ? "alive" : "terminated"));
if (!adders[i].isAlive())
{
num_dead++;
}
}
assertEquals(10, num_dead);
queue.close(false); // will cause all threads still blocking on peek() to return
}
/**
* Times how long it takes to add and remove 1000000 elements concurrently (1 reader, 1 writer)
*/
public void testConcurrentAddRemove() {
final long NUM=1000000;
long num_received=0;
Object ret;
long start, stop;
start=System.currentTimeMillis();
new Thread() {
public void run() {
for(int i=0; i < NUM; i++) {
try {
queue.add(new Object());
}
catch(QueueClosedException e) {
}
}
}
}.start();
while(num_received < NUM) {
try {
ret=queue.remove();
if(ret != null)
num_received++;
}
catch(QueueClosedException e) {
e.printStackTrace();
fail();
}
}
assertEquals(NUM, num_received);
stop=System.currentTimeMillis();
System.out.println("time to add/remove " + NUM + " elements: " + (stop-start));
}
/** Has multiple threads add(), remove() and peek() elements to/from the queue */
public void testConcurrentAccess() {
final int NUM_THREADS=10;
final int INTERVAL=20000;
Writer[] writers=new Writer[NUM_THREADS];
Reader[] readers=new Reader[NUM_THREADS];
int[] writes=new int[NUM_THREADS];
int[] reads=new int[NUM_THREADS];
long total_reads=0, total_writes=0;
for(int i=0; i < writers.length; i++) {
readers[i]=new Reader(i, reads);
readers[i].start();
writers[i]=new Writer(i, writes);
writers[i].start();
}
Util.sleep(INTERVAL);
System.out.println("current queue size=" + queue.size());
for(int i=0; i < writers.length; i++) {
writers[i].stopThread();
}
for(int i=0; i < readers.length; i++) {
readers[i].stopThread();
}
queue.close(false); // will cause all threads still blocking on peek() to return
System.out.println("current queue size=" + queue.size());
for(int i=0; i < writers.length; i++) {
try {
writers[i].join(300);
readers[i].join(300);
}
catch(Exception ex) {
System.err.println(ex);
}
}
for(int i=0; i < writes.length; i++) {
System.out.println("Thread #" + i + ": " + writes[i] + " writes, " + reads[i] + " reads");
total_writes+=writes[i];
total_reads+=reads[i];
}
System.out.println("total writes=" + total_writes + ", total_reads=" + total_reads +
", diff=" + Math.abs(total_writes - total_reads));
}
class AddOneItem extends Thread
{
Long retval = null;
int rank = 0;
int iteration = 0;
AddOneItem(int rank, int iteration)
{
super("AddOneItem thread #" + rank);
this.rank = rank;
this.iteration = iteration;
setDaemon(true);
}
public void run()
{
try
{
for (int i = 0; i < iteration; i++)
{
queue.add(new Long(rank));
// Util.sleepRandom(1);
// System.out.println("Thread #" + rank + " added element (" + rank + ")");
}
}
catch (QueueClosedException closed)
{
System.err.println("Thread #" + rank + ": queue was closed");
}
}
}
class RemoveOneItem extends Thread {
Long retval=null;
int rank=0;
RemoveOneItem(int rank) {
super("RemoveOneItem thread #" + rank);
this.rank=rank;
setDaemon(true);
}
public void run() {
try {
retval=(Long)queue.remove();
// System.out.println("Thread #" + rank + " removed element (" + retval + ")");
}
catch(QueueClosedException closed) {
System.err.println("Thread #" + rank + ": queue was closed");
}
}
Long getRetval() {
return retval;
}
}
class RemoveOneItemWithTimeout extends Thread
{
Long retval = null;
int rank = 0;
long timeout = 0;
RemoveOneItemWithTimeout(int rank, long timeout)
{
super("RemoveOneItem thread #" + rank);
this.rank = rank;
this.timeout=timeout;
setDaemon(true);
}
public void run()
{
boolean finished = false;
while (!finished)
{
try
{
retval = (Long) queue.remove(timeout);
// System.out.println("Thread #" + rank + " removed element (" + retval + ")");
finished = true;
}
catch (QueueClosedException closed)
{
System.err.println("Thread #" + rank + ": queue was closed");
finished = true;
}
catch (TimeoutException e)
{
}
}
}
Long getRetval()
{
return retval;
}
}
class Writer extends Thread {
int rank=0;
int num_writes=0;
boolean running=true;
int[] writes=null;
Writer(int i, int[] writes) {
super("WriterThread");
rank=i;
this.writes=writes;
setDaemon(true);
}
public void run() {
while(running) {
try {
queue.add(new Long(System.currentTimeMillis()));
num_writes++;
}
catch(QueueClosedException closed) {
running=false;
}
catch(Throwable t) {
System.err.println("QueueTest.Writer.run(): exception=" + t);
}
}
writes[rank]=num_writes;
}
void stopThread() {
running=false;
}
}
class Reader extends Thread {
int rank;
int num_reads=0;
int[] reads=null;
boolean running=true;
Reader(int i, int[] reads) {
super("ReaderThread");
rank=i;
this.reads=reads;
setDaemon(true);
}
public void run() {
Long el;
while(running) {
try {
el=(Long)queue.remove();
if(el == null) { // @remove
System.out.println("QueueTest.Reader.run(): peek() returned null element. " +
"queue.size()=" + queue.size() + ", queue.closed()=" + queue.closed());
}
assertNotNull(el);
num_reads++;
}
catch(QueueClosedException closed) {
running=false;
}
catch(Throwable t) {
System.err.println("QueueTest.Reader.run(): exception=" + t);
}
}
reads[rank]=num_reads;
}
void stopThread() {
running=false;
}
}
public static void main(String[] args) {
String[] testCaseName={QueueTest.class.getName()};
junit.textui.TestRunner.main(testCaseName);
}
}