/* * Created on Feb 22, 2007 Copyright (C) 2001-6, Anthony Harrison anh23@pitt.edu * (jactr.org) 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 org.jactr.tools.async; import java.util.concurrent.ExecutorService; import junit.framework.TestCase; import org.antlr.runtime.tree.CommonTree; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.mina.filter.executor.OrderedThreadPoolExecutor; import org.commonreality.mina.protocol.NOOPProtocol; import org.commonreality.mina.protocol.SerializingProtocol; import org.commonreality.mina.service.ClientService; import org.commonreality.mina.service.ServerService; import org.commonreality.mina.transport.LocalTransportProvider; import org.commonreality.mina.transport.NIOTransportProvider; import org.commonreality.net.protocol.IProtocolConfiguration; import org.commonreality.net.transport.ITransportProvider; import org.jactr.core.logging.Logger; import org.jactr.core.logging.impl.DefaultModelLogger; import org.jactr.core.model.IModel; import org.jactr.core.production.IProduction; import org.jactr.core.runtime.ACTRRuntime; import org.jactr.core.runtime.controller.debug.BreakpointType; import org.jactr.core.runtime.controller.debug.DebugController; import org.jactr.io.CommonIO; import org.jactr.io.antlr3.misc.ASTSupport; import org.jactr.tools.async.controller.RemoteInterface; import org.jactr.tools.async.shadow.ShadowController; /** * general MINA remote controller test. the ShadowController is the shadow copy * of the actual NetworkedIODebugController. They can both run as either servers * or clients. * * @author developer */ public class MINATest extends TestCase { /** * logger definition */ static private final Log LOGGER = LogFactory.getLog(MINATest.class); static public final String MODEL_LOCATION = "org/jactr/core/runtime/semantic-model.jactr"; protected IModel _model; /** * @see junit.framework.TestCase#setUp() */ @Override protected void setUp() throws Exception { super.setUp(); _model = loadModel(MODEL_LOCATION); configureModel(_model); configureRuntime(_model); } protected void configureRuntime(IModel model) throws Exception { ACTRRuntime runtime = ACTRRuntime.getRuntime(); runtime.setController(new DebugController()); runtime.addModel(model); } /** * @see junit.framework.TestCase#tearDown() */ @Override protected void tearDown() throws Exception { super.tearDown(); ACTRRuntime runtime = ACTRRuntime.getRuntime(); runtime.setController(null); runtime.removeModel(_model); _model.dispose(); } protected IModel loadModel(String location) throws Exception { CommonTree descriptor = CommonIO.parserTest(MODEL_LOCATION, true, true); CommonIO.compilerTest(descriptor, true, true); return CommonIO.constructorTest(descriptor); } protected void configureModel(IModel model) { org.jactr.core.logging.impl.DefaultModelLogger dml = new DefaultModelLogger(); // dml.setParameter(Logger.CYCLE,"out"); dml.setParameter(Logger.Stream.TIME.toString(), "out"); dml.setParameter(Logger.Stream.OUTPUT.toString(), "out"); // dml.setParameter(Logger.Stream.GOAL.toString(), "err"); dml.setParameter(Logger.Stream.PROCEDURAL.toString(), "out"); // dml.setParameter(Logger.CONFLICT_RESOLUTION, "out"); // dml.setParameter(Logger.CONFLICT_SET, "out"); // dml.setParameter(Logger.ACTIVATION_BUFFER,"out"); // dml.setParameter(Logger.MATCHES,"out"); // dml.setParameter(Logger.EXACT_MATCH,"out"); // dml.setParameter(Logger.PARTIAL_MATCH,"out"); model.install(dml); } protected void connectAndTest(ITransportProvider transport, IProtocolConfiguration protocol, String addressInfo, String credentials, boolean runtimeIsServer, ExecutorService shadowExecutor, ExecutorService runtimeExecutor) throws Exception { RemoteInterface controller = new RemoteInterface(); controller.setTransportProvider(transport); controller.setProtocol(protocol); controller.setAddressInfo(addressInfo); controller.setCredentialInformation(credentials); // controller.setIOExecutorService(runtimeExecutor); controller.setSendOnSuspend(true); /* * the remote controller that just reflects the real one that it * communicates with */ ShadowController remote = new ShadowController(); remote.setTransportProvider(transport); remote.setProtocol(protocol); remote.setAddressInfo(addressInfo); remote.setCredentialInformation(credentials); // remote.setIOExecutorService(shadowExecutor); // addHandlers(remote.getHandler()); if (runtimeIsServer) { remote.setService(new ClientService()); controller.setService(new ServerService()); } else { remote.setService(new ServerService()); controller.setService(new ClientService()); } Exception delayedException = null; try { /* * the server must be running first */ if (runtimeIsServer) { _model.install(controller); remote.attach(); } else { remote.attach(); _model.install(controller); } generalTest(remote); } catch (Exception e) { LOGGER.error("Exception has been caught, delaying until after cleanup ", e); delayedException = e; } finally { if (LOGGER.isDebugEnabled()) LOGGER.debug("Cleaning up - detaching"); /* * disconnect */ remote.detach(false); controller.disconnectSafe(false); /* * would normally block until all connections are closed */ if (LOGGER.isDebugEnabled()) LOGGER.debug("Uninstalling"); _model.uninstall(controller); /* * we should sleep for a bit just to make sure we we've unbound */ Thread.sleep(1000); } if (delayedException != null) throw delayedException; } protected void generalTest(ShadowController remote) throws Exception { remote.waitForConnection(0); assertTrue(remote.isConnected()); assertFalse(remote.isRunning()); assertFalse(remote.isSuspended()); breakpointTest(remote); // runToCompletionTest(remote); assertFalse(remote.isRunning()); assertFalse(remote.isSuspended()); } protected void runToCompletionTest(ShadowController controller) throws Exception { controller.start(); controller.waitForStart(); assertTrue(controller.isRunning()); while (controller.isRunning()) controller.waitForCompletion(100); assertFalse(controller.isRunning()); } protected void breakpointTest(ShadowController controller) throws Exception { /* * add break points for all productions */ for (IProduction production : _model.getProceduralModule().getProductions() .get()) controller.addBreakpoint(BreakpointType.PRODUCTION, _model.getName(), production.getSymbolicProduction().getName()); controller.start(); controller.waitForStart(); assertTrue(controller.isRunning()); String[] productionSequence = { "initial-retrieve", "chain-category", "chain-category", "fail" }; int i = 0; for (String brokeProduction : productionSequence) { if (LOGGER.isDebugEnabled()) LOGGER.debug("Waiting for breakpoint"); assertTrue(controller.waitForSuspension()); CommonTree ast = controller.getBreakpointData(_model.getName()); assertNotNull(ast); String actualName = ASTSupport.getName(ast); if (LOGGER.isDebugEnabled()) LOGGER.debug("Expecting " + brokeProduction + " got " + actualName); assertEquals("production " + i + " fired out of sequence", actualName, brokeProduction); i++; if (LOGGER.isDebugEnabled()) LOGGER.debug("Requesting resumption"); controller.resume(); if (LOGGER.isDebugEnabled()) LOGGER.debug("waiting for resumption"); boolean resumed = controller.waitForResumption(); if (!resumed) { if (LOGGER.isDebugEnabled()) LOGGER .debug("*** runtime state has changed and we have missed some events, suspended:" + controller.isSuspended()); } else if (LOGGER.isDebugEnabled()) LOGGER.debug("runtime has resumed"); } assertEquals("Not all productions fired", i, productionSequence.length); if (controller.isConnected()) controller.waitForCompletion(); assertFalse(controller.isRunning()); } public void testLocalRuntimeServer() throws Exception { ExecutorService shadow = new OrderedThreadPoolExecutor(); ExecutorService runtime = new OrderedThreadPoolExecutor(); connectAndTest(new LocalTransportProvider(), new NOOPProtocol(), "6969", "user:password", true, shadow, runtime); shadow.shutdown(); runtime.shutdown(); } public void testLocalControllerServer() throws Exception { ExecutorService shadow = new OrderedThreadPoolExecutor(); ExecutorService runtime = new OrderedThreadPoolExecutor(); connectAndTest(new LocalTransportProvider(), new NOOPProtocol(), "6969", "user:password", false, shadow, runtime); shadow.shutdown(); runtime.shutdown(); } public void testNIORuntimeServer() throws Exception { ExecutorService shadow = new OrderedThreadPoolExecutor(); ExecutorService runtime = new OrderedThreadPoolExecutor(); connectAndTest(new NIOTransportProvider(), new SerializingProtocol(), "localhost:6969", "user:password", true, shadow, runtime); shadow.shutdown(); runtime.shutdown(); } public void testNIOControllerServer() throws Exception { ExecutorService shadow = new OrderedThreadPoolExecutor(); ExecutorService runtime = new OrderedThreadPoolExecutor(); connectAndTest(new NIOTransportProvider(), new SerializingProtocol(), "localhost:6970", "user:password", false, shadow, runtime); shadow.shutdown(); runtime.shutdown(); } }