1   /*
2       This file is part of quExec.
3   
4       quExec is free software; you can redistribute it and/or modify
5       it under the terms of the GNU Lesser General Public License as published by
6       the Free Software Foundation; either version 2 of the License, or
7       (at your option) any later version.
8   
9       quExec is distributed in the hope that it will be useful,
10      but WITHOUT ANY WARRANTY; without even the implied warranty of
11      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12      GNU Lesser General Public License for more details.
13  
14      You should have received a copy of the GNU Lesser General Public License
15      along with quExec; if not, write to the Free Software
16      Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18  
19  package net.sourceforge.quexec.proc;
20  
21  
22  import static org.junit.Assert.assertEquals;
23  import static org.junit.Assert.assertFalse;
24  import static org.junit.Assert.assertTrue;
25  import static org.junit.Assert.fail;
26  
27  import java.io.IOException;
28  import java.util.ArrayList;
29  import java.util.Arrays;
30  import java.util.List;
31  import java.util.TreeMap;
32  import java.util.Map;
33  import java.util.concurrent.TimeoutException;
34  
35  import net.sourceforge.quexec.packet.chars.consumer.StoreCharPacketConsumer;
36  import net.sourceforge.quexec.packet.chars.consumer.StreamCharPacketConsumer;
37  import net.sourceforge.quexec.packet.chars.producer.AbstractReaderCharPacketProducer;
38  import net.sourceforge.quexec.packet.chars.producer.LinewiseCharPacketProducer;
39  import net.sourceforge.quexec.packet.chars.stream.QueueCharPacketStream;
40  import net.sourceforge.quexec.packet.chars.stream.StreamTestUtils;
41  import net.sourceforge.quexec.packet.chars.stream.WriterCharPacketOutputStream;
42  
43  import org.junit.After;
44  import org.junit.AfterClass;
45  import org.junit.Before;
46  import org.junit.BeforeClass;
47  import org.junit.Test;
48  
49  public class ProcessExecutorTest {
50  	
51  	private static final String[] output = {
52  			"bla",
53  			"foo",
54  			"bar",
55  	};
56  
57  	private ProcessExecutor pexec;
58  	
59  	private StoreCharPacketConsumer storeConsumer;
60  	
61  	private QueueCharPacketStream procOutStream;
62  
63  	private WriterCharPacketOutputStream procInStream;
64  
65  	@BeforeClass
66  	public static void setUpBeforeClass() throws Exception {
67  	}
68  
69  	@AfterClass
70  	public static void tearDownAfterClass() throws Exception {
71  	}
72  
73  	@Before
74  	public void setUp() throws Exception {
75  		this.pexec = new ProcessExecutor();
76  
77  	}
78  	
79  	private void connectStoreConsumer() {
80  		this.storeConsumer = new StoreCharPacketConsumer();
81  		
82  		AbstractReaderCharPacketProducer producer =
83  			new LinewiseCharPacketProducer();
84  		producer.setConsumer(this.storeConsumer);
85  
86  		ReaderProcessOutputConnector connector =
87  			new ReaderProcessOutputConnector();
88  		connector.setConnectReader(producer);
89  
90  		this.pexec.setConnector(connector);
91  	}
92  	
93  	private void connectInputOutputStreams() {
94  		List<ProcessConnector> connList = new ArrayList<ProcessConnector>(2);
95  		
96  		ReaderProcessOutputConnector outConn =
97  			new ReaderProcessOutputConnector();
98  		AbstractReaderCharPacketProducer producer =
99  			new LinewiseCharPacketProducer();
100 		StreamCharPacketConsumer consumer =
101 			new StreamCharPacketConsumer();
102 		this.procOutStream = QueueCharPacketStream.newInstance();
103 		consumer.setOutputStream(this.procOutStream);
104 		producer.setConsumer(consumer);
105 		outConn.setConnectReader(producer);
106 		connList.add(outConn);
107 		
108 		WriterProcessInputConnector inpConn = new WriterProcessInputConnector();
109 		this.procInStream = new WriterCharPacketOutputStream();
110 		inpConn.setConnectWriter(this.procInStream);
111 		connList.add(inpConn);
112 		
113 		this.pexec.setConnectors(connList);
114 	}
115 
116 	@After
117 	public void tearDown() throws Exception {
118 	}
119 
120 	@Test(timeout=1000)
121 	public void runSuccessfulCommandAndCheckReturnCode()
122 	throws IOException, InterruptedException, TimeoutException {
123 		final int rcVal = 10;
124 		this.pexec.execJava(Arrays.asList(
125 				ArgToReturnCodeMain.class.getName(),
126 				String.valueOf(rcVal)));
127 		assertEquals(rcVal, this.pexec.waitFor());
128 	}
129 	
130 	@Test(expected=TimeoutException.class)
131 	public void runNonTerminatingCommandWithTimeout()
132 	throws IOException, InterruptedException, TimeoutException {
133 		this.pexec.execJava(NonTerminatingMain.class.getName());
134 		this.pexec.waitFor(100);
135 	}
136 
137 	@Test(timeout=10000)
138 	public void checkOutputAfterSuccessfulRun()
139 	throws IOException, InterruptedException, TimeoutException {
140 		final String[] output = {
141 				"bla",
142 				"foo",
143 				"bar",
144 		};
145 		connectStoreConsumer();
146 		List<String> args = new ArrayList<String>(output.length + 1);
147 		args.add(EchoArgsMain.class.getName());
148 		args.addAll(Arrays.asList(output));
149 		this.pexec.execJava(args);
150 		assertEquals(0, this.pexec.waitFor());
151 		assertEquals(concatenate(output), this.storeConsumer.retrieveData());
152 	}
153 	
154 	@Test(timeout=10000)
155 	public void checkOutputAfterTimeout()
156 	throws IOException, InterruptedException, TimeoutException {
157 		connectStoreConsumer();
158 		List<String> args = new ArrayList<String>(output.length + 1);
159 		args.add(EchoArgsNonTerminatingMain.class.getName());
160 		args.addAll(Arrays.asList(output));
161 		this.pexec.execJava(args);
162 		try {
163 			this.pexec.waitFor(1000);
164 			fail("timeout should occur");
165 		}
166 		catch (TimeoutException ignored) {
167 			// nothing to do
168 		}
169 		assertEquals(concatenate(output), this.storeConsumer.retrieveData());
170 		
171 	}
172 	
173 	@Test(timeout=1000)
174 	public void checkReceiveThroughPacketStream()
175 	throws IOException, InterruptedException {
176 		connectInputOutputStreams();
177 		List<String> args = new ArrayList<String>(output.length + 1);
178 		args.add(EchoArgsMain.class.getName());
179 		args.addAll(Arrays.asList(output));
180 		this.pexec.execJava(args);
181 
182 		for (int pos = 0; pos < output.length; pos++) {
183 			assertFalse(this.procOutStream.isFinished());
184 			assertEquals(output[pos] + "\n", this.procOutStream.readPacket());
185 		}
186 		
187 		Thread.sleep(100);
188 		assertFalse(this.procOutStream.isFinished());
189 		assertEquals(0, this.pexec.waitFor());
190 		StreamTestUtils.checkStreamFinished(this.procOutStream);
191 	}
192 	
193 	@Test(timeout=4000)
194 	public void interactiveInputAndOutput()
195 	throws IOException, InterruptedException {
196 		connectInputOutputStreams();
197 		this.pexec.execJava(CatMain.class.getName());
198 
199 		// send and receive interleaved
200 		for (int pos = 0; pos < output.length; pos++) {
201 			assertFalse(this.procOutStream.isFinished());
202 			this.procInStream.sendPacket(output[pos] + "X\n");
203 			assertEquals(output[pos] + "X\n", this.procOutStream.readPacket());
204 		}
205 		
206 		// first send, then receive
207 		for (int pos = 0; pos < output.length; pos++) {
208 			this.procInStream.sendPacket(output[pos] + "Y\n");
209 		}
210 		this.procInStream.finish();
211 /*		Thread.sleep(1000);
212 		this.pexec.kill(); */
213 		assertEquals(0, this.pexec.waitFor());
214 		for (int pos = 0; pos < output.length; pos++) {
215 			assertFalse(this.procOutStream.isFinished());
216 			assertEquals(output[pos] + "Y\n", this.procOutStream.readPacket());
217 		}
218 		assertTrue(this.procOutStream.isFinished());
219 	}
220 	
221 	@Test(timeout=5000)
222 	public void manipulateProcessEnvironment()
223 	throws IOException, InterruptedException {
224 		connectInputOutputStreams();
225 		
226 		this.pexec.setClearEnvironment(true);
227 		Map<String, String> env = new TreeMap<String, String>();
228 		for (int pos = 0; pos < output.length; pos++) {
229 			env.put(String.valueOf(pos), output[pos]);
230 		}
231 		this.pexec.setEnvSettings(env);
232 		
233 		this.pexec.execJava(PrintEnvMain.class.getName());
234 		for (int pos = 0; pos < output.length; pos++) {
235 			assertFalse(this.procOutStream.isFinished());
236 			assertEquals(output[pos] + "\n", this.procOutStream.readPacket());
237 		}
238 		assertFalse(this.procOutStream.isFinished());
239 		this.pexec.waitFor();
240 		StreamTestUtils.checkStreamFinished(this.procOutStream);
241 	}
242 	
243 	private static String concatenate(String[] l) {
244         StringBuffer buffer = new StringBuffer();
245         for (String s : l) {
246             buffer.append(s);
247             buffer.append("\n");
248         }
249         return buffer.toString();
250 	}
251 }