com.datasalt.utils.commons.TestExpiringSemaphore.java Source code

Java tutorial

Introduction

Here is the source code for com.datasalt.utils.commons.TestExpiringSemaphore.java

Source

/**
 * Copyright [2011] [Datasalt Systems S.L.]
 *
 * 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.datasalt.utils.commons;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import org.apache.hadoop.io.BooleanWritable;
import org.junit.Test;

import com.datasalt.utils.commons.ExpiringSemaphore;

/**
 * Unit tests for the {@link ExpiringSemaphore}
 * 
 * @author pere
 *
 */
public class TestExpiringSemaphore {

    /*
     * Here we will test that after "expiring" time the acquires() done with no release() afterwards become available again
     */
    @Test
    public void testPermitExpiring() throws InterruptedException {
        long expiring = 1000;
        long start = System.currentTimeMillis();
        ExpiringSemaphore semaphore = new ExpiringSemaphore(2, expiring);
        assertEquals(semaphore.availablePermits(), 2);
        semaphore.acquire();
        assertEquals(semaphore.availablePermits(), 1);
        semaphore.acquire();
        // next call will block until one permit expires
        assertEquals(semaphore.availablePermits(), 0);
        semaphore.acquire();
        // expired
        assertTrue(semaphore.expiredCount() >= 1);
        long end = System.currentTimeMillis();
        assertTrue((end - start) >= expiring);
        // let's grab one more one
        semaphore.acquire();
        // expire count = 2
        assertEquals(semaphore.expiredCount(), 2);
    }

    /*
     * Here we will test the usedPermits() method. We will block on it until it reaches = 0 because of automatic expiring.
     */
    @Test
    public void testUsedPermits() throws InterruptedException {
        long expiring = 1000;
        ExpiringSemaphore semaphore = new ExpiringSemaphore(4, expiring);
        semaphore.acquire();
        semaphore.acquire();
        semaphore.acquire();
        semaphore.acquire();
        assertEquals(semaphore.availablePermits(), 0);
        assertEquals(semaphore.usedPermits(), 4);
        while (semaphore.usedPermits() > 0) {
            Thread.sleep(100);
        }
        assertEquals(semaphore.availablePermits(), 4);
        /*
         * Here we are also testing the currentlyExpiredPermits() which shows us a snapshot of the
         * permits that are expired in the semaphore. It tells us how many permits someone could
         * grab with acquire() such that these permits have expired (there wasn't release() called for them).
         */
        assertEquals(semaphore.currentlyExpiredPermits(), 4);
        semaphore.acquire();
        semaphore.acquire();
        semaphore.acquire();
        semaphore.acquire();
        assertEquals(semaphore.expiredCount(), 4);
    }

    /*
     * Here we will test that release() behaves like a normal semaphore. We won't expire any permit.
     */
    @Test
    public void testSequentialRelease() throws InterruptedException {
        long expiring = 10000;
        ExpiringSemaphore semaphore = new ExpiringSemaphore(3, expiring);
        /*
         * Acquire 3
         */
        semaphore.acquire();
        semaphore.acquire();
        semaphore.acquire();
        long start = System.currentTimeMillis();
        /*
         * release + acquire
         */
        semaphore.release();
        semaphore.acquire();
        long end = System.currentTimeMillis();
        assertTrue((end - start) < 50);
        start = System.currentTimeMillis();
        /*
         * release + acquire
         */
        semaphore.release();
        semaphore.acquire();
        end = System.currentTimeMillis();
        assertTrue((end - start) < 50);
        start = System.currentTimeMillis();
        /*
         * release + acquire
         */
        semaphore.release();
        semaphore.acquire();
        end = System.currentTimeMillis();
        assertTrue((end - start) < 50);
        /*
         * Assert we have had no expired permits
         */
        assertEquals(semaphore.expiredCount() + semaphore.currentlyExpiredPermits(), 0);
    }

    /*
     * Here we will test that release() is an operation that awakes threads blocking on acquire()
     * One thread will block on an acquire() and the other (main) thread will release() a resource.
     */
    @Test
    public void testConcurrentRelease() throws InterruptedException {
        final long expiring = 10000;
        final ExpiringSemaphore semaphore = new ExpiringSemaphore(3, expiring);

        Thread t = new Thread() {

            public void run() {
                try {
                    semaphore.acquire();
                    semaphore.acquire();
                    long start = System.currentTimeMillis();
                    semaphore.acquire();
                    long end = System.currentTimeMillis();
                    assertTrue((end - start) < 50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        semaphore.acquire();
        t.start();
        semaphore.release();
        t.join();
        assertEquals(semaphore.expiredCount(), 0);
    }

    /*
     * This parallelism thread just asserts that the semaphore can be used like a normal semaphore.
     * We will use 10 threads that will compete for a 1-sized semaphore and execute a block of code like this:
     * 
     * flag = true
     * flag = false
     * 
     * The threads will assert that flag is always false when they have acquired() the semaphore, otherwise
     * the semaphore is not acting like a mutex.
     */
    @Test
    public void testParallelism() throws InterruptedException {
        final ExpiringSemaphore semaphore = new ExpiringSemaphore(1, 2000);
        final BooleanWritable flag = new BooleanWritable();

        Thread[] threads = new Thread[10];

        for (int i = 0; i < 10; i++) {
            threads[i] = new Thread() {
                @Override
                public void run() {
                    try {
                        for (int i = 0; i < 200; i++) {
                            semaphore.acquire();
                            if (flag.get()) {
                                throw new RuntimeException("Semaphore is not behaving as expected");
                            }
                            flag.set(true);
                            flag.set(false);
                            semaphore.release();
                        }
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            };
        }

        for (int i = 0; i < 10; i++) {
            threads[i].start();
        }

        for (int i = 0; i < 10; i++) {
            threads[i].join();
        }
    }
}