You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@etch.apache.org by sc...@apache.org on 2009/02/04 22:29:08 UTC

svn commit: r740897 [1/2] - in /incubator/etch/trunk: ./ interoptester/ interoptester/example/ interoptester/example/src/ interoptester/example/src/main/ interoptester/example/src/main/etch/ interoptester/example/src/main/java/ interoptester/example/sr...

Author: sccomer
Date: Wed Feb  4 21:29:06 2009
New Revision: 740897

URL: http://svn.apache.org/viewvc?rev=740897&view=rev
Log:
fix for ETCH-39: create directory structure for interoperability tester

Added:
    incubator/etch/trunk/interoptester/
    incubator/etch/trunk/interoptester/example/   (with props)
    incubator/etch/trunk/interoptester/example/src/
    incubator/etch/trunk/interoptester/example/src/main/
    incubator/etch/trunk/interoptester/example/src/main/etch/
    incubator/etch/trunk/interoptester/example/src/main/etch/IOT.etch   (with props)
    incubator/etch/trunk/interoptester/example/src/main/java/
    incubator/etch/trunk/interoptester/example/src/main/java/org/
    incubator/etch/trunk/interoptester/example/src/main/java/org/apache/
    incubator/etch/trunk/interoptester/example/src/main/java/org/apache/etch/
    incubator/etch/trunk/interoptester/example/src/main/java/org/apache/etch/interoptester/
    incubator/etch/trunk/interoptester/example/src/main/java/org/apache/etch/interoptester/example/
    incubator/etch/trunk/interoptester/example/src/main/java/org/apache/etch/interoptester/example/iot/
    incubator/etch/trunk/interoptester/example/src/main/java/org/apache/etch/interoptester/example/iot/ImplIOTClient.java   (with props)
    incubator/etch/trunk/interoptester/example/src/main/java/org/apache/etch/interoptester/example/iot/ImplIOTServer.java   (with props)
    incubator/etch/trunk/interoptester/example/src/main/java/org/apache/etch/interoptester/example/iot/MainIOTClient.java   (with props)
    incubator/etch/trunk/interoptester/example/src/main/java/org/apache/etch/interoptester/example/iot/MainIOTListener.java   (with props)
    incubator/etch/trunk/interoptester/src/
    incubator/etch/trunk/interoptester/src/main/
    incubator/etch/trunk/interoptester/src/main/java/
    incubator/etch/trunk/interoptester/src/main/java/org/
    incubator/etch/trunk/interoptester/src/main/java/org/apache/
    incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/
    incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/
    incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Arg.java   (with props)
    incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/ChildWalker.java   (with props)
    incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/DefaultRunningProg.java   (with props)
    incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Env.java   (with props)
    incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/InteropTest.java   (with props)
    incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/InteropTestIntf.java   (with props)
    incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/MainInteropTester.java
    incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Param.java   (with props)
    incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Prog.java   (with props)
    incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Program.java   (with props)
    incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Run.java   (with props)
    incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/RunningProg.java   (with props)
    incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Substitutor.java   (with props)
    incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Test.java   (with props)
    incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/TestIntf.java   (with props)
    incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Token.java   (with props)
    incubator/etch/trunk/interoptester/src/test/
    incubator/etch/trunk/interoptester/src/test/java/
    incubator/etch/trunk/interoptester/src/test/java/org/
    incubator/etch/trunk/interoptester/src/test/java/org/apache/
    incubator/etch/trunk/interoptester/src/test/java/org/apache/etch/
    incubator/etch/trunk/interoptester/src/test/java/org/apache/etch/interoptester/
    incubator/etch/trunk/interoptester/src/test/java/org/apache/etch/interoptester/TestArg.java   (with props)
    incubator/etch/trunk/interoptester/src/test/java/org/apache/etch/interoptester/TestEnv.java   (with props)
    incubator/etch/trunk/interoptester/src/test/java/org/apache/etch/interoptester/TestParam.java   (with props)
    incubator/etch/trunk/interoptester/src/test/java/org/apache/etch/interoptester/TestProg.java   (with props)
    incubator/etch/trunk/interoptester/src/test/java/org/apache/etch/interoptester/TestRun.java   (with props)
    incubator/etch/trunk/interoptester/src/test/java/org/apache/etch/interoptester/TestSubstitutor.java   (with props)
    incubator/etch/trunk/interoptester/src/test/java/org/apache/etch/interoptester/TestTest.java   (with props)
    incubator/etch/trunk/interoptester/src/test/java/org/apache/etch/interoptester/TestToken.java   (with props)
Modified:
    incubator/etch/trunk/.classpath

Modified: incubator/etch/trunk/.classpath
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/.classpath?rev=740897&r1=740896&r2=740897&view=diff
==============================================================================
--- incubator/etch/trunk/.classpath (original)
+++ incubator/etch/trunk/.classpath Wed Feb  4 21:29:06 2009
@@ -39,6 +39,8 @@
 	<classpathentry kind="src" path="binding-c/compiler/src/main/resources"/>
 	<classpathentry kind="src" path="binding-python/compiler/src/main/java"/>
 	<classpathentry kind="src" path="binding-python/compiler/src/main/resources"/>
+	<classpathentry kind="src" path="interoptester/src/main/java"/>
+	<classpathentry kind="src" path="interoptester/src/test/java"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/ETCH_DEPENDENT_JARS"/>
 	<classpathentry kind="output" path="bin"/>

Propchange: incubator/etch/trunk/interoptester/example/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Wed Feb  4 21:29:06 2009
@@ -0,0 +1 @@
+target

Added: incubator/etch/trunk/interoptester/example/src/main/etch/IOT.etch
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/interoptester/example/src/main/etch/IOT.etch?rev=740897&view=auto
==============================================================================
--- incubator/etch/trunk/interoptester/example/src/main/etch/IOT.etch (added)
+++ incubator/etch/trunk/interoptester/example/src/main/etch/IOT.etch Wed Feb  4 21:29:06 2009
@@ -0,0 +1,13 @@
+module org.apache.etch.interoptester.example.iot
+
+/** Simple example for the interoptester. */
+service IOT
+{
+	/**
+	 * Adds two numbers.
+	 * @param x the first number to add.
+	 * @param y the second number to add.
+	 * @return the sum of x and y.
+	 */
+	int add( int x, int y )
+}

Propchange: incubator/etch/trunk/interoptester/example/src/main/etch/IOT.etch
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/etch/trunk/interoptester/example/src/main/etch/IOT.etch
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: incubator/etch/trunk/interoptester/example/src/main/java/org/apache/etch/interoptester/example/iot/ImplIOTClient.java
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/interoptester/example/src/main/java/org/apache/etch/interoptester/example/iot/ImplIOTClient.java?rev=740897&view=auto
==============================================================================
--- incubator/etch/trunk/interoptester/example/src/main/java/org/apache/etch/interoptester/example/iot/ImplIOTClient.java (added)
+++ incubator/etch/trunk/interoptester/example/src/main/java/org/apache/etch/interoptester/example/iot/ImplIOTClient.java Wed Feb  4 21:29:06 2009
@@ -0,0 +1,49 @@
+/* $Id$
+ *
+ * Copyright 2009 Cisco Systems Inc.
+ *
+ * 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.apache.etch.interoptester.example.iot;
+
+import org.apache.etch.interoptester.example.iot.BaseIOTClient;
+import org.apache.etch.interoptester.example.iot.RemoteIOTServer;
+
+/**
+ * Your custom implementation of BaseIOTClient. Add methods here to provide
+ * implementations of messages from the server.
+ */
+public class ImplIOTClient extends BaseIOTClient
+{
+	/**
+	 * Constructs the ImplIOTClient.
+	 *
+	 * @param server a connection to the server session. Use this to send a
+	 * message to the server.
+	 */
+	public ImplIOTClient( RemoteIOTServer server )
+	{
+		this.server = server;
+	}
+	
+	/**
+	 * A connection to the server session. Use this to send a
+	 * message to the server.
+	 */
+	@SuppressWarnings( "unused" )
+	private final RemoteIOTServer server;
+
+	// TODO insert methods here to provide implementations of IOTClient
+	// messages from the server.
+}
\ No newline at end of file

