Package org.locationtech.udig

Source Code of org.locationtech.udig.UDIGDisplaySafeLockTest

/*
*    uDig - User Friendly Desktop Internet GIS client
*    http://udig.refractions.net
*    (C) 2012, Refractions Research Inc.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD
* License v1.0 (http://udig.refractions.net/files/bsd3-v10.html).
*/
package org.locationtech.udig;

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

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.locationtech.udig.ui.PlatformGIS;
import org.locationtech.udig.ui.UDIGDisplaySafeLock;
import org.locationtech.udig.ui.WaitCondition;
import org.locationtech.udig.ui.tests.support.UDIGTestUtil;

import org.eclipse.swt.widgets.Display;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;

public class UDIGDisplaySafeLockTest {

    int WAIT_LENGTH = 10000;
    private UDIGDisplaySafeLock lock;

    @Before
    public void setUp() throws Exception {
        lock = new UDIGDisplaySafeLock();
    }

    enum State {
        NO_LOCK, THREAD_HAS_LOCK, DISPLAY_WAITING_FOR_LOCK, THREAD_RELEASED_LOCK, DISPLAY_HAS_LOCK, THREAD_WAITING_FOR_LOCK
    }

    @Test
    public void testLock() throws Throwable {
        final Thread displayThread = Thread.currentThread();
        final Set<State> states = new HashSet<State>();
        final Lock lockLock = new ReentrantLock();
        final Throwable[] exception = new Throwable[1];
        final boolean[] passed = new boolean[1];

        Runnable other = new Runnable(){
            public void run() {
                try {
                    lockLock.lock();
                    lock.lock();
                    states.add(State.THREAD_HAS_LOCK);
                    lockLock.unlock();

                    while( !states.contains(State.DISPLAY_WAITING_FOR_LOCK) ) {
                        Thread.sleep(100);
                    }

                    Display.getDefault().asyncExec(new Runnable(){
                        public void run() {
                            passed[0] = true;
                        }
                    });

                    PlatformGIS.wait(200, WAIT_LENGTH, new WaitCondition(){

                        public boolean isTrue() {
                            return passed[0] = true;
                        }

                    }, null);

                    assertTrue(passed[0]);
                    states.remove(State.THREAD_HAS_LOCK);
                    lock.unlock();

                    while( !states.contains(State.DISPLAY_HAS_LOCK) )
                        Thread.sleep(200);

                    lockLock.lock();

                    states.add(State.THREAD_WAITING_FOR_LOCK);
                    lock.lock();
                    states.add(State.THREAD_HAS_LOCK);
                    lockLock.unlock();

                    PlatformGIS.wait(200, WAIT_LENGTH, new WaitCondition(){

                        public boolean isTrue() {
                            return passed[0];
                        }

                    }, null);

                    lock.unlock();
                    states.remove(State.THREAD_HAS_LOCK);
                    states.add(State.THREAD_RELEASED_LOCK);
                } catch (Throwable e) {
                    exception[0] = e;
                    displayThread.interrupt();
                }
            }
        };

        Thread t = new Thread(other, "Lock Test Thread"); //$NON-NLS-1$
        t.start();

        // wait til thread has lock
        UDIGTestUtil.inDisplayThreadWait(WAIT_LENGTH, new WaitCondition(){

            public boolean isTrue() {
                return states.contains(State.THREAD_HAS_LOCK);
            }

        }, false);

        lockLock.lock();
        states.add(State.DISPLAY_WAITING_FOR_LOCK);
        lock.lock();
        states.remove(State.DISPLAY_WAITING_FOR_LOCK);
        states.add(State.DISPLAY_HAS_LOCK);
        lockLock.unlock();

        // make sure thread has released lock.
        if (exception[0] != null)
            throw exception[0];
        assertFalse(states.contains(State.THREAD_HAS_LOCK));
        assertTrue(passed[0]);

        passed[0] = false;

        UDIGTestUtil.inDisplayThreadWait(WAIT_LENGTH, new WaitCondition(){

            public boolean isTrue() {
                return states.contains(State.THREAD_WAITING_FOR_LOCK);
            }

        }, false);

        if (exception[0] != null)
            throw exception[0];

        states.remove(State.DISPLAY_HAS_LOCK);
        lock.unlock();

        UDIGTestUtil.inDisplayThreadWait(5000, new WaitCondition(){

            public boolean isTrue() {
                return states.contains(State.THREAD_HAS_LOCK);
            }

        }, false);
        if (exception[0] != null)
            throw exception[0];

        passed[0] = true;

        UDIGTestUtil.inDisplayThreadWait(5000, new WaitCondition(){

            public boolean isTrue() {
                return states.contains(State.THREAD_RELEASED_LOCK);
            }

        }, false);
        if (exception[0] != null)
            throw exception[0];

    }

