/*
* Copyright 2010 Revelytix.
*
* 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 org.mulgara.connection;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicBoolean;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.mulgara.connection.Connection.SessionOp;
import org.mulgara.server.Session;
/**
* Test the command execution methods of Connection interface.
*/
public class ConnectionUnitTest extends TestCase {
protected static ThreadFactory threadFactory = new ThreadFactory() {
public Thread newThread(Runnable r) {
return new Thread(r);
}
};
public ConnectionUnitTest(String name) {
super(name);
}
public static Test suite() {
TestSuite suite = new TestSuite();
suite.addTest(new ConnectionUnitTest("testExecute"));
suite.addTest(new ConnectionUnitTest("testExecuteProxy"));
suite.addTest(new ConnectionUnitTest("testException"));
suite.addTest(new ConnectionUnitTest("testExceptionProxy"));
suite.addTest(new ConnectionUnitTest("testLock"));
suite.addTest(new ConnectionUnitTest("testLockProxy"));
suite.addTest(new ConnectionUnitTest("testCancel"));
suite.addTest(new ConnectionUnitTest("testCancelProxy"));
return suite;
}
public void testExecute() throws Exception {
doTestExecute(null);
}
public void testExecuteProxy() throws Exception {
doTestExecute(threadFactory);
}
public void testException() throws Exception {
doTestException(null);
}
public void testExceptionProxy() throws Exception {
doTestException(threadFactory);
}
public void testLock() throws Exception {
doTestLock(null);
}
public void testLockProxy() throws Exception {
doTestLock(threadFactory);
}
public void testCancel() throws Exception {
doTestCancel(null);
}
public void testCancelProxy() throws Exception {
doTestCancel(threadFactory);
}
protected void doTestExecute(ThreadFactory factory) throws Exception {
Connection conn = new DummyConnection(factory);
final int testValue = 123;
int value = conn.execute(new SessionOp<Integer,Exception>() {
public Integer fn(Session session) throws Exception {
return testValue;
}
});
assertEquals(testValue, value);
final String exMsg = "Test Exception Message";
try {
conn.execute(new SessionOp<Object,Exception>() {
public Object fn(Session arg) throws Exception {
throw new Exception(exMsg);
}
});
fail("Should have thrown exception");
} catch (Exception ex) {
assertEquals(exMsg, ex.getMessage());
}
}
protected void doTestException(ThreadFactory factory) throws Exception {
Connection conn = new DummyConnection(factory);
final Wrapper<Object> exception = new Wrapper<Object>();
try {
conn.execute(new SessionOp<Object,ConnectionTestException>() {
public Object fn(Session arg) throws ConnectionTestException {
ConnectionTestException e = new ConnectionTestException("Test Exception Message");
exception.set(e);
throw e;
}
});
fail("Should have thrown exception");
} catch (ConnectionTestException e) {
assertTrue(e == exception.get());
}
exception.set(null);
try {
conn.execute(new SessionOp<Object,ConnectionTestException>() {
public Object fn(Session arg) throws ConnectionTestException {
RuntimeException e = new RuntimeException("Test Exception Message");
exception.set(e);
throw e;
}
});
fail("Should have thrown exception");
} catch (RuntimeException e) {
assertTrue(e == exception.get());
}
exception.set(null);
try {
conn.execute(new SessionOp<Object,ConnectionTestException>() {
public Object fn(Session arg) throws ConnectionTestException {
Error e = new Error("Test Exception Message");
exception.set(e);
throw e;
}
});
fail("Should have thrown exception");
} catch (Throwable th) {
assertTrue(th == exception.get());
}
}
protected void doTestLock(ThreadFactory factory) throws Exception {
final Connection conn = new DummyConnection(factory);
final AtomicBoolean t1Started = new AtomicBoolean(false);
final AtomicBoolean t1Complete = new AtomicBoolean(false);
final AtomicBoolean t2Started = new AtomicBoolean(false);
final AtomicBoolean t1Error = new AtomicBoolean(false);
final AtomicBoolean t2Error = new AtomicBoolean(false);
Runnable r1 = new Runnable() {
public void run() {
conn.execute(new SessionOp<Object,RuntimeException>() {
public Object fn(Session session) throws RuntimeException {
synchronized (t1Started) {
t1Started.set(true);
t1Started.notify();
}
safeSleep(5000);
if (t2Started.get()) t1Error.set(true);
t1Complete.set(true);
return null;
}
});
}
};
Runnable r2 = new Runnable() {
public void run() {
synchronized (t1Started) {
while (!t1Started.get()) safeWait(t1Started);
}
conn.execute(new SessionOp<Object,RuntimeException>(){
public Object fn(Session session) throws RuntimeException {
if (!t1Complete.get()) t2Error.set(true);
return null;
}
});
}
};
runAll(r1, r2);
assertFalse("t2 started before t1 complete", t1Error.get() || t2Error.get());
}
protected void doTestCancel(ThreadFactory factory) throws Exception {
final Connection conn = new DummyConnection(factory);
final AtomicBoolean interrupted = new AtomicBoolean(false);
final Runnable r = new Runnable() {
public void run() {
boolean result = conn.execute(new SessionOp<Boolean,RuntimeException>() {
public Boolean fn(Session session) throws RuntimeException {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
return true;
}
return false;
}
});
interrupted.set(result);
}
};
Thread t = new Thread(r);
t.start();
safeSleep(1000);
conn.cancel();
safeJoin(t);
assertTrue("thread should have been interrupted", interrupted.get());
}
protected static void safeSleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
fail("Interrupted while sleeping");
}
}
protected static void safeWait(Object obj) {
try {
obj.wait();
} catch (InterruptedException e) {
fail("Interrupted while waiting");
}
}
protected static void safeJoin(Thread t) {
try {
t.join();
} catch (InterruptedException e) {
fail("Interrupted while joining");
}
}
protected static void runAll(Runnable... ops) {
List<Thread> threads = new ArrayList<Thread>(ops.length);
for (Runnable r : ops) {
Thread t = new Thread(r);
t.start();
threads.add(t);
}
for (Thread t : threads) {
safeJoin(t);
}
}
protected static class ConnectionTestException extends Exception {
private static final long serialVersionUID = 7763762484291936870L;
public ConnectionTestException() {
super();
}
public ConnectionTestException(String message) {
super(message);
}
}
private static class Wrapper<T> {
private T value = null;
public void set(T value) { this.value = value; }
public T get() { return this.value; }
}
}