Propchange: incubator/etch/trunk/interoptester/example/src/main/java/org/apache/etch/interoptester/example/iot/ImplIOTClient.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/etch/trunk/interoptester/example/src/main/java/org/apache/etch/interoptester/example/iot/ImplIOTClient.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: incubator/etch/trunk/interoptester/example/src/main/java/org/apache/etch/interoptester/example/iot/ImplIOTServer.java
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/interoptester/example/src/main/java/org/apache/etch/interoptester/example/iot/ImplIOTServer.java?rev=740897&view=auto
==============================================================================
--- incubator/etch/trunk/interoptester/example/src/main/java/org/apache/etch/interoptester/example/iot/ImplIOTServer.java (added)
+++ incubator/etch/trunk/interoptester/example/src/main/java/org/apache/etch/interoptester/example/iot/ImplIOTServer.java Wed Feb  4 21:29:06 2009
@@ -0,0 +1,62 @@
+/* $Id$
+ *
+ * Copyright 2009 Cisco Systems Inc.
+ *
+ * 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.apache.etch.interoptester.example.iot;
+
+import org.apache.etch.interoptester.example.iot.BaseIOTServer;
+import org.apache.etch.interoptester.example.iot.RemoteIOTClient;
+
+/**
+ * Your custom implementation of BaseIOTServer. Add methods here to provide
+ * implementations of messages from the client.
+ */
+public class ImplIOTServer extends BaseIOTServer
+{
+	/**
+	 * Constructs the ImplIOTServer.
+	 *
+	 * @param client a connection to the client session. Use this to send a
+	 * message to the client.
+	 */
+	public ImplIOTServer( RemoteIOTClient client )
+	{
+		this.client = client;
+	}
+	
+	/**
+	 * A connection to the client session. Use this to send a
+	 * message to the client.
+	 */
+	@SuppressWarnings( "unused" )
+	private final RemoteIOTClient client;
+
+	@Override
+	public Integer add( Integer x, Integer y )
+	{
+		if (x == null)
+			throw new IllegalArgumentException( "x == null" );
+		if (y == null)
+			throw new IllegalArgumentException( "y == null" );
+		return x + y;
+	}
+	
+	@Override
+	public void _sessionNotify( Object event ) throws Exception
+	{
+		// ignore events.
+	}
+}
\ No newline at end of file

Propchange: incubator/etch/trunk/interoptester/example/src/main/java/org/apache/etch/interoptester/example/iot/ImplIOTServer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/etch/trunk/interoptester/example/src/main/java/org/apache/etch/interoptester/example/iot/ImplIOTServer.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: incubator/etch/trunk/interoptester/example/src/main/java/org/apache/etch/interoptester/example/iot/MainIOTClient.java
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/interoptester/example/src/main/java/org/apache/etch/interoptester/example/iot/MainIOTClient.java?rev=740897&view=auto
==============================================================================
--- incubator/etch/trunk/interoptester/example/src/main/java/org/apache/etch/interoptester/example/iot/MainIOTClient.java (added)
+++ incubator/etch/trunk/interoptester/example/src/main/java/org/apache/etch/interoptester/example/iot/MainIOTClient.java Wed Feb  4 21:29:06 2009
@@ -0,0 +1,183 @@
+/* $Id$
+ *
+ * Copyright 2009 Cisco Systems Inc.
+ *
+ * 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.apache.etch.interoptester.example.iot;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.etch.bindings.java.support._Etch_RuntimeException;
+import org.apache.etch.interoptester.example.iot.IOTClient;
+import org.apache.etch.interoptester.example.iot.IOTHelper;
+import org.apache.etch.interoptester.example.iot.RemoteIOTServer;
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunListener;
+
+
+/**
+ * Main program for IOTClient. This program makes a connection to the
+ * listener created by MainIOTListener.
+ */
+public class MainIOTClient implements IOTHelper.IOTClientFactory
+{
+	/**
+	 * Main program for IOTClient.
+	 * 
+	 * @param args command line arguments.
+	 * @throws Exception
+	 */
+	public static void main( String[] args ) throws Exception
+	{
+		System.out.println( "MainIOTClient: starting" );
+		
+		if (args.length > 1)
+		{
+			System.err.println( "usage: MainIOTClient [uri]" );
+			System.exit( 1 );
+		}
+		
+		if (args.length > 0)
+			uri = args[0];
+		
+		RemoteIOTServer server = IOTHelper.newServer( uri, null,
+			new MainIOTClient() );
+
+		// Connect to the service
+		server._startAndWaitUp( 4000 );
+
+		assertEquals( (Object) 11, server.add( 5, 6 ) );
+
+		// Disconnect from the service
+		server._stopAndWaitDown( 4000 );
+		server = null;
+		
+		JUnitCore c = new org.junit.runner.JUnitCore();
+		
+		c.addListener( new RunListener()
+		{
+			@Override
+			public void testRunStarted( Description description )
+				throws Exception
+			{
+				System.out.println( "testRunStarted "+description );
+			}
+			
+			@Override
+			public void testStarted( Description description ) throws Exception
+			{
+				System.out.print( "test "+description );
+			}
+			
+			@Override
+			public void testFailure( Failure failure ) throws Exception
+			{
+				System.out.println( "[failed:  "+failure+"]" );
+			}
+			
+			@Override
+			public void testIgnored( Description description ) throws Exception
+			{
+				System.out.println( " [ignored]" );
+			}
+			
+			@Override
+			public void testFinished( Description description )
+				throws Exception
+			{
+				System.out.println( " [ok]" );
+			}
+			
+			@Override
+			public void testRunFinished( Result result ) throws Exception
+			{
+				System.out.println( "testRunFinished" );
+			}
+		} );
+		
+		Result r = c.run( MainIOTClient.class );
+		
+		if (!r.wasSuccessful())
+		{
+			System.err.printf( "MainIOTClient: tests failed (%d/%d/%d)",
+				r.getRunCount(), r.getIgnoreCount(), r.getFailureCount() );
+			System.err.println();
+			System.exit( 1 );
+		}
+		
+		System.out.printf( "MainIOTClient: tests succeeeded (%d/%d)",
+			r.getRunCount(), r.getIgnoreCount() );
+		System.out.println();
+		System.exit( 0 );
+	}
+	
+	private static String uri = "tcp://127.0.0.1:4001";
+	
+	/** @throws Exception */
+	@org.junit.Before
+	public void before() throws Exception
+	{
+		server = IOTHelper.newServer( uri, null, this );
+		server._startAndWaitUp( 4000 );
+	}
+	
+	private RemoteIOTServer server;
+	
+	/** @throws Exception */
+	@org.junit.After
+	public void after() throws Exception
+	{
+		server._stopAndWaitDown( 4000 );
+		server = null;
+	}
+
+	public IOTClient newIOTClient( RemoteIOTServer server )
+		throws Exception
+	{
+		return new ImplIOTClient( server );
+	}
+	
+	/** @throws Exception */
+	@Test( expected = _Etch_RuntimeException.class )
+	public void add_null_null() throws Exception
+	{
+		server.add( null, null );
+	}
+	
+	/** @throws Exception */
+	@Test( expected = _Etch_RuntimeException.class )
+	public void add_null_2() throws Exception
+	{
+		server.add( null, 2 );
+	}
+	
+	/** @throws Exception */
+	@Test( expected = _Etch_RuntimeException.class )
+	public void add_1_null() throws Exception
+	{
+		server.add( 1, null );
+	}
+	
+	/** @throws Exception */
+	@Test
+	public void add_1_2() throws Exception
+	{
+		assertEquals( 3, server.add( 1, 2 ) );
+	}
+}

Propchange: incubator/etch/trunk/interoptester/example/src/main/java/org/apache/etch/interoptester/example/iot/MainIOTClient.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/etch/trunk/interoptester/example/src/main/java/org/apache/etch/interoptester/example/iot/MainIOTClient.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: incubator/etch/trunk/interoptester/example/src/main/java/org/apache/etch/interoptester/example/iot/MainIOTListener.java
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/interoptester/example/src/main/java/org/apache/etch/interoptester/example/iot/MainIOTListener.java?rev=740897&view=auto
==============================================================================
--- incubator/etch/trunk/interoptester/example/src/main/java/org/apache/etch/interoptester/example/iot/MainIOTListener.java (added)
+++ incubator/etch/trunk/interoptester/example/src/main/java/org/apache/etch/interoptester/example/iot/MainIOTListener.java Wed Feb  4 21:29:06 2009
@@ -0,0 +1,63 @@
+/* $Id$
+ *
+ * Copyright 2009 Cisco Systems Inc.
+ *
+ * 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.apache.etch.interoptester.example.iot;
+
+
+import org.apache.etch.bindings.java.support.ServerFactory;
+import org.apache.etch.interoptester.example.iot.IOTHelper;
+import org.apache.etch.interoptester.example.iot.IOTServer;
+import org.apache.etch.interoptester.example.iot.RemoteIOTClient;
+import org.apache.etch.util.core.io.Transport;
+
+
+/**
+ * Main program for IOTServer. This program makes a listener to accept
+ * connections from MainIOTClient.
+ */
+public class MainIOTListener implements IOTHelper.IOTServerFactory
+{
+	/**
+	 * Main program for IOTServer.
+	 * 
+	 * @param args command line arguments.
+	 * @throws Exception
+	 */
+	public static void main( String[] args ) throws Exception
+	{
+		if (args.length > 1)
+		{
+			System.err.println( "usage: MainIOTClient [uri]" );
+			System.exit( 1 );
+		}
+		
+		String uri = args.length > 0 ? args[0] : "tcp://127.0.0.1:4001";
+		
+		Transport<ServerFactory> listener = IOTHelper.newListener( uri, null,
+			new MainIOTListener() );
+
+		// Start the Listener
+		listener.transportControl( Transport.START_AND_WAIT_UP, 4000 );
+		
+		System.out.println( "listener started: "+listener );
+	}
+
+	public IOTServer newIOTServer( RemoteIOTClient client )
+	{
+		return new ImplIOTServer( client );
+	}
+}

