// ========================================================================
// Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.util;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.HashSet;
import java.util.Random;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;
import org.junit.Test;
public class BlockingArrayQueueTest
{
@Test
public void testWrap() throws Exception
{
BlockingArrayQueue<String> queue = new BlockingArrayQueue<String>(3);
assertEquals(0,queue.size());
for (int i=0;i<3;i++)
{
queue.offer("one");
assertEquals(1,queue.size());
queue.offer("two");
assertEquals(2,queue.size());
queue.offer("three");
assertEquals(3,queue.size());
assertEquals("one",queue.get(0));
assertEquals("two",queue.get(1));
assertEquals("three",queue.get(2));
assertEquals("[one, two, three]",queue.toString());
assertEquals("one",queue.poll());
assertEquals(2,queue.size());
assertEquals("two",queue.poll());
assertEquals(1,queue.size());
assertEquals("three",queue.poll());
assertEquals(0,queue.size());
queue.offer("xxx");
assertEquals(1,queue.size());
assertEquals("xxx",queue.poll());
assertEquals(0,queue.size());
}
}
@Test
public void testRemove() throws Exception
{
BlockingArrayQueue<String> queue = new BlockingArrayQueue<String>(3,3);
queue.add("0");
queue.add("x");
for (int i=1;i<100;i++)
{
queue.add(""+i);
queue.add("x");
queue.remove(queue.size()-3);
queue.set(queue.size()-3,queue.get(queue.size()-3)+"!");
}
for (int i=0;i<99;i++)
assertEquals(i+"!",queue.get(i));
}
@Test
public void testGrow() throws Exception
{
BlockingArrayQueue<String> queue = new BlockingArrayQueue<String>(3,2);
assertEquals(3,queue.getCapacity());
queue.add("a");
queue.add("a");
assertEquals(2,queue.size());
assertEquals(3,queue.getCapacity());
queue.add("a");
queue.add("a");
assertEquals(4,queue.size());
assertEquals(5,queue.getCapacity());
int s=5;
int c=5;
queue.add("a");
for (int t=0;t<100;t++)
{
assertEquals(s,queue.size());
assertEquals(c,queue.getCapacity());
for (int i=queue.size();i-->0;)
queue.poll();
assertEquals(0,queue.size());
assertEquals(c,queue.getCapacity());
for (int i=queue.getCapacity();i-->0;)
queue.add("a");
queue.add("a");
assertEquals(s+1,queue.size());
assertEquals(c+2,queue.getCapacity());
queue.poll();
queue.add("a");
queue.add("a");
assertEquals(s+2,queue.size());
assertEquals(c+2,queue.getCapacity());
s+=2;
c+=2;
}
}
@Test
public void testTake() throws Exception
{
final String[] data=new String[4];
final BlockingArrayQueue<String> queue = new BlockingArrayQueue<String>();
Thread thread = new Thread()
{
@Override
public void run()
{
try
{
data[0]=queue.take();
data[1]=queue.take();
Thread.sleep(1000);
data[2]=queue.take();
data[3]=queue.poll(100,TimeUnit.MILLISECONDS);
}
catch(Exception e)
{
assertTrue(false);
e.printStackTrace();
}
}
};
thread.start();
Thread.sleep(1000);
queue.offer("zero");
queue.offer("one");
queue.offer("two");
thread.join();
assertEquals("zero",data[0]);
assertEquals("one",data[1]);
assertEquals("two",data[2]);
assertEquals(null,data[3]);
}
volatile boolean _running;
@Test
public void testConcurrentAccess() throws Exception
{
final int THREADS=50;
final int LOOPS=1000;
final BlockingArrayQueue<Integer> queue = new BlockingArrayQueue<Integer>(1+THREADS*LOOPS);
final ConcurrentLinkedQueue<Integer> produced=new ConcurrentLinkedQueue<Integer>();
final ConcurrentLinkedQueue<Integer> consumed=new ConcurrentLinkedQueue<Integer>();
_running=true;
// start consumers
final CyclicBarrier barrier0 = new CyclicBarrier(THREADS+1);
for (int i=0;i<THREADS;i++)
{
final Integer id = new Integer(i);
new Thread()
{
@Override
public void run()
{
final Random random = new Random();
setPriority(getPriority()-1);
try
{
while(_running)
{
int r=1+random.nextInt(10);
if (r%2==0)
{
Integer msg=queue.poll();
if (msg==null)
{
Thread.sleep(1+random.nextInt(10));
continue;
}
consumed.add(msg);
}
else
{
Integer msg=queue.poll(r,TimeUnit.MILLISECONDS);
if (msg!=null)
consumed.add(msg);
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
try
{
barrier0.await();
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}.start();
}
// start producers
final CyclicBarrier barrier1 = new CyclicBarrier(THREADS+1);
for (int i=0;i<THREADS;i++)
{
final Integer id = new Integer(i);
new Thread()
{
@Override
public void run()
{
final Random random = new Random();
try
{
for (int j=0;j<LOOPS;j++)
{
Integer msg = new Integer(random.nextInt());
produced.add(msg);
if (!queue.offer(msg))
throw new Exception(id+" FULL! "+queue.size());
Thread.sleep(1+random.nextInt(10));
}
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
try
{
barrier1.await();
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}.start();
}
barrier1.await();
int size=queue.size();
int last=size-1;
while (size>0 && size!=last)
{
last=size;
Thread.sleep(500);
size=queue.size();
}
_running=false;
barrier0.await();
HashSet<Integer> prodSet = new HashSet<Integer>(produced);
HashSet<Integer> consSet = new HashSet<Integer>(consumed);
assertEquals(prodSet,consSet);
}
}