    @Test
    public void testUnlockOrder() throws Exception {

        final boolean[] canQuit = new boolean[1];
        canQuit[0] = false;

        final boolean[] gotLock = new boolean[1];
        gotLock[0] = false;

        Runnable thread1 = new Runnable(){
            public void run() {
                lock.lock();
                gotLock[0] = true;
                try {
                    PlatformGIS.wait(200, WAIT_LENGTH, new WaitCondition(){

                        public boolean isTrue() {
                            return canQuit[0];
                        }

                    }, null);

                    lock.unlock();
                } catch (InterruptedException e) {
                    throw (RuntimeException) new RuntimeException().initCause(e);
                }
            }
        };

        Thread t1 = new Thread(thread1);
        t1.start();

        final boolean[] waiting = new boolean[1];
        waiting[0] = false;

        final boolean[] gotLock2 = new boolean[1];
        gotLock2[0] = false;
        Runnable thread2 = new Runnable(){
            public void run() {
                waiting[0] = true;
                lock.lock();
                gotLock2[0] = true;
            }
        };

        Thread t2 = new Thread(thread2);
        t2.start();

        UDIGTestUtil.inDisplayThreadWait(WAIT_LENGTH, new WaitCondition(){

            public boolean isTrue() {
                return gotLock[0];
            }

        }, true);

        canQuit[0] = true;
        lock.lock();

        assertFalse(gotLock2[0]);

        lock.unlock();

        UDIGTestUtil.inDisplayThreadWait(WAIT_LENGTH, new WaitCondition(){

            public boolean isTrue() {
                return gotLock2[0];
            }

        }, true);

    }

    @Test
    public void testTryLock() throws Exception {
        assertTrue(lock.tryLock());
       
        assertTrue(lock.isHeldByCurrentThread());
        final boolean[] result=new boolean[1];
        result[0]=true;
        new Thread(){
            @Override
            public void run() {
                result[0]=lock.tryLock();
            }
        }.start();
       
        UDIGTestUtil.inDisplayThreadWait(WAIT_LENGTH, new WaitCondition(){

            public boolean isTrue() {
                return !result[0];
            }
           
        }, true);
    }

    @Test
    public void testTryLockTimout() throws Throwable {
        assertTrue(lock.tryLock(100, TimeUnit.MICROSECONDS));
       
        assertTrue(lock.isHeldByCurrentThread());
        final boolean[] ready=new boolean[1];
        ready[0]=false;
       
        final boolean[] obtained=new boolean[1];
        obtained[0]=false;
        final Throwable[] exception=new Throwable[1];
        new Thread(){
            @Override
            public void run() {
                ready[0]=true;
                try {
                    obtained[0]=lock.tryLock(100, TimeUnit.SECONDS);
                } catch (Throwable e) {
                    exception[0]=e;
                }
            }
        }.start();
       
        UDIGTestUtil.inDisplayThreadWait(WAIT_LENGTH, new WaitCondition(){

            public boolean isTrue() {
                return ready[0];
            }
           
        }, false);
        if( exception[0]!=null )
            throw exception[0];

        lock.unlock();
       
        UDIGTestUtil.inDisplayThreadWait(WAIT_LENGTH, new WaitCondition(){

            public boolean isTrue() {
                return obtained[0];
            }
           
        }, false);
        if( exception[0]!=null )
            throw exception[0];
       
       
    }