Propchange: incubator/etch/trunk/interoptester/example/src/main/java/org/apache/etch/interoptester/example/iot/MainIOTListener.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/etch/trunk/interoptester/example/src/main/java/org/apache/etch/interoptester/example/iot/MainIOTListener.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Arg.java
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Arg.java?rev=740897&view=auto
==============================================================================
--- incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Arg.java (added)
+++ incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Arg.java Wed Feb  4 21:29:06 2009
@@ -0,0 +1,110 @@
+/* $Id$
+ *
+ * Copyright 2009 Cisco Systems Inc.
+ *
+ * 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.apache.etch.interoptester;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.etch.util.Assertion;
+import org.apache.etch.util.core.xml.XmlParser.TagElement;
+
+
+/**
+ * Arg models an named value passed to a procedure (which is used to initialize
+ * a Param once received).
+ */
+public class Arg
+{
+	/**
+	 * @param r
+	 * @return the Arg that was parsed.
+	 */
+	public static Arg parse( TagElement r )
+	{
+		Assertion.check( r.matches( null, "arg" ), "tag is arg" );
+		
+		String name = r.getAttr( null, "name" );
+		if (name == null || name.length() == 0)
+			throw new IllegalArgumentException( "arg tag has no name" );
+		
+		String value = r.getAttr( null, "value" );
+		if (value == null && r.countChildren() > 0)
+			value = r.getCdataValue();
+		
+		if (value == null)
+			throw new IllegalArgumentException( "arg '"+name+"' has no value" );
+		
+		return new Arg( name, value );
+	}
+
+	private Arg( String name, String value )
+	{
+		this.name = name;
+		this.value = value;
+	}
+	
+	private final String name;
+	
+	private final String value;
+
+	/**
+	 * @return the name of this arg.
+	 */
+	public String name()
+	{
+		return name;
+	}
+	
+	/**
+	 * @param args named values which might be used as substitutions.
+	 * @return the value of this arg. This might involve substituting named
+	 * values from args.
+	 */
+	public String value( Map<String, String> args )
+	{
+		if (value == null)
+			return null;
+		
+		return Substitutor.subst( value, args );
+	}
+	
+	@Override
+	public String toString()
+	{
+		return String.format( "Arg( %s, %s )", name, value );
+	}
+
+	/**
+	 * @param who
+	 * @param args
+	 * @param substs
+	 * @return the map formed by processing substitutions from substs into each
+	 * value from args.
+	 */
+	public static Map<String, String> processSubst( String who,
+		Map<String, Arg> args, Map<String, String> substs )
+	{
+		Map<String, String> nargs = new HashMap<String, String>();
+		for (Arg a: args.values())
+		{
+			String v = a.value( substs );
+			nargs.put( a.name(), v );
+		}
+		return nargs;
+	}
+}
\ No newline at end of file

Propchange: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Arg.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Arg.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/ChildWalker.java
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/ChildWalker.java?rev=740897&view=auto
==============================================================================
--- incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/ChildWalker.java (added)
+++ incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/ChildWalker.java Wed Feb  4 21:29:06 2009
@@ -0,0 +1,76 @@
+/* $Id$
+ *
+ * Copyright 2009 Cisco Systems Inc.
+ *
+ * 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.apache.etch.interoptester;
+
+import java.util.Iterator;
+
+import org.apache.etch.util.core.xml.XmlParser.CdataElement;
+import org.apache.etch.util.core.xml.XmlParser.Element;
+import org.apache.etch.util.core.xml.XmlParser.TagElement;
+
+
+/**
+ * ChildWalker calls a method with each child element under a given tag
+ * element.
+ */
+abstract public class ChildWalker
+{
+	/**
+	 * Iterates over the children of r and calls tag or cdata for each.
+	 * @param r
+	 */
+	public void walk( TagElement r )
+	{
+		for (Iterator<Element> i = r.getChildren(); i.hasNext();)
+		{
+			Element e = i.next();
+			if (!(e instanceof TagElement))
+			{
+				if (!cdata( (CdataElement) e ))
+					throw new IllegalArgumentException(
+						"tag "+r.getQName()+": cdata not allowed here: '"+e+"'" );
+				
+				continue;
+			}
+			
+			TagElement te = (TagElement) e;
+			if (!tag( te ))
+				throw new IllegalArgumentException(
+					"tag "+r.getQName()+": tag "+te.getQName()+" not allowed here" );
+		}
+	}
+
+	/**
+	 * @param te
+	 * @return if tag is allowed.
+	 */
+	public boolean tag( TagElement te )
+	{
+		return false;
+	}
+	
+	/**
+	 * @param e
+	 * @return true if cdata is allowed.
+	 */
+	public boolean cdata( CdataElement e )
+	{
+		String s = e.getCdata();
+		return s.trim().length() == 0;
+	}
+}
\ No newline at end of file

