/******************************************************************************* * ALMA - Atacama Large Millimiter Array * (c) European Southern Observatory, 2002 * Copyright by ESO (in the framework of the ALMA collaboration) * and Cosylab 2002, All rights reserved * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package alma.ACS.jbaci.test; import java.util.Vector; import java.util.logging.Logger; import junit.framework.TestCase; import org.omg.CORBA.Context; import org.omg.CORBA.ContextList; import org.omg.CORBA.DomainManager; import org.omg.CORBA.ExceptionList; import org.omg.CORBA.NVList; import org.omg.CORBA.NamedValue; import org.omg.CORBA.Policy; import org.omg.CORBA.Request; import org.omg.CORBA.SetOverrideType; import alma.ACS.CBDescIn; import alma.ACS.CBDescOut; import alma.ACS.Callback; import alma.ACS.jbaci.BACIDispatchAction; import alma.ACS.jbaci.BACIFramework; import alma.ACS.jbaci.CallbackDispatcher; import alma.ACS.jbaci.CompletionUtil; import alma.ACSErr.Completion; import alma.acs.container.CleaningDaemonThreadFactory; import alma.acs.logging.ClientLogManager; /** * <code>BACIDispatchAction</code> test. * @author <a href="mailto:matej.sekoranjaATcosylab.com">Matej Sekoranja</a> * @version $id$ */ public class BACIDispatchActionTest extends TestCase { /** * Response wait time in ms. Defaults to 5s. */ private static final int RESPONSE_WAIT_TIME = 5000; /** * Dummy response wait time in ms. Defaults to 2s. */ private static final int DUMMY_WAIT_TIME = 2000; /** * Thread factory for BACI FW. */ private CleaningDaemonThreadFactory threadFactory; private Logger logger; /** * Dispatch action. */ class DispatchAction { public DispatchAction( int type, Object value, Callback callback, Completion completion, CBDescOut desc) { this.type = type; this.value = value; this.callback = callback; this.completion = completion; this.desc = desc; } /** * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals(Object obj) { DispatchAction da = (DispatchAction)obj; return (type == da.type && value == da.value && desc == da.desc && completion == da.completion && callback == da.callback); } public int type; public Object value; public CBDescOut desc; public Completion completion; public Callback callback; } /** * Test callback dispatcher impl. * Always sucessfull callback dispatcher. */ class TestCallbackDispatcher implements CallbackDispatcher { /** * Sync. response queue. */ protected Vector responseQueue = new Vector(); /** * @see alma.ACS.jbaci.CallbackDispatcher#dispatchCallback(int, java.lang.Object, alma.ACS.Callback, alma.ACSErr.Completion, alma.ACS.CBDescOut) */ public boolean dispatchCallback( int type, Object value, Callback callback, Completion completion, CBDescOut desc) { responseQueue.add(new DispatchAction(type, value, callback, completion, desc)); if ((type != CallbackDispatcher.WORKING_TYPE && type != CallbackDispatcher.DONE_TYPE) || callback == null || completion == null || desc == null) return false; else return true; } /** * Get response queue. * @return response queue. */ public Vector getResponseQueue() { return responseQueue; } } /** * Always disaster callback dispatcher. */ class PerfectCallbackDispatcher extends TestCallbackDispatcher { /** * @see alma.ACS.jbaci.CallbackDispatcher#dispatchCallback(int, java.lang.Object, alma.ACS.Callback, alma.ACSErr.Completion, alma.ACS.CBDescOut) */ public synchronized boolean dispatchCallback( int type, Object value, Callback callback, Completion completion, CBDescOut desc) { boolean retVal = super.dispatchCallback(type, value, callback, completion, desc); this.notify(); return retVal; } } /** * Always disaster callback dispatcher. */ class DisasterCallbackDispatcher extends TestCallbackDispatcher { /** * Failure count. */ private int count = 0; /** * @see alma.ACS.jbaci.CallbackDispatcher#dispatchCallback(int, java.lang.Object, alma.ACS.Callback, alma.ACSErr.Completion, alma.ACS.CBDescOut) */ public synchronized boolean dispatchCallback( int type, Object value, Callback callback, Completion completion, CBDescOut desc) { super.dispatchCallback(type, value, callback, completion, desc); if (++count == 3) this.notify(); return false; } } /** * Exception callback dispatcher impl. * Always throws exception. */ class ExceptionCallbackDispatcher extends TestCallbackDispatcher { /** * Failure count. */ private int count = 0; /** * @see alma.ACS.jbaci.CallbackDispatcher#dispatchCallback(int, java.lang.Object, alma.ACS.Callback, alma.ACSErr.Completion, alma.ACS.CBDescOut) */ public synchronized boolean dispatchCallback( int type, Object value, Callback callback, Completion completion, CBDescOut desc) { super.dispatchCallback(type, value, callback, completion, desc); if (++count == 3) this.notify(); throw new RuntimeException("test exception"); } } /** * First filed callback dispatcher. */ class FirstFailedCallbackDispatcher extends TestCallbackDispatcher { /** * @see alma.ACS.jbaci.CallbackDispatcher#dispatchCallback(int, java.lang.Object, alma.ACS.Callback, alma.ACSErr.Completion, alma.ACS.CBDescOut) */ public synchronized boolean dispatchCallback( int type, Object value, Callback callback, Completion completion, CBDescOut desc) { // simple impl. and thread-safe boolean first = true; DispatchAction[] actions = null; synchronized (responseQueue) { actions = new DispatchAction[responseQueue.size()]; responseQueue.toArray(actions); } for (int i = 0; first && i < actions.length; i++) if (type == actions[i].type && value == actions[i].value && callback == actions[i].callback && completion == actions[i].completion && desc == actions[i].desc) first = false; super.dispatchCallback(type, value, callback, completion, desc); if (!first) this.notify(); return !first; } } /** * Override policy test dispatcher impl. * Always throws exception. */ class OverrideTestCallbackDispatcher extends TestCallbackDispatcher { /** * Constructor. */ public OverrideTestCallbackDispatcher() { this(false); } /** * Constructor. */ public OverrideTestCallbackDispatcher(boolean blockingFails) { this.blockingFails = blockingFails; } /** * Failure count. */ private int count = 0; /** * Failure count. */ private boolean blockingFails; /** * @see alma.ACS.jbaci.CallbackDispatcher#dispatchCallback(int, java.lang.Object, alma.ACS.Callback, alma.ACSErr.Completion, alma.ACS.CBDescOut) */ public synchronized boolean dispatchCallback( int type, Object value, Callback callback, Completion completion, CBDescOut desc) { boolean retVal = super.dispatchCallback(type, value, callback, completion, desc); this.notify(); // first callback will block, so that other request could do some override themselves if (++count == 1) { try { this.wait(RESPONSE_WAIT_TIME); } catch (InterruptedException ie) {} if (blockingFails) return false; } return retVal; } } /** * Test callback impl. */ class TestCallback implements Callback { /** * @see alma.ACS.CallbackOperations#negotiate(long, alma.ACS.CBDescOut) */ public boolean negotiate(long arg0, CBDescOut arg1) { return false; } /** * @see org.omg.CORBA.Object#_create_request(org.omg.CORBA.Context, java.lang.String, org.omg.CORBA.NVList, org.omg.CORBA.NamedValue, org.omg.CORBA.ExceptionList, org.omg.CORBA.ContextList) */ public Request _create_request( Context ctx, String operation, NVList arg_list, NamedValue result, ExceptionList exclist, ContextList ctxlist) { // auto-generated method stub return null; } /** * @see org.omg.CORBA.Object#_create_request(org.omg.CORBA.Context, java.lang.String, org.omg.CORBA.NVList, org.omg.CORBA.NamedValue) */ public Request _create_request( Context ctx, String operation, NVList arg_list, NamedValue result) { // auto-generated method stub return null; } /** * @see org.omg.CORBA.Object#_duplicate() */ public org.omg.CORBA.Object _duplicate() { // auto-generated method stub return null; } /** * @see org.omg.CORBA.Object#_get_domain_managers() */ public DomainManager[] _get_domain_managers() { // auto-generated method stub return null; } /** * @see org.omg.CORBA.Object#_get_interface_def() */ public org.omg.CORBA.Object _get_interface_def() { // auto-generated method stub return null; } /** * @see org.omg.CORBA.Object#_get_policy(int) */ public Policy _get_policy(int policy_type) { // auto-generated method stub return null; } /** * @see org.omg.CORBA.Object#_hash(int) */ public int _hash(int maximum) { // auto-generated method stub return 0; } /** * @see org.omg.CORBA.Object#_is_a(java.lang.String) */ public boolean _is_a(String repositoryIdentifier) { // auto-generated method stub return false; } /** * @see org.omg.CORBA.Object#_is_equivalent(org.omg.CORBA.Object) */ public boolean _is_equivalent(org.omg.CORBA.Object other) { // auto-generated method stub return false; } /** * @see org.omg.CORBA.Object#_non_existent() */ public boolean _non_existent() { // auto-generated method stub return false; } /** * @see org.omg.CORBA.Object#_release() */ public void _release() { // auto-generated method stub } /** * @see org.omg.CORBA.Object#_request(java.lang.String) */ public Request _request(String operation) { // auto-generated method stub return null; } public org.omg.CORBA.ORB _get_orb() { return null; } public org.omg.CORBA.Object _get_component() { return null; } public boolean _validate_connection( org.omg.CORBA.PolicyListHolder inconsistent_policies ) { return false; } public org.omg.CORBA.Policy[] _get_policy_overrides( int[] types ) { return null; } public org.omg.CORBA.Policy _get_client_policy( int type ) { return null; } public org.omg.CORBA.Object _set_policy_overrides ( Policy[] policies, SetOverrideType set_add) { return null; } public String _repository_id() { return null; } public org.omg.CORBA.InterfaceDef _get_interface() { return null; } /** * @see org.omg.CORBA.Object#_set_policy_override(org.omg.CORBA.Policy[], org.omg.CORBA.SetOverrideType) */ public org.omg.CORBA.Object _set_policy_override( Policy[] policies, SetOverrideType set_add) { // auto-generated method stub return null; } } /** * Constructor for BACIDispatchActionTest. * @param name */ public BACIDispatchActionTest(String name) { super(name); } protected void setUp() throws Exception { String name = getClass().getSimpleName(); logger = ClientLogManager.getAcsLogManager().getLoggerForApplication(name, false); logger.info("START----------------------------" + getName() + "-------------"); threadFactory = new CleaningDaemonThreadFactory(name, logger); BACIFramework.INSTANCE.initialize(threadFactory); } protected void tearDown() throws Exception { // this should clean all the threads BACIFramework.INSTANCE.shutdown(); threadFactory.cleanUp(); logger.info("END------------------------------" + getName() + "-------------\n\n"); } /** * Methods that check dispatcher response. */ private void checkResponse( Object value, Completion completion, CBDescIn descIn, Callback callback, DispatchAction response) { // check reponse type assertEquals(CallbackDispatcher.DONE_TYPE, response.type); // check value (compare pointers) assertTrue(value == response.value); // check callback (compare callback) assertTrue(callback == response.callback); // check descriptor assertEquals(descIn.id_tag, response.desc.id_tag); // check completion (compare pointers) assertTrue(completion == response.completion); } /** * Dummy wait. */ private void dummyWait() { try { Thread.sleep(DUMMY_WAIT_TIME); } catch (InterruptedException ie) {} } /** * Normal (success) test. */ public void testNormal() { Object value = new Object(); Completion completion = CompletionUtil.generateNoErrorCompletion(); CBDescIn descIn = new CBDescIn(50000, 50000, 1234); Callback callback = new TestCallback(); TestCallbackDispatcher dispatcher = new PerfectCallbackDispatcher(); BACIDispatchAction action = new BACIDispatchAction(callback, descIn, dispatcher); synchronized (dispatcher) { action.dispatchDoneRequest(completion, value); try { // wait dispatcher.wait(RESPONSE_WAIT_TIME); } catch (InterruptedException ie) {} } // dummy wait (just in case there is a bug and more responses will come) dummyWait(); // only 1 response is expected assertEquals(1, dispatcher.getResponseQueue().size()); DispatchAction response = (DispatchAction)dispatcher.getResponseQueue().firstElement(); // check response checkResponse(value, completion, descIn, callback, response); } /** * First failed then success test. */ public void testFirstFailed() { Object value = new Object(); Completion completion = CompletionUtil.generateNoErrorCompletion(); CBDescIn descIn = new CBDescIn(50000, 50000, 1234); Callback callback = new TestCallback(); TestCallbackDispatcher dispatcher = new FirstFailedCallbackDispatcher(); BACIDispatchAction action = new BACIDispatchAction(callback, descIn, dispatcher); synchronized (dispatcher) { action.dispatchDoneRequest(completion, value); try { // wait dispatcher.wait(RESPONSE_WAIT_TIME); } catch (InterruptedException ie) {} } // dummy wait (just in case there is a bug and more responses will come) dummyWait(); // only 2 (failed and successful) responses are expected assertEquals(2, dispatcher.getResponseQueue().size()); // should be the same assertEquals(dispatcher.getResponseQueue().get(0), dispatcher.getResponseQueue().get(1)); DispatchAction response = (DispatchAction)dispatcher.getResponseQueue().firstElement(); // check response checkResponse(value, completion, descIn, callback, response); } /** * Always fails test. */ public void testAlwaysFails() { Object value = new Object(); Completion completion = CompletionUtil.generateNoErrorCompletion(); CBDescIn descIn = new CBDescIn(50000, 50000, 1234); Callback callback = new TestCallback(); TestCallbackDispatcher dispatcher = new DisasterCallbackDispatcher(); BACIDispatchAction action = new BACIDispatchAction(callback, descIn, dispatcher); synchronized (dispatcher) { action.dispatchDoneRequest(completion, value); try { // wait dispatcher.wait(RESPONSE_WAIT_TIME); } catch (InterruptedException ie) {} } // dummy wait (just in case there is a bug and more responses will come) dummyWait(); // only 3 responses (retries) are expected assertEquals(3, dispatcher.getResponseQueue().size()); // should be the same assertEquals(dispatcher.getResponseQueue().get(0), dispatcher.getResponseQueue().get(1)); DispatchAction response = (DispatchAction)dispatcher.getResponseQueue().firstElement(); // check response checkResponse(value, completion, descIn, callback, response); } /** * Always throws exception. */ public void testException() { Object value = new Object(); Completion completion = CompletionUtil.generateNoErrorCompletion(); CBDescIn descIn = new CBDescIn(50000, 50000, 1234); Callback callback = new TestCallback(); TestCallbackDispatcher dispatcher = new ExceptionCallbackDispatcher(); BACIDispatchAction action = new BACIDispatchAction(callback, descIn, dispatcher); synchronized (dispatcher) { action.dispatchDoneRequest(completion, value); try { // wait dispatcher.wait(RESPONSE_WAIT_TIME); } catch (InterruptedException ie) {} } // dummy wait (just in case there is a bug and more responses will come) dummyWait(); // only 3 responses (retries) are expected assertEquals(3, dispatcher.getResponseQueue().size()); // should be the same assertEquals(dispatcher.getResponseQueue().get(0), dispatcher.getResponseQueue().get(1)); DispatchAction response = (DispatchAction)dispatcher.getResponseQueue().firstElement(); // check response checkResponse(value, completion, descIn, callback, response); } /** * No error override policy test. */ public void noErrorOverrideTest(boolean blockingFails) { Object value = new Object(); Completion completion = CompletionUtil.generateNoErrorCompletion(); Completion completion2 = CompletionUtil.generateNoErrorCompletion(); CBDescIn descIn = new CBDescIn(50000, 50000, 1234); Callback callback = new TestCallback(); TestCallbackDispatcher dispatcher = new OverrideTestCallbackDispatcher(blockingFails); BACIDispatchAction action = new BACIDispatchAction(callback, descIn, dispatcher); action.setOverridePolicy(true); synchronized (dispatcher) { // blocking request action.dispatchDoneRequest(completion, value); try { // wait dispatcher.wait(RESPONSE_WAIT_TIME); } catch (InterruptedException ie) {} } synchronized (dispatcher) { // to be overriden action.dispatchDoneRequest(completion, value); action.dispatchDoneRequest(completion, value); action.dispatchDoneRequest(completion, value); // to survive ;) action.dispatchDoneRequest(completion2, value); // release blocking request dispatcher.notify(); try { // wait dispatcher.wait(RESPONSE_WAIT_TIME); } catch (InterruptedException ie) {} } // dummy wait (just in case there is a bug and more responses will come) dummyWait(); // only 2 responses are expected assertEquals(2, dispatcher.getResponseQueue().size()); DispatchAction response = (DispatchAction)dispatcher.getResponseQueue().firstElement(); DispatchAction response2 = (DispatchAction)dispatcher.getResponseQueue().get(1); // check response checkResponse(value, completion, descIn, callback, response); checkResponse(value, completion2, descIn, callback, response2); } /** * Override policy test. */ public void testOverrideTest() { noErrorOverrideTest(false); } /** * Override policy test. */ public void testOverrideBlockingFailsTest() { noErrorOverrideTest(true); } /** * Override policy test (blocking fails, none to override). */ public void testOverrideBlockingFailsNoneToOverrideTest() { Object value = new Object(); Completion completion = CompletionUtil.generateNoErrorCompletion(); CBDescIn descIn = new CBDescIn(50000, 50000, 1234); Callback callback = new TestCallback(); TestCallbackDispatcher dispatcher = new OverrideTestCallbackDispatcher(true); BACIDispatchAction action = new BACIDispatchAction(callback, descIn, dispatcher); action.setOverridePolicy(true); synchronized (dispatcher) { // blocking request action.dispatchDoneRequest(completion, value); try { // wait dispatcher.wait(RESPONSE_WAIT_TIME); } catch (InterruptedException ie) {} } synchronized (dispatcher) { // notift blocking request dispatcher.notify(); } // dummy wait (just in case there is a bug and more responses will come) dummyWait(); // only 2 (failed and successful) responses are expected assertEquals(2, dispatcher.getResponseQueue().size()); // should be the same assertEquals(dispatcher.getResponseQueue().get(0), dispatcher.getResponseQueue().get(1)); DispatchAction response = (DispatchAction)dispatcher.getResponseQueue().firstElement(); // check response checkResponse(value, completion, descIn, callback, response); } public static void main(String[] args) { junit.textui.TestRunner.run(BACIDispatchActionTest.class); // System.exit(0); } }