/*
* Copyright (c) 2015-2016, Christoph Engelbert (aka noctarius) and
* 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.
*/
package com.noctarius.tengi.spi.ringbuffer.impl;
import com.noctarius.tengi.spi.ringbuffer.RingBuffer;
import org.junit.Test;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicReferenceArray;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
public class NonBlockingRingBufferTestCase {
@Test
public void test_write_read_write_read()
throws Exception {
Object value1 = new Object();
Object value2 = new Object();
RingBuffer<Object> ringBuffer = RingBuffer.create(1);
assertTrue(ringBuffer.write(value1));
assertSame(value1, ringBuffer.read());
assertTrue(ringBuffer.write(value2));
assertSame(value2, ringBuffer.read());
}
@Test
public void test_read_empty_ringbuffer()
throws Exception {
RingBuffer<Object> ringBuffer = RingBuffer.create(10);
assertNull(ringBuffer.read());
}
@Test
public void test_write_reader_greater_writer_ringbuffer()
throws Exception {
RingBuffer<Object> ringBuffer = RingBuffer.create(5);
for (int i = 0; i < 4; i++) {
assertTrue(ringBuffer.write(new Object()));
assertNotNull(ringBuffer.read());
}
assertTrue(ringBuffer.write(new Object()));
assertTrue(ringBuffer.write(new Object()));
}
@Test
public void test_write_reader_greater_writer_full_ringbuffer()
throws Exception {
RingBuffer<Object> ringBuffer = RingBuffer.create(5);
for (int i = 0; i < 5; i++) {
assertTrue(ringBuffer.write(new Object()));
}
assertNotNull(ringBuffer.read());
assertTrue(ringBuffer.write(new Object()));
assertFalse(ringBuffer.write(new Object()));
}
@Test
public void test_write_reader_greater_writer_full_cycle_ringbuffer()
throws Exception {
RingBuffer<Object> ringBuffer = RingBuffer.create(4);
for (int i = 0; i < 3; i++) {
assertTrue(ringBuffer.write(new Object()));
assertNotNull(ringBuffer.read());
}
assertTrue(ringBuffer.write(new Object()));
assertTrue(ringBuffer.write(new Object()));
}
@Test
public void test_read_ringbuffer()
throws Exception {
RingBuffer<Object> ringBuffer = RingBuffer.create(10);
Object value = new Object();
ringBuffer.write(value);
assertSame(value, ringBuffer.read());
}
@Test
public void test_read_timeout_ringbuffer()
throws Exception {
RingBuffer<Object> ringBuffer = RingBuffer.create(10);
Object value = new Object();
ringBuffer.write(value);
assertSame(value, ringBuffer.read(1, TimeUnit.NANOSECONDS));
}
@Test
public void test_read_timeout_ringbuffer_become_available()
throws Exception {
RingBuffer<Object> ringBuffer = RingBuffer.create(10);
Semaphore start = new Semaphore(1);
Semaphore end = new Semaphore(1);
start.acquire();
AtomicReference<Object> result = new AtomicReference<>();
new Thread() {
@Override
public void run() {
try {
// Prepare end semaphore
end.acquire();
// Wait to start
start.acquire();
result.set(ringBuffer.read(30, TimeUnit.SECONDS));
} catch (InterruptedException e) {
result.set(e);
} finally {
end.release();
}
}
}.start();
start.release();
Thread.sleep(2000);
Object value = new Object();
ringBuffer.write(value);
end.acquire();
assertSame(value, result.get());
}
@Test
public void test_read_timeout_empty_ringbuffer()
throws Exception {
RingBuffer<Object> ringBuffer = RingBuffer.create(10);
long deadline = System.nanoTime() + TimeUnit.SECONDS.toNanos(1);
assertNull(ringBuffer.read(1, TimeUnit.SECONDS));
assertTrue(System.nanoTime() > deadline);
}
@Test
public void test_write_empty_ringbuffer()
throws Exception {
RingBuffer<Object> ringBuffer = RingBuffer.create(10);
assertTrue(ringBuffer.write(new Object()));
}
@Test
public void test_write_full_ringbuffer()
throws Exception {
RingBuffer<Object> ringBuffer = RingBuffer.create(1);
ringBuffer.write(new Object());
assertFalse(ringBuffer.write(new Object()));
}
@Test
public void test_write_timeout_ringbuffer_become_available()
throws Exception {
RingBuffer<Object> ringBuffer = RingBuffer.create(1);
ringBuffer.write(new Object());
Object value = new Object();
Semaphore start = new Semaphore(1);
Semaphore end = new Semaphore(1);
start.acquire();
AtomicReference<Object> result = new AtomicReference<>();
new Thread() {
@Override
public void run() {
try {
// Prepare end semaphore
end.acquire();
// Wait to start
start.acquire();
result.set(ringBuffer.write(value, 30, TimeUnit.SECONDS));
} catch (InterruptedException e) {
result.set(e);
} finally {
end.release();
}
}
}.start();
start.release();
Thread.sleep(2000);
ringBuffer.read();
end.acquire();
assertEquals(Boolean.TRUE, result.get());
assertSame(value, ringBuffer.read());
}
@Test
public void test_write_timeout_empty_ringbuffer()
throws Exception {
RingBuffer<Object> ringBuffer = RingBuffer.create(10);
assertTrue(ringBuffer.write(new Object(), 1, TimeUnit.SECONDS));
}
@Test
public void test_write_double_empty_ringbuffer()
throws Exception {
RingBuffer<Object> ringBuffer = RingBuffer.create(10);
assertTrue(ringBuffer.write(new Object()));
assertTrue(ringBuffer.write(new Object()));
}
@Test
public void test_write_timeout_full_ringbuffer()
throws Exception {
RingBuffer<Object> ringBuffer = RingBuffer.create(1);
ringBuffer.write(new Object(), 1, TimeUnit.SECONDS);
long deadline = System.nanoTime() + TimeUnit.SECONDS.toNanos(1);
assertFalse(ringBuffer.write(new Object(), 1, TimeUnit.SECONDS));
assertTrue(System.nanoTime() > deadline);
}
@Test
public void test_concurrent_write()
throws Throwable {
int concurrencyLevel = 100;
RingBuffer<Object> ringBuffer = RingBuffer.create(concurrencyLevel);
Object[] values = new Object[concurrencyLevel];
for (int i = 0; i < concurrencyLevel; i++) {
values[i] = new Object();
}
AtomicReferenceArray<Object> results = new AtomicReferenceArray<Object>(concurrencyLevel);
Semaphore start = new Semaphore(concurrencyLevel);
CountDownLatch end = new CountDownLatch(concurrencyLevel);
start.acquire(concurrencyLevel);
for (int i = 0; i < concurrencyLevel; i++) {
int index = i;
new Thread(() -> {
try {
start.acquire();
results.set(index, ringBuffer.write(values[index]));
} catch (Throwable e) {
results.set(index, e);
} finally {
end.countDown();
}
}).start();
}
start.release(concurrencyLevel);
end.await(20, TimeUnit.SECONDS);
for (int i = 0; i < concurrencyLevel; i++) {
Object result = results.get(i);
if (result instanceof Throwable) {
throw (Throwable) result;
}
assertTrue((Boolean) result);
}
Set<Object> readings = Collections.newSetFromMap(new IdentityHashMap<>());
for (int i = 0; i < concurrencyLevel; i++) {
readings.add(ringBuffer.read());
}
assertEquals(concurrencyLevel, readings.size());
}
}