Propchange: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/ChildWalker.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/ChildWalker.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/DefaultRunningProg.java
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/DefaultRunningProg.java?rev=740897&view=auto
==============================================================================
--- incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/DefaultRunningProg.java (added)
+++ incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/DefaultRunningProg.java Wed Feb  4 21:29:06 2009
@@ -0,0 +1,162 @@
+/* $Id$
+ *
+ * Copyright 2009 Cisco Systems Inc.
+ *
+ * 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.apache.etch.interoptester;
+
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.etch.interoptester.Program.ProcessStreamReader;
+
+/**
+ * Default implementation of {@link RunningProg}.
+ */
+public class DefaultRunningProg implements RunningProg
+{
+	/**
+	 * @param tkns
+	 * @param nvs
+	 * @param stdoutTag
+	 * @param stderrTag
+	 */
+	public DefaultRunningProg( List<String> tkns, Map<String, String> nvs,
+		String stdoutTag, String stderrTag )
+	{
+		this.tkns = tkns;
+		this.nvs = nvs;
+		this.stdoutTag = stdoutTag;
+		this.stderrTag = stderrTag;
+	}
+
+	private final List<String> tkns;
+
+	private final Map<String, String> nvs;
+
+	private final String stdoutTag;
+
+	private final String stderrTag;
+
+	private ProcessBuilder pb;
+
+	private Process p;
+
+	private ProcessStreamReader outrdr;
+
+	private ProcessStreamReader errrdr;
+
+	private Integer sts;
+
+	@Override
+	public String toString()
+	{
+		return "DefaultRunningProg@" + Integer.toHexString( hashCode() );
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public void start() throws Exception
+	{
+		pb = new ProcessBuilder( tkns );
+		pb.environment().putAll( nvs );
+		
+		h = new Thread( new Runnable()
+		{
+			public void run()
+			{
+				try
+				{
+					stop();
+				}
+				catch ( InterruptedException e )
+				{
+					// ignore
+				}
+			}
+		} );
+		
+		Runtime.getRuntime().addShutdownHook( h );
+
+		report( "start, tokens = " + tkns + ", nvs = " + nvs );
+
+		p = pb.start();
+
+		report( "started" );
+
+		p.getOutputStream().close();
+
+		outrdr = new ProcessStreamReader( p.getInputStream(), System.out,
+			stdoutTag );
+		outrdr.start();
+
+		errrdr = new ProcessStreamReader( p.getErrorStream(), System.out,
+			stderrTag );
+		errrdr.start();
+	}
+	
+	private Thread h;
+
+	public Integer join() throws InterruptedException
+	{
+		if (p != null)
+		{
+			report( "join" );
+
+			sts = p.waitFor();
+			p = null;
+			
+			try
+			{
+				Runtime.getRuntime().removeShutdownHook( h );
+			}
+			catch ( IllegalStateException e )
+			{
+				// ignore
+			}
+			h = null;
+
+			report( "join, sts = " + sts );
+
+			if (outrdr != null)
+				outrdr.join();
+
+			if (errrdr != null)
+				errrdr.join();
+
+			return sts;
+		}
+
+		report( "join: no program" );
+		return null;
+	}
+
+	public Integer stop() throws InterruptedException
+	{
+		report( "stop" );
+
+		if (p != null)
+			p.destroy();
+
+		return join();
+	}
+
+	private void report( String msg )
+	{
+		System.out.println( this.toString() + ": " + msg );
+	}
+}

Propchange: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/DefaultRunningProg.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/DefaultRunningProg.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Env.java
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Env.java?rev=740897&view=auto
==============================================================================
--- incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Env.java (added)
+++ incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Env.java Wed Feb  4 21:29:06 2009
@@ -0,0 +1,80 @@
+/* $Id$
+ *
+ * Copyright 2009 Cisco Systems Inc.
+ *
+ * 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.apache.etch.interoptester;
+
+import java.util.Map;
+
+import org.apache.etch.util.Assertion;
+import org.apache.etch.util.core.xml.XmlParser.TagElement;
+
+
+/**
+ * Env models a contribution to the environment of a running program.
+ */
+public class Env
+{
+	/**
+	 * @param r
+	 * @return the Env that was parsed.
+	 */
+	public static Env parse( TagElement r )
+	{
+		Assertion.check( r.matches( null, "env" ), "tag is env" );
+		
+		String name = r.getAttr( null, "name" );
+		if (name == null || name.length() == 0)
+			throw new IllegalArgumentException( "env tag has no name" );
+		
+		String value = r.getAttr( null, "value" );
+		if (value == null && r.hasChildren())
+			value = r.getCdataValue();
+		
+		return new Env( name, value );
+	}
+	
+	private Env( String name, String value )
+	{
+		this.name = name;
+		this.value = value;
+	}
+	
+	private final String name;
+
+	/**
+	 * @return the name of this environment variable.
+	 */
+	public String name()
+	{
+		return name;
+	}
+	
+	private final String value;
+	
+	/**
+	 * @param args named values which might be used as substitutions.
+	 * @return the value of this env. This might involve substituting named
+	 * values from args.
+	 */
+	public String value( Map<String, String> args )
+	{
+		if (value == null)
+			return null;
+		
+		return Substitutor.subst( value, args );
+	}
+}

Propchange: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Env.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Env.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/InteropTest.java
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/InteropTest.java?rev=740897&view=auto
==============================================================================
--- incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/InteropTest.java (added)
+++ incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/InteropTest.java Wed Feb  4 21:29:06 2009
@@ -0,0 +1,194 @@
+/* $Id$
+ *
+ * Copyright 2009 Cisco Systems Inc.
+ *
+ * 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.apache.etch.interoptester;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.etch.util.core.xml.XmlParser.TagElement;
+
+
+/** */
+public class InteropTest implements InteropTestIntf
+{
+	static InteropTestIntf parse( TagElement r )
+	{
+		if (!r.matches( null, "interoptest" ))
+			return null;
+		
+		InteropTest it = new InteropTest();
+		it.parseBody( r );
+		return it;
+	}
+	
+	/**
+	 * @param r
+	 */
+	public void parseBody( TagElement r )
+	{
+		new ChildWalker()
+		{
+			public boolean tag( TagElement te )
+			{
+				if (te.matches( null, "params" ))
+				{
+					parseParams( te );
+					return true;
+				}
+				
+				if (te.matches( null, "programs" ))
+				{
+					parsePrograms( te );
+					return true;
+				}
+				
+				if (te.matches( null, "tests" ))
+				{
+					parseTests( te );
+					return true;
+				}
+				
+				if (te.matches( null, "run" ))
+				{
+					parseRun( te );
+					return true;
+				}
+				
+				return false;
+			}
+		}.walk( r );
+	}
+	
+	private void parseParams( TagElement r )
+	{
+		new ChildWalker()
+		{
+			public boolean tag( TagElement te )
+			{
+				if (te.matches( null, "param" ))
+				{
+					parseParam( te );
+					return true;
+				}
+				
+				return false;
+			}
+		}.walk( r );
+	}
+	
+	private void parsePrograms( TagElement r )
+	{
+		new ChildWalker()
+		{
+			public boolean tag( TagElement te )
+			{
+				if (te.matches( null, "program" ))
+				{
+					parseProgram( te );
+					return true;
+				}
+				
+				return false;
+			}
+		}.walk( r );
+	}
+
+	private void parseTests( TagElement r )
+	{
+		new ChildWalker()
+		{
+			public boolean tag( TagElement te )
+			{
+				if (te.matches( null, "test" ))
+				{
+					parseTest( te );
+					return true;
+				}
+				
+				return false;
+			}
+		}.walk( r );
+	}
+	
+	private void parseParam( TagElement r )
+	{
+		Param p = Param.parse( r );
+		params.put( p.name(), p );
+	}
+	
+	private final Map<String, Param> params = new HashMap<String, Param>();
+
+	private void parseProgram( TagElement r )
+	{
+		Program p = Program.parse( this, r );
+		programs.put( p.name(), p );
+	}
+	
+	private final Map<String, Program> programs = new HashMap<String, Program>();
+
+	private void parseTest( TagElement r )
+	{
+		Test t = Test.parse( this, r );
+		tests.put( t.name(), t );
+	}
+	
+	final Map<String, Test> tests = new HashMap<String, Test>();
+
+	private void parseRun( TagElement r )
+	{
+		runs.add( Run.parse( this, r ) );
+	}
+	
+	private final List<Run> runs = new ArrayList<Run>();
+
+	public void run( Map<String, String> overrides ) throws Exception
+	{
+		System.out.println( "InteropTest.run: overrides = "+overrides );
+		
+		// construct substs out of params + overrides
+		
+		Map<String, String> substs = Param.processOverrides( "interoptest",
+			params, overrides );
+		
+		System.out.println( "InteropTest.run: substs = "+substs );
+		
+		// run each "run" defined in interoptest
+		
+		for (Run r: runs)
+			r.run( substs );
+	}
+
+	public TestIntf getTest( String test )
+	{
+		return tests.get( test );
+	}
+
+	public Program getProgram( String name )
+	{
+		return programs.get( name );
+	}
+
+	public int nextRunId()
+	{
+		return ++runId;
+	}
+	
+	private int runId;
+}
\ No newline at end of file

Propchange: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/InteropTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/InteropTest.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/InteropTestIntf.java
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/InteropTestIntf.java?rev=740897&view=auto
==============================================================================
--- incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/InteropTestIntf.java (added)
+++ incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/InteropTestIntf.java Wed Feb  4 21:29:06 2009
@@ -0,0 +1,52 @@
+/* $Id$
+ *
+ * Copyright 2009 Cisco Systems Inc.
+ *
+ * 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.apache.etch.interoptester;
+
+import java.util.Map;
+
+/**
+ * Interface to a suite of tests to be run.
+ */
+public interface InteropTestIntf
+{
+	/**
+	 * @param test the name of the test to get.
+	 * @return the interface to the test.
+	 */
+	public TestIntf getTest( String test );
+
+	/**
+	 * @param name
+	 * @return the named Program.
+	 */
+	public Program getProgram( String name );
+	
+	/**
+	 * Runs all the tests in the suite.
+	 * 
+	 * @param overrides replacement values for interoptest params. any params
+	 * which have no default must be specified.
+	 * @throws Exception 
+	 */
+	public void run( Map<String, String> overrides ) throws Exception;
+
+	/**
+	 * @return the next id of a run in this interoptest.
+	 */
+	public int nextRunId();
+}

Propchange: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/InteropTestIntf.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/InteropTestIntf.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/MainInteropTester.java
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/MainInteropTester.java?rev=740897&view=auto
==============================================================================
--- incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/MainInteropTester.java (added)
+++ incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/MainInteropTester.java Wed Feb  4 21:29:06 2009
@@ -0,0 +1,91 @@
+/* $Id: InteropTester.java 2575 2009-01-29 16:53:50Z sccomer $
+ *
+ * Copyright 2009 Cisco Systems Inc.
+ *
+ * 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.apache.etch.interoptester;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.etch.util.ArrayIterator;
+import org.apache.etch.util.StringUtil;
+import org.apache.etch.util.cmd.StringArrayIterator;
+import org.apache.etch.util.core.xml.XmlParser;
+import org.apache.etch.util.core.xml.XmlParser.TagElement;
+
+
+/** */
+@SuppressWarnings( "all" )
+public class MainInteropTester
+{
+	/**
+	 * @param args
+	 * @throws Exception
+	 */
+	public static void main( String[] args ) throws Exception
+	{
+		if (args.length < 1)
+		{
+			System.err.println( "usage: InteropTester file [name=value ...]" );
+			System.exit( 1 );
+		}
+
+		StringArrayIterator i = new StringArrayIterator( args );
+
+		TagElement te = new XmlParser().parseOne( new File( i.next() ), null,
+			"interoptest" );
+		// System.out.println( te );
+		InteropTestIntf itest = InteropTest.parse( te );
+		te = null;
+
+		Map<String, String> overrides = new HashMap<String, String>();
+		while (i.hasNext())
+		{
+			String s = i.next();
+			String[] x = StringUtil.leftSplit( s, '=' );
+			if (x == null)
+				throw new IllegalArgumentException(
+					"malformed 'name=value' token on command line" );
+			overrides.put( x[0], x[1] );
+		}
+
+		System.out.println( "main: overrides = " + overrides );
+
+		new Thread( new Runnable()
+		{
+			public void run()
+			{
+				try
+				{
+					int c = System.in.read();
+					if (c == 'q')
+						System.exit( 1 );
+				}
+				catch ( IOException e )
+				{
+					// ignore
+				}
+			}
+		} ).start();
+
+		itest.run( overrides );
+
+		System.out.println( "main: done" );
+		System.exit( 0 );
+	}
+}

Added: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Param.java
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Param.java?rev=740897&view=auto
==============================================================================
--- incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Param.java (added)
+++ incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Param.java Wed Feb  4 21:29:06 2009
@@ -0,0 +1,124 @@
+/* $Id$
+ *
+ * Copyright 2009 Cisco Systems Inc.
+ *
+ * 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.apache.etch.interoptester;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.etch.util.Assertion;
+import org.apache.etch.util.core.xml.XmlParser.TagElement;
+
+
+/**
+ * Param models a named value initialized from args supplied to a function and
+ * perhaps given a default value. A Param may be used when calling another
+ * function by substitution into an Arg or Token.
+ */
+public class Param
+{
+	/**
+	 * @param r
+	 * @return the parsed Param.
+	 */
+	public static Param parse( TagElement r )
+	{
+		Assertion.check( r.matches( null, "param" ), "tag is param" );
+		
+		String name = r.getAttr( null, "name" );
+		if (name == null || name.length() == 0)
+			throw new IllegalArgumentException( "param tag has no name attribute" );
+		
+		Param p = new Param( name );
+		p.parseBody( r );
+		return p;
+	}
+
+	private Param( String name )
+	{
+		this.name = name;
+	}
+
+	private final String name;
+
+	/**
+	 * @return the name of this param.
+	 */
+	public String name()
+	{
+		return name;
+	}
+
+	private void parseBody( TagElement r )
+	{
+		deflt = r.getAttr( null, "default" );
+		if (deflt == null && r.countChildren() > 0)
+			deflt = r.getCdataValue();
+	}
+	
+	private String deflt;
+
+	/**
+	 * @param args
+	 * @return the value of the named param in args, or the default value if not
+	 * in args.
+	 */
+	public String value( Map<String, String> args )
+	{
+		String v = args.get( name );
+		if (v != null)
+			return v;
+		return deflt;
+	}
+	
+	@Override
+	public String toString()
+	{
+		return String.format( "Param( %s, %s )", name, deflt );
+	}
+
+	/**
+	 * @param who the tag name of the owner of params.
+	 * @param params a map of params (from param tags).
+	 * @param overrides name / value pairs which override default param values.
+	 * @return a map of name / value pairs which are the param values after
+	 * overrides have been applied.
+	 */
+	public static Map<String, String> processOverrides( String who,
+		Map<String, Param> params, Map<String, String> overrides )
+	{
+		// ensure names in overrides appear in params
+		
+		for (String name: overrides.keySet())
+			if (!params.containsKey( name ))
+				throw new IllegalArgumentException(
+					who+" param '"+name+"' is not defined, cannot override" );
+		
+		// construct args out of params + overrides
+		
+		Map<String, String> args = new HashMap<String, String>();
+		for (Param p : params.values())
+		{
+			String v = p.value( overrides );
+			if (v == null)
+				throw new IllegalArgumentException(
+					who+" param '"+p.name()+"' has no value, must override" );
+			args.put( p.name(), v );
+		}
+		return args;
+	}
+}
\ No newline at end of file

Propchange: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Param.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Param.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Prog.java
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Prog.java?rev=740897&view=auto
==============================================================================
--- incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Prog.java (added)
+++ incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Prog.java Wed Feb  4 21:29:06 2009
@@ -0,0 +1,147 @@
+/* $Id$
+ *
+ * Copyright 2009 Cisco Systems Inc.
+ *
+ * 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.apache.etch.interoptester;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.etch.util.Assertion;
+import org.apache.etch.util.core.xml.XmlParser.TagElement;
+
+
+/**
+ * Prog models a reference to a Program in a Test.
+ */
+public class Prog
+	{
+		/**
+		 * @param test
+		 * @param r
+		 * @return the parsed Prog.
+		 */
+		public static Prog parse( TestIntf test, TagElement r )
+		{
+			Assertion.check( r.matches( null, "prog" ), "tag is prog" );
+			
+			String name = r.getAttr( null, "name" );
+			if (name == null || name.length() == 0)
+				throw new IllegalArgumentException( "prog tag has no name attribute" );
+			
+			Prog p = new Prog( test, name );
+			p.parseBody( r );
+			return p;
+		}
+		
+		private Prog( TestIntf test, String name )
+		{
+			this.test = test;
+			this.name = name;
+		}
+
+		private final TestIntf test;
+		
+		private final String name;
+
+		/**
+		 * @return the enclosing Test
+		 */
+		public TestIntf test()
+		{
+			return test;
+		}
+
+		/**
+		 * @return the name of the Program to run.
+		 */
+		public String name()
+		{
+			return name;
+		}
+		
+		private void parseBody( TagElement r )
+		{
+			new ChildWalker()
+			{
+				public boolean tag( TagElement te )
+				{
+					if (te.matches( null, "arg" ))
+					{
+						Arg a = Arg.parse( te );
+						if (args.containsKey( a.name() ))
+							throw new IllegalArgumentException( "duplicate name arg "+a.name() );
+						args.put( a.name(), a );
+						return true;
+					}
+					
+					return false;
+				}
+			}.walk( r );
+		}
+		
+		private final Map<String, Arg> args = new HashMap<String, Arg>();
+
+		/**
+		 * @return the args to be passed to this prog.
+		 */
+		public Map<String, Arg> args()
+		{
+			return args;
+		}
+
+		/**
+		 * @param substs
+		 * @return a running instance of Prog.
+		 * @throws Exception 
+		 */
+		public RunningProg start( Map<String, String> substs ) throws Exception
+		{
+			Map<String, String> overrides = processSubst( "start", substs );
+			return getProgram().start( overrides );
+		}
+
+		/**
+		 * @param substs
+		 * @throws Exception 
+		 */
+		public void run( Map<String, String> substs ) throws Exception
+		{
+			Map<String, String> overrides = processSubst( "run", substs );
+			getProgram().run( overrides );
+		}
+
+		private Map<String, String> processSubst( String who,
+			Map<String, String> substs )
+		{
+			System.out.println( "Prog."+who+": name "+name+", substs = "+substs );
+			
+			Map<String, String> overrides = Arg.processSubst( "prog", args,
+				substs );
+			
+			System.out.println( "Prog."+who+": name "+name+", overrides = "+overrides );
+			
+			return overrides;
+		}
+
+		private Program getProgram()
+		{
+			Program p = test.getProgram( name );
+			if (p == null)
+				throw new IllegalArgumentException( "no such program "+name );
+			return p;
+		}
+	}
\ No newline at end of file

Propchange: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Prog.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Prog.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Program.java
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Program.java?rev=740897&view=auto
==============================================================================
--- incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Program.java (added)
+++ incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Program.java Wed Feb  4 21:29:06 2009
@@ -0,0 +1,427 @@
+/* $Id$
+ *
+ * Copyright 2009 Cisco Systems Inc.
+ *
+ * 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.apache.etch.interoptester;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.etch.util.Assertion;
+import org.apache.etch.util.core.xml.XmlParser.TagElement;
+
+
+/**
+ * Program models a program to be run as part of a test. The program has
+ * positional parameters, environment, stdin, stdout, stderr, and timeout.
+ */
+public class Program
+{
+	/**
+	 * @param itest
+	 * @param r
+	 * @return the parsed Program.
+	 */
+	public static Program parse( InteropTestIntf itest, TagElement r )
+	{
+		Assertion.check( r.matches( null, "program" ), "tag is program" );
+		
+		String name = r.getAttr( null, "name" );
+		if (name == null || name.length() == 0)
+			throw new IllegalArgumentException( "program tag has no name" );
+		
+		Program p = new Program( itest, name );
+		p.parseBody( r );
+		return p;
+	}
+	
+	/**
+	 * @param itest
+	 * @param name
+	 */
+	private Program( InteropTestIntf itest, String name )
+	{
+		this.itest = itest;
+		this.name = name;
+	}
+
+	private final InteropTestIntf itest;
+
+	private final String name;
+	
+	/**
+	 * @return the containing InteropTestIntf.
+	 */
+	public InteropTestIntf itest()
+	{
+		return itest;
+	}
+	
+	/**
+	 * @return the name of this Program.
+	 */
+	public String name()
+	{
+		return name;
+	}
+	
+	/**
+	 * @param r
+	 */
+	public void parseBody( TagElement r )
+	{
+		new ChildWalker()
+		{
+			public boolean tag( TagElement te )
+			{
+				if (te.matches( null, "params" ))
+				{
+					parseParams( te );
+					return true;
+				}
+				
+				if (te.matches( null, "tokens" ))
+				{
+					parseTokens( te );
+					return true;
+				}
+				
+				if (te.matches( null, "environment" ))
+				{
+					parseEnvironment( te );
+					return true;
+				}
+				
+				if (te.matches( null, "stdin" ))
+				{
+					parseStdin( te );
+					return true;
+				}
+				
+				if (te.matches( null, "stdout" ))
+				{
+					parseStdout( te );
+					return true;
+				}
+				
+				if (te.matches( null, "stderr" ))
+				{
+					parseStderr( te );
+					return true;
+				}
+				
+				if (te.matches( null, "stdouttag" ))
+				{
+					parseStdoutTag( te );
+					return true;
+				}
+				
+				if (te.matches( null, "stderrtag" ))
+				{
+					parseStderrTag( te );
+					return true;
+				}
+				
+				if (te.matches( null, "timeout" ))
+				{
+					parseTimeout( te );
+					return true;
+				}
+				
+				return false;
+			}
+		}.walk( r );
+	}
+
+	private void parseParams( TagElement r )
+	{
+		new ChildWalker()
+		{
+			public boolean tag( TagElement te )
+			{
+				if (te.matches( null, "param" ))
+				{
+					parseParam( te );
+					return true;
+				}
+
+				return false;
+			}
+		}.walk( r );
+	}
+
+	private void parseParam( TagElement te )
+	{
+		Param p = Param.parse( te );
+		params.put( p.name(), p );
+	}
+	
+	private final Map<String, Param> params = new HashMap<String, Param>();
+
+	private void parseTokens( TagElement r )
+	{
+		new ChildWalker()
+		{
+			public boolean tag( TagElement te )
+			{
+				if (te.matches( null, "token" ))
+				{
+					parseToken( te );
+					return true;
+				}
+
+				return false;
+			}
+		}.walk( r );
+	}
+
+	private void parseToken( TagElement r )
+	{
+		tokens.add( Token.parse( r ) );
+	}
+	
+	private final List<Token> tokens = new ArrayList<Token>();
+
+	private void parseEnvironment( TagElement r )
+	{
+		new ChildWalker()
+		{
+			public boolean tag( TagElement te )
+			{
+				if (te.matches( null, "env" ))
+				{
+					parseEnv( te );
+					return true;
+				}
+
+				return false;
+			}
+		}.walk( r );
+	}
+
+	private void parseEnv( TagElement r )
+	{
+		Env e = Env.parse( r );
+		envs.put( e.name(), e );
+	}
+	
+	private final Map<String, Env> envs = new HashMap<String, Env>();
+
+	private void parseStdin( TagElement r )
+	{
+		// TODO Auto-generated method stub
+		throw new UnsupportedOperationException( "parseStdin" );
+	}
+
+	private void parseStdout( TagElement r )
+	{
+		// TODO Auto-generated method stub
+		throw new UnsupportedOperationException( "parseStdout" );
+	}
+
+	private void parseStderr( TagElement r )
+	{
+		// TODO Auto-generated method stub
+		throw new UnsupportedOperationException( "parseStderr" );
+	}
+	
+	private void parseStdoutTag( TagElement r )
+	{
+		stdoutTag = r.getCdataValue();
+	}
+	
+	private String stdoutTag = "out";
+	
+	private void parseStderrTag( TagElement r )
+	{
+		stderrTag = r.getCdataValue();
+	}
+	
+	private String stderrTag = "err";
+
+	private void parseTimeout( TagElement r )
+	{
+		// TODO Auto-generated method stub
+		throw new UnsupportedOperationException( "parseTimeout" );
+	}
+
+	/**
+	 * @param overrides
+	 * @return a RunningProg which allows the running program to be controlled.
+	 * @throws Exception 
+	 */
+	public RunningProg start( Map<String, String> overrides ) throws Exception
+	{
+		Map<String, String> substs = processOverrides( "start", overrides );
+		List<String> tkns = processTokens( substs );
+		Map<String, String> nvs = processEnvs( substs );
+		System.out.printf( "Program.start: tokens %s envs %s\n", tkns, nvs );
+		DefaultRunningProg rp = new DefaultRunningProg( tkns, nvs, stdoutTag, stderrTag );
+		try
+		{
+			rp.start();
+			return rp;
+		}
+		catch ( Exception e )
+		{
+			e.printStackTrace();
+			try
+			{
+				rp.stop();
+			}
+			catch ( InterruptedException e1 )
+			{
+				e1.printStackTrace();
+			}
+			throw new Exception( "process did not start" );
+		}
+	}
+
+	/**
+	 * @param overrides
+	 * @throws Exception 
+	 */
+	public void run( Map<String, String> overrides ) throws Exception
+	{
+		Map<String, String> substs = processOverrides( "run", overrides );
+		List<String> tkns = processTokens( substs );
+		Map<String, String> nvs = processEnvs( substs );
+		System.out.printf( "Program.run: tokens %s envs %s\n", tkns, nvs );
+		
+		DefaultRunningProg rp = new DefaultRunningProg( tkns, nvs, stdoutTag, stderrTag );
+		try
+		{
+			rp.start();
+		}
+		catch ( Exception e )
+		{
+			e.printStackTrace();
+			try
+			{
+				rp.stop();
+			}
+			catch ( InterruptedException e1 )
+			{
+				e1.printStackTrace();
+			}
+			throw new Exception( "process did not start" );
+		}
+		
+		try
+		{
+			Integer sts = rp.join();
+			if (sts == null || sts != 0)
+				throw new Exception( "process died with bad status: "+sts );
+		}
+		catch ( InterruptedException e )
+		{
+			e.printStackTrace();
+		}
+	}
+
+	private Map<String, String> processOverrides( String who,
+		Map<String, String> overrides )
+	{
+		System.out.println( "Program."+who+": name "+name+", overrides = "+overrides );
+		
+		Map<String, String> substs = Param.processOverrides( "program", params,
+			overrides );
+		
+		System.out.println( "Program."+who+": name "+name+", substs = "+substs );
+		
+		return substs;
+	}
+
+	private List<String> processTokens( Map<String, String> substs )
+	{
+		List<String> ntokens = new ArrayList<String>();
+		for (Token t: tokens)
+			ntokens.add( t.value( substs ) );
+		return ntokens;
+	}
+
+	private Map<String, String> processEnvs( Map<String, String> substs )
+	{
+		Map<String, String> nenvs = new HashMap<String, String>();
+		for (Env e: envs.values())
+			nenvs.put( e.name(), e.value( substs ) );
+		return nenvs;
+	}
+	
+	/**
+	 * @author wert
+	 *
+	 */
+	public static class ProcessStreamReader extends Thread
+	{
+		/**
+		 * @param is input stream to read until eof.
+		 * @param tag 
+		 * @param ps 
+		 * @throws Exception 
+		 */
+		public ProcessStreamReader( InputStream is, PrintStream ps, String tag ) throws Exception
+		{
+			rdr = new BufferedReader( new InputStreamReader( is ) );
+			this.ps = ps;
+			this.tag = tag;
+		}
+		
+		private final BufferedReader rdr;
+		
+		private final PrintStream ps;
+		
+		private final String tag;
+		
+		@Override
+		public void run()
+		{
+			try
+			{
+				String s;
+				while ((s = rdr.readLine()) != null)
+				{
+					synchronized (ps)
+					{
+						ps.printf( "[%s] %s\n", tag, s );
+					}
+				}
+			}
+			catch ( Exception e )
+			{
+				e.printStackTrace();
+			}
+			finally
+			{
+				try
+				{
+					rdr.close();
+				}
+				catch ( IOException e )
+				{
+					e.printStackTrace();
+				}
+			}
+		}
+	}
+}
\ No newline at end of file

Propchange: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Program.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Program.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Run.java
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Run.java?rev=740897&view=auto
==============================================================================
--- incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Run.java (added)
+++ incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Run.java Wed Feb  4 21:29:06 2009
@@ -0,0 +1,182 @@
+/* $Id$
+ *
+ * Copyright 2009 Cisco Systems Inc.
+ *
+ * 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.apache.etch.interoptester;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.etch.util.Assertion;
+import org.apache.etch.util.core.xml.XmlParser.TagElement;
+
+
+/**
+ * Model of a test run. Run identifies the Test to be run and the arguments
+ * (name / value pairs) which will be supplied to the Test when it is run.
+ */
+public class Run
+{
+	/**
+	 * @param itest 
+	 * @param r the xml tag which defines this Run.
+	 * @return the parsed Run object.
+	 */
+	public static Run parse( InteropTestIntf itest, TagElement r )
+	{
+		Assertion.check( r.matches( null, "run" ), "tag is run" );
+		
+		String name = r.getAttr( null, "name" );
+		if (name == null || name.length() == 0)
+			name = "run-"+itest.nextRunId();
+		
+		String test = r.getAttr( null, "test" );
+		if (test == null || test.length() == 0)
+			throw new IllegalArgumentException( "run tag has no test attribute" );
+		
+		Run t = new Run( itest, name, test );
+		t.parseBody( r );
+		return t;
+	}
+
+	/**
+	 * @param itest
+	 * @param test
+	 */
+	private Run( InteropTestIntf itest, String name, String test )
+	{
+		this.itest = itest;
+		this.name = name;
+		this.test = test;
+	}
+
+	private final InteropTestIntf itest;
+	
+	private final String name;
+	
+	private final String test;
+	
+	/**
+	 * @return the containing InteropTestIntf.
+	 */
+	public InteropTestIntf itest()
+	{
+		return itest;
+	}
+	
+	/**
+	 * @return the name of this run.
+	 */
+	public String name()
+	{
+		return name;
+	}
+
+	/**
+	 * @return the test name.
+	 */
+	public String test()
+	{
+		return test;
+	}
+	
+	@Override
+	public String toString()
+	{
+		return "Run ("+name+")";
+	}
+	
+	private void parseBody( TagElement r )
+	{
+		new ChildWalker()
+		{
+			public boolean tag( TagElement te )
+			{
+				if (te.matches( null, "arg" ))
+				{
+					Arg a = Arg.parse( te );
+					if (args.containsKey( a.name() ))
+						throw new IllegalArgumentException( "duplicate name arg "+a.name() );
+					args.put( a.name(), a );
+					return true;
+				}
+				
+				if (te.matches( null, "disable" ))
+				{
+					if (te.countChildren() > 0)
+						disable = Boolean.valueOf( te.getCdataValue() );
+					else
+						disable = true;
+					System.out.println( "run "+name+" test "+test+", disable = "+disable );
+					return true;
+				}
+				
+				return false;
+			}
+		}.walk( r );
+	}
+	
+	private boolean disable;
+	
+	private final Map<String, Arg> args = new HashMap<String, Arg>();
+
+	/**
+	 * Runs the test specified by this Run.
+	 * @param substs params from interoptest to use for substitutions into this
+	 * Run's args. The args are then used to override the params of the Run's
+	 * test.
+	 * @throws Exception 
+	 */
+	public void run( Map<String, String> substs ) throws Exception
+	{
+		try
+		{
+			TestIntf t = itest.getTest( test );
+			if (t == null)
+				throw new IllegalArgumentException( "test "+test+" not found" );
+			
+			System.out.println( "---------------------------------------------------" );
+			
+			if (disable)
+			{
+				System.out.println( "Run.run: name "+name+" test "+test+", disabled" );
+				return;
+			}
+			
+			System.out.println( "Run.run: name "+name+" test "+test+", substs = "+substs );
+			
+			Map<String, String> overrides = Arg.processSubst( "run", args, substs );
+			
+			System.out.println( "Run.run: name "+name+" test "+test+", overrides = "+overrides );
+			
+			t.run( overrides );
+			
+			System.out.println( "Run.run: name "+name+" test "+test+", done" );
+		}
+		catch ( RuntimeException e )
+		{
+			throw new RuntimeException( "Run.run: name "+name+" test "+test+", caught exception", e );
+		}
+	}
+
+	/**
+	 * @return the map of args for this test run.
+	 */
+	public Map<String, Arg> args()
+	{
+		return args;
+	}
+}
\ No newline at end of file

Propchange: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Run.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Run.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/RunningProg.java
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/RunningProg.java?rev=740897&view=auto
==============================================================================
--- incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/RunningProg.java (added)
+++ incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/RunningProg.java Wed Feb  4 21:29:06 2009
@@ -0,0 +1,38 @@
+/* $Id$
+ *
+ * Copyright 2009 Cisco Systems Inc.
+ *
+ * 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.apache.etch.interoptester;
+
+/**
+ * RunningProg models a running program.
+ */
+public interface RunningProg
+{
+	/**
+	 * Stops the running program.
+	 * @return the status of the program. 0 means it exited normally.
+	 * @throws InterruptedException 
+	 */
+	public Integer stop() throws InterruptedException;
+	
+	/**
+	 * Waits for the running program to terminate.
+	 * @return the status of the program. 0 means it exited normally.
+	 * @throws InterruptedException 
+	 */
+	public Integer join() throws InterruptedException;
+}
\ No newline at end of file

Propchange: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/RunningProg.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/RunningProg.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Substitutor.java
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Substitutor.java?rev=740897&view=auto
==============================================================================
--- incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Substitutor.java (added)
+++ incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Substitutor.java Wed Feb  4 21:29:06 2009
@@ -0,0 +1,155 @@
+/* $Id$
+ *
+ * Copyright 2009 Cisco Systems Inc.
+ *
+ * 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.apache.etch.interoptester;
+
+import java.util.Map;
+
+import org.apache.etch.util.Assertion;
+import org.apache.etch.util.CharIterator;
+
+
+/**
+ * A class to perform substitutions into a string from a map,
+ * so that with input value="abc{foo}def" and map has key "foo"
+ * with value "123", the result is "abc123def".
+ */
+public class Substitutor
+{
+	private Substitutor()
+	{
+		// don't instantiate
+	}
+	
+	/**
+	 * @param value
+	 * @param map
+	 * @return value with substitutions from map
+	 */
+	public static String subst( String value, Map<String, String> map )
+	{
+		StringBuffer sb = new StringBuffer();
+		StringBuffer save = new StringBuffer();
+		CharIterator i = new CharIterator( value );
+		int state = 0;
+		while (state != 4)
+		{
+			char c;
+			int cc;
+			if (i.hasNext())
+			{
+				c = i.next();
+				cc = charClass( c );
+			}
+			else
+			{
+				c = 0;
+				cc = EOF;
+			}
+			
+			int nstate = nstates[state][cc];
+			int action = actions[state][cc];
+			
+			switch (action)
+			{
+				case 1:
+					sb.append( c );
+					break;
+				case 2:
+					// ignore
+					break;
+				case 3:
+					save.append( c );
+					break;
+				case 4:
+					sb.append( save );
+					save.setLength( 0 );
+					sb.append( c );
+					break;
+				case 5:
+					save.append( c );
+					sb.append( subst0( save.toString(), map ) );
+					save.setLength( 0 );
+					break;
+				case 6:
+					throw new IllegalArgumentException( "malformed escape" );
+				case 7:
+					sb.append( save );
+					save.setLength( 0 );
+					break;
+				default:
+					throw new IllegalArgumentException( "action "+action+" unknown" );
+			}
+			
+			state = nstate;
+		}
+		return sb.toString();
+	}
+	
+	private static Object subst0( String s, Map<String, String> map )
+	{
+		Assertion.check( s.startsWith( "{" ), "starts with {" );
+		Assertion.check( s.endsWith( "}" ), "ends with }" );
+		String n = s.substring( 1 ).substring( 0, s.length()-2 );
+		if (map.containsKey( n ))
+			return map.get( n );
+		return s;
+	}
+
+	private static int charClass( char c )
+	{
+		if (c == '\\') return BSL;
+		if (c == '{') return LBR;
+		if (c == '}') return RBR;
+		if (c >= 'a' && c <= 'z') return ALN;
+		if (c >= 'A' && c <= 'Z') return ALN;
+		if (c >= '0' && c <= '9') return ALN;
+		return OTH;
+	}
+	
+	private final static int BSL = 0;
+	
+	private final static int LBR = 1;
+	
+	private final static int RBR = 2;
+	
+	private final static int ALN = 3;
+	
+	private final static int OTH = 4;
+	
+	private final static int EOF = 5;
+	
+	private static final byte[][] nstates =
+	{
+		// first index is current state
+		// second index is char class: BSL, LBR, RBR, ALN, OTH, EOF
+		{ 1, 2, 0, 0, 0, 4 },
+		{ 0, 0, 0, 0, 0, 4 },
+		{ 0, 2, 0, 3, 0, 4 },
+		{ 0, 0, 0, 3, 0, 4 }
+	};
+	
+	private static final byte[][] actions =
+	{
+		// first index is current state
+		// second index is char class: BSL, LBR, RBR, ALN, OTH, EOF
+		{ 2, 3, 1, 1, 1, 2 },
+		{ 1, 1, 1, 1, 1, 6 },
+		{ 4, 1, 4, 3, 4, 7 },
+		{ 4, 4, 5, 3, 4, 7 }
+	};
+}

Propchange: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Substitutor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Substitutor.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Test.java
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Test.java?rev=740897&view=auto
==============================================================================
--- incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Test.java (added)
+++ incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Test.java Wed Feb  4 21:29:06 2009
@@ -0,0 +1,294 @@
+/* $Id$
+ *
+ * Copyright 2009 Cisco Systems Inc.
+ *
+ * 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.apache.etch.interoptester;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.etch.util.Assertion;
+import org.apache.etch.util.core.xml.XmlParser.TagElement;
+
+
+/**
+ * Test models a test that can be run. A Test has a name (used by a Run to
+ * specify the test), includes some parameter values and some programs to be
+ * run for setup, support, the test jig itself, and then cleanup.
+ */
+public class Test implements TestIntf
+{
+	/**
+	 * @param itest
+	 * @param r
+	 * @return the parsed Test.
+	 */
+	public static Test parse( InteropTestIntf itest, TagElement r )
+	{
+		Assertion.check( r.matches( null, "test" ), "tag is test" );
+		
+		String name = r.getAttr( null, "name" );
+		if (name == null || name.length() == 0)
+			throw new IllegalArgumentException( "test tag has no name attribute" );
+		
+		Test t = new Test( itest, name );
+		t.parseBody( r );
+		return t;
+	}
+
+	/**
+	 * @param itest
+	 * @param name
+	 */
+	private Test( InteropTestIntf itest, String name )
+	{
+		this.itest = itest;
+		this.name = name;
+	}
+	
+	private final InteropTestIntf itest;
+	
+	private final String name;
+	
+	public InteropTestIntf itest()
+	{
+		return itest;
+	}
+	
+	public String name()
+	{
+		return name;
+	}
+	
+	private void parseBody( TagElement r )
+	{
+		new ChildWalker()
+		{
+			public boolean tag( TagElement te )
+			{
+				if (te.matches( null, "params" ))
+				{
+					parseParams( te );
+					return true;
+				}
+				
+				if (te.matches( null, "setup" ))
+				{
+					parseSetup( te );
+					return true;
+				}
+				
+				if (te.matches( null, "support" ))
+				{
+					parseSupport( te );
+					return true;
+				}
+				
+				if (te.matches( null, "jig" ))
+				{
+					parseJig( te );
+					return true;
+				}
+				
+				if (te.matches( null, "cleanup" ))
+				{
+					parseCleanup( te );
+					return true;
+				}
+				
+				return false;
+			}
+		}.walk( r );
+		
+		if (jig == null)
+			throw new IllegalArgumentException( "no jig defined for test: "+name );
+	}
+	
+	private void parseParams( TagElement r )
+	{
+		new ChildWalker()
+		{
+			public boolean tag( TagElement te )
+			{
+				if (te.matches( null, "param" ))
+				{
+					parseParam( te );
+					return true;
+				}
+				
+				return false;
+			}
+		}.walk( r );
+	}
+
+	private void parseParam( TagElement r )
+	{
+		Param p = Param.parse( r );
+		params.put( p.name(), p );
+	}
+	
+	private final Map<String, Param> params = new HashMap<String, Param>();
+
+	private void parseSetup( TagElement r )
+	{
+		parseProgList( setup, r );
+	}
+	
+	private final List<Prog> setup = new ArrayList<Prog>();
+
+	private void parseSupport( TagElement r )
+	{
+		parseProgList( support, r );
+	}
+	
+	private final List<Prog> support = new ArrayList<Prog>();
+
+	private void parseJig( TagElement r )
+	{
+		List<Prog> jigs = new ArrayList<Prog>();
+		parseProgList( jigs, r );
+		if (jigs.size() != 1)
+			throw new IllegalArgumentException( "only one test jig per test" );
+		jig = jigs.get( 0 );
+	}
+	
+	private Prog jig;
+
+	private void parseCleanup( TagElement r )
+	{
+		parseProgList( cleanup, r );
+	}
+
+	private final List<Prog> cleanup = new ArrayList<Prog>();
+	
+	private void parseProgList( final List<Prog> list, TagElement r )
+	{
+		new ChildWalker()
+		{
+			public boolean tag( TagElement te )
+			{
+				if (te.matches( null, "prog" ))
+				{
+					parseProg( list, te );
+					return true;
+				}
+				
+				return false;
+			}
+		}.walk( r );
+	}
+
+	private void parseProg( List<Prog> list, TagElement r )
+	{
+		list.add( Prog.parse( this, r ) );
+	}
+
+	public void run( Map<String, String> overrides ) throws Exception
+	{
+		System.out.println( "Test.run: "+name+", overrides = "+overrides );
+		
+		Map<String, String> substs = Param.processOverrides( "test", params,
+			overrides );
+		
+		System.out.println( "Test.run: "+name+", substs = "+substs );
+		
+		runProgs( setup, substs );
+		try
+		{
+			List<RunningProg> runningProgs = startProgs( support, substs );
+			try
+			{
+				runProg( jig, substs );
+			}
+			finally
+			{
+				stopProgs( runningProgs );
+			}
+		}
+		finally
+		{
+			runProgs( cleanup, substs );
+		}
+	}
+
+	private void runProgs( List<Prog> progs, Map<String, String> substs ) throws Exception
+	{
+		for (Prog prog: progs)
+			runProg( prog, substs );
+	}
+
+	private List<RunningProg> startProgs( List<Prog> progs,
+		Map<String, String> substs ) throws Exception
+	{
+		List<RunningProg> runningProgs = new ArrayList<RunningProg>();
+		for (Prog prog: progs)
+			runningProgs.add( startProg( prog, substs ) );
+		return runningProgs;
+	}
+
+	private void stopProgs( List<RunningProg> runningProgs ) throws Exception
+	{
+		for (RunningProg rp: runningProgs)
+			stopProg( rp );
+	}
+
+	private void runProg( Prog prog, Map<String, String> substs ) throws Exception
+	{
+		prog.run( substs );
+	}
+
+	private RunningProg startProg( Prog prog, Map<String, String> substs ) throws Exception
+	{
+		return prog.start( substs );
+	}
+
+	private void stopProg( RunningProg rp ) throws Exception
+	{
+		rp.stop();
+	}
+
+	public Prog jig()
+	{
+		return jig;
+	}
+
+	public List<Prog> cleanup()
+	{
+		return cleanup;
+	}
+
+	public List<Prog> setup()
+	{
+		return setup;
+	}
+
+	public List<Prog> support()
+	{
+		return support;
+	}
+
+	public Map<String, Param> params()
+	{
+		return params;
+	}
+
+	public Program getProgram( String name )
+	{
+		return itest.getProgram( name );
+	}
+}
\ No newline at end of file

Propchange: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Test.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/Test.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/TestIntf.java
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/TestIntf.java?rev=740897&view=auto
==============================================================================
--- incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/TestIntf.java (added)
+++ incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/TestIntf.java Wed Feb  4 21:29:06 2009
@@ -0,0 +1,78 @@
+/* $Id$
+ *
+ * Copyright 2009 Cisco Systems Inc.
+ *
+ * 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.apache.etch.interoptester;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Interface to a test. A test consists of setup, support, jig, and cleanup
+ * programs.
+ */
+public interface TestIntf
+{
+	/**
+	 * @return the containing InteropTestIntf.
+	 */
+	public InteropTestIntf itest();
+	
+	/**
+	 * @return the name of the test.
+	 */
+	public String name();
+	
+	/**
+	 * @return the params of this test.
+	 */
+	public Map<String, Param> params();
+	
+	/**
+	 * @return the setup programs of this test.
+	 */
+	public List<Prog> setup();
+	
+	/**
+	 * @return the support programs of this test.
+	 */
+	public List<Prog> support();
+	
+	/**
+	 * @return the test jig of this test. This is the program that performs the
+	 * test.
+	 */
+	public Prog jig();
+	
+	/**
+	 * @return the cleanup programs of this test.
+	 */
+	public List<Prog> cleanup();
+
+	/**
+	 * Runs the test with the specified arguments.
+	 * @param overrides name / value pairs which must correspond to defined
+	 * test parameters and override their values.
+	 * @throws Exception 
+	 */
+	public void run( Map<String, String> overrides ) throws Exception;
+
+	/**
+	 * @param name
+	 * @return the named Program
+	 */
+	public Program getProgram( String name );
+}

Propchange: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/TestIntf.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/etch/trunk/interoptester/src/main/java/org/apache/etch/interoptester/TestIntf.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"