    @Test
    public void testReentrance() throws Exception {
        final Thread current = Thread.currentThread();
        Thread t = new Thread(){
            @Override
            public void run() {
                try {
                    PlatformGIS.wait(100, WAIT_LENGTH, new WaitCondition(){

                        public boolean isTrue() {
                            return !lock.isLocked();
                        }

                    }, null);
                } catch (InterruptedException e) {
                    current.interrupt();
                }
            }
        };

        t.start();

        lock.lockInterruptibly();
        lock.lockInterruptibly();

        assertTrue(lock.isHeldByCurrentThread());
        assertEquals(2, lock.getHoldCount());

        lock.lockInterruptibly();

        assertEquals(3, lock.getHoldCount());

        lock.unlock();
        assertTrue(lock.isHeldByCurrentThread());
        assertEquals(2, lock.getHoldCount());

        lock.unlock();
        assertTrue(lock.isHeldByCurrentThread());
        assertEquals(1, lock.getHoldCount());

        lock.unlock();
        assertFalse(lock.isHeldByCurrentThread());
        assertEquals(0, lock.getHoldCount());

    }

    @Test
    public void testWaitQueueLength() throws Exception {
        final Condition condition = lock.newCondition();
        assertEquals(0, lock.getWaitQueueLength(condition));
        assertFalse(lock.hasWaiters(condition));

        final Exception[] ex=new Exception[1];
       
        Thread t = new Thread(){
            @Override
            public void run() {
                try {
                    lock.lock();
                    condition.await();
                    lock.unlock();
                } catch (Exception e) {
                    ex[0]=e;
                }
            }
        };

        t.start();

        UDIGTestUtil.inDisplayThreadWait(WAIT_LENGTH, new WaitCondition(){

            public boolean isTrue() {
                return lock.getWaitQueueLength(condition) == 1 || ex[0]!=null;
            }

        }, true);
        if( ex[0]!=null )
            throw ex[0];
        assertTrue(lock.hasWaiters(condition));

        lock.lock();
        condition.signal();
        lock.unlock();

        UDIGTestUtil.inDisplayThreadWait(WAIT_LENGTH, new WaitCondition(){

            public boolean isTrue() {
                return lock.getWaitQueueLength(condition) == 0;
            }

        }, true);

        assertFalse(lock.hasWaiters(condition));
    }
   
    @Test
    public void testLockInterruptibly() throws Exception {
        final boolean[] interrupted = new boolean[1];
        final boolean[] isLocked = new boolean[1];
        lock.lock();

        Thread t = new Thread(){
            @Override
            public void run() {
                try {
                    isLocked[0] = true;
                    lock.lockInterruptibly();
                } catch (InterruptedException e) {
                    interrupted[0] = true;
                }
            }
        };

        t.start();

        UDIGTestUtil.inDisplayThreadWait(WAIT_LENGTH, new WaitCondition(){

            public boolean isTrue() {
                return isLocked[0];
            }

        }, true);

        t.interrupt();

        UDIGTestUtil.inDisplayThreadWait(WAIT_LENGTH, new WaitCondition(){

            public boolean isTrue() {
                return interrupted[0];
            }

        }, true);

        assertTrue(interrupted[0]);
        lock.unlock();
    }
   
    @Test
    public void testConditionWithDisplay() throws Exception {
        lock.lock();
        try {
            final Condition condition = lock.newCondition();
            Display.getCurrent().asyncExec(new Runnable(){

                public void run() {
                    lock.lock();
                    try {
                        condition.signal();
                    } finally {
                        lock.unlock();
                    }
                }

            });

            condition.await();
        } finally {
            lock.unlock();
        }
    }
   
    @Ignore("fails in tycho")
    @Test
    public void testSignalAll() throws Exception {
            final Condition condition = lock.newCondition();
            final Exception[] exception=new Exception[1];
            final boolean[] awake=new boolean[2];
            Thread t=new Thread(){

                public void run() {
                    lock.lock();
                    try {
                        condition.await();
                        awake[0]=true;
                    } catch (InterruptedException e) {
                        exception[0]=e;
                    } finally {
                        lock.unlock();
                    }
                }

            };
            t.start();

            Thread t2=new Thread(){

                public void run() {
                    lock.lock();
                    try {
                        condition.await();
                        awake[1]=true;
                    } catch (InterruptedException e) {
                        exception[0]=e;
                    } finally {
                        lock.unlock();
                    }
                }

            };
            t2.start();

            UDIGTestUtil.inDisplayThreadWait(WAIT_LENGTH, new WaitCondition(){

                public boolean isTrue() {
                    return lock.getWaitQueueLength(condition)==2;
                }
               
            }, false);
            if( exception[0]!=null )
                throw exception[0];
            lock.lock();
            condition.signalAll();
            lock.unlock();
            UDIGTestUtil.inDisplayThreadWait(WAIT_LENGTH, new WaitCondition(){

                public boolean isTrue() {
                    return lock.getWaitQueueLength(condition)==0;
                }
               
            }, false);
            if( exception[0]!=null )
                throw exception[0];
            assertTrue(awake[0]);
            assertTrue(awake[1]);
           
    }
   
    /**
     * This is a special case that we found causes a bug.  See <a href="http://jira.codehaus.org/browse/UDIG-1007"/>
     *
     * @throws Exception
     */
    @Test
    public void testLockSignalLockUnlockUnlock() throws Exception {
        final Display display=Display.getCurrent();
        final Set<State> state=new CopyOnWriteArraySet<State>();
        final boolean[] done=new boolean[1];
        done[0]=false;
       
        Thread t=new Thread(){

            public void run() {
                lock.lock();
                state.add(UDIGDisplaySafeLockTest.State.THREAD_HAS_LOCK);
                final boolean[] locked=new boolean[1];
                locked[0]=false;

                display.asyncExec(new Runnable(){
                    public void run() {
                        display.asyncExec(new Runnable(){
                            public void run() {
                                state.add(UDIGDisplaySafeLockTest.State.DISPLAY_WAITING_FOR_LOCK);
                                lock.lock();
                                lock.unlock();

                                state.remove(UDIGDisplaySafeLockTest.State.DISPLAY_WAITING_FOR_LOCK);
                            }
                        });
                        lock.lock();
                        locked[0]=true;
                        lock.unlock();
                    }
                });
               
                long timeout=200000;
                long start=System.currentTimeMillis();
               
                while( !state.contains(UDIGDisplaySafeLockTest.State.DISPLAY_WAITING_FOR_LOCK) && timeout>(System.currentTimeMillis()-start) ){
                    synchronized (this) {
                        try {
                            wait(200);
                        } catch (InterruptedException e) {
                            throw (RuntimeException) new RuntimeException( ).initCause( e );
                        }
                    }
                }
               
                lock.unlock();
                state.remove(UDIGDisplaySafeLockTest.State.THREAD_HAS_LOCK);
               
                start=System.currentTimeMillis();
                while( (!locked[0]) && timeout>(System.currentTimeMillis()-start) ){
                    synchronized (this) {
                        try {
                            wait(200);
                        } catch (InterruptedException e) {
                            throw (RuntimeException) new RuntimeException( ).initCause( e );
                        }
                    }
                }

                if( !locked[0] ){
                    display.getThread().interrupt();
                    Exception exception=new Exception("Test Failed in a blocking manner so killing tests... Sorry no other way"); //$NON-NLS-1$
                    exception.printStackTrace();
                    System.exit(-1);
                }
                done[0]=true;
            }

        };
        t.start();

        UDIGTestUtil.inDisplayThreadWait(5000, new WaitCondition(){

            public boolean isTrue() {
                return state.contains(State.THREAD_HAS_LOCK);
            }
           
        }, false);

        lock.lock();

        UDIGTestUtil.inDisplayThreadWait(5000, new WaitCondition(){

            public boolean isTrue() {
                return done[0];
            }
           
        }, true);
        lock.unlock();
    }
}
TOP

Related Classes of org.locationtech.udig.UDIGDisplaySafeLockTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.