You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jmeter.apache.org by se...@apache.org on 2012/09/03 00:35:26 UTC

svn commit: r1380074 - in /jmeter/trunk: src/protocol/native/org/apache/jmeter/protocol/system/ src/protocol/native/org/apache/jmeter/protocol/system/gui/ xdocs/

Author: sebb
Date: Sun Sep  2 22:35:25 2012
New Revision: 1380074

URL: http://svn.apache.org/viewvc?rev=1380074&view=rev
Log:
OS Process - allow specification of stdout/stderr/stdin
Bugzilla Id: 53168

Added:
    jmeter/trunk/src/protocol/native/org/apache/jmeter/protocol/system/StreamCopier.java   (with props)
Modified:
    jmeter/trunk/src/protocol/native/org/apache/jmeter/protocol/system/NativeCommand.java
    jmeter/trunk/src/protocol/native/org/apache/jmeter/protocol/system/SystemSampler.java
    jmeter/trunk/src/protocol/native/org/apache/jmeter/protocol/system/gui/SystemSamplerGui.java
    jmeter/trunk/xdocs/changes.xml

Modified: jmeter/trunk/src/protocol/native/org/apache/jmeter/protocol/system/NativeCommand.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/native/org/apache/jmeter/protocol/system/NativeCommand.java?rev=1380074&r1=1380073&r2=1380074&view=diff
==============================================================================
--- jmeter/trunk/src/protocol/native/org/apache/jmeter/protocol/system/NativeCommand.java (original)
+++ jmeter/trunk/src/protocol/native/org/apache/jmeter/protocol/system/NativeCommand.java Sun Sep  2 22:35:25 2012
@@ -19,6 +19,8 @@
 package org.apache.jmeter.protocol.system;
 
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.util.Collections;
 import java.util.List;
@@ -33,17 +35,27 @@ public class NativeCommand {
     private final File directory;
     private final Map<String, String> env;
     private Map<String, String> executionEnvironment;
+    private final String stdin;
+    private final String stdout;
+    private final String stderr;
 
 	/**
 	 * @param env Environment variables appended to environment
 	 * @param directory File working directory
 	 */
 	public NativeCommand(File directory, Map<String, String> env) {
-		super();
-		this.directory = directory;
-		this.env = env;
+	    this(directory, env, null, null, null);
 	}
 
+    public NativeCommand(File directory, Map<String, String> env, String stdin, String stdout, String stderr) {
+        super();
+        this.directory = directory;
+        this.env = env;
+        this.stdin = nonEmpty(stdin);
+        this.stdout = nonEmpty(stdout);
+        this.stderr = nonEmpty(stderr);
+    }
+
 	/**
 	 * @param arguments List<String>
 	 * @return return code
@@ -58,15 +70,45 @@ public class NativeCommand {
 		    procBuild.environment().putAll(env);
 		    this.executionEnvironment = Collections.unmodifiableMap(procBuild.environment());
 		    procBuild.directory(directory);
-            procBuild.redirectErrorStream(true);
+		    if (stderr == null || stderr.equals(stdout)) { // we're not redirecting stderr separately
+		        procBuild.redirectErrorStream(true);
+		    }
             proc = procBuild.start();
-            this.outputGobbler = new 
-                     StreamGobbler(proc.getInputStream());
-            outputGobbler.start();
-	                            
+            StreamCopier swerr = null;
+            if (!procBuild.redirectErrorStream()) { // stderr has separate output file
+                swerr = new StreamCopier(proc.getErrorStream(), new FileOutputStream(stderr));
+                swerr.start();
+            }
+            
+            StreamCopier swout = null;
+            if (stdout != null) {
+                swout = new StreamCopier(proc.getInputStream(), new FileOutputStream(stdout));
+                swout.start();
+            } else {
+                outputGobbler = new StreamGobbler(proc.getInputStream());
+                outputGobbler.start();
+            }
+            
+            StreamCopier swin = null;
+	        if (stdin != null) {
+	            swin = new StreamCopier(new FileInputStream(stdin), proc.getOutputStream());
+	            swin.start();
+	        }
 			int exitVal = proc.waitFor();
 
-			outputGobbler.join();
+			if (outputGobbler != null) {
+			    outputGobbler.join();
+			}
+			if (swout != null) {
+			    swout.join();
+			}
+			if (swerr != null) {
+			    swerr.join();
+			}
+			if (swin != null) {
+			    swin.interrupt(); // the copying thread won't generally detect EOF
+			    swin.join();
+			}
 			return exitVal;
 		}
 		finally
@@ -99,4 +141,15 @@ public class NativeCommand {
     public Map<String, String> getExecutionEnvironment() {
         return executionEnvironment;
     }
+
+    private String nonEmpty(String input) {
+        if (input == null) {
+            return null;
+        }
+        String trimmed = input.trim();
+        if (trimmed.length() == 0) {
+            return null;
+        }
+        return trimmed;
+    }
 }

Added: jmeter/trunk/src/protocol/native/org/apache/jmeter/protocol/system/StreamCopier.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/native/org/apache/jmeter/protocol/system/StreamCopier.java?rev=1380074&view=auto
==============================================================================
--- jmeter/trunk/src/protocol/native/org/apache/jmeter/protocol/system/StreamCopier.java (added)
+++ jmeter/trunk/src/protocol/native/org/apache/jmeter/protocol/system/StreamCopier.java Sun Sep  2 22:35:25 2012
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jmeter.protocol.system;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.jorphan.logging.LoggingManager;
+import org.apache.log.Logger;
+
+/**
+ * Thread that copies a stream in the background; closes both input and output streams.
+ */
+class StreamCopier extends Thread {
+
+    private static final Logger log = LoggingManager.getLoggerForClass();
+
+    private final InputStream is;
+    private final OutputStream os;
+
+	/**
+	 * @param is {@link InputStream}
+	 * @throws IOException 
+	 */
+	StreamCopier(InputStream is, OutputStream os) throws IOException {
+		this.is = is;
+		this.os = os;
+	}
+
+	/**
+	 * @see java.lang.Thread#run()
+	 */
+	@Override
+    public void run() {
+	    try {
+            IOUtils.copyLarge(is, os);
+            os.close();
+            is.close();
+        } catch (IOException e) {
+            log.warn("Error writing stream", e);
+        } finally {
+            IOUtils.closeQuietly(is);
+            IOUtils.closeQuietly(os);
+        }
+	}
+	
+}

Propchange: jmeter/trunk/src/protocol/native/org/apache/jmeter/protocol/system/StreamCopier.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jmeter/trunk/src/protocol/native/org/apache/jmeter/protocol/system/StreamCopier.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Modified: jmeter/trunk/src/protocol/native/org/apache/jmeter/protocol/system/SystemSampler.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/native/org/apache/jmeter/protocol/system/SystemSampler.java?rev=1380074&r1=1380073&r2=1380074&view=diff
==============================================================================
--- jmeter/trunk/src/protocol/native/org/apache/jmeter/protocol/system/SystemSampler.java (original)
+++ jmeter/trunk/src/protocol/native/org/apache/jmeter/protocol/system/SystemSampler.java Sun Sep  2 22:35:25 2012
@@ -47,6 +47,7 @@ import org.apache.log.Logger;
 public class SystemSampler extends AbstractSampler {
     private static final long serialVersionUID = 1;
     
+    // + JMX names, do not change their values
     public static final String COMMAND = "SystemSampler.command";
     
     public static final String DIRECTORY = "SystemSampler.directory";
@@ -58,6 +59,14 @@ public class SystemSampler extends Abstr
     public static final String CHECK_RETURN_CODE = "SystemSampler.checkReturnCode";
     
     public static final String EXPECTED_RETURN_CODE = "SystemSampler.expectedReturnCode";
+    
+    private static final String STDOUT = "SystemSampler.stdout";
+
+    private static final String STDERR = "SystemSampler.stderr";
+
+    private static final String STDIN = "SystemSampler.stdin";
+
+    // - JMX names
 
     /**
      * Logging
@@ -128,7 +137,7 @@ public class SystemSampler extends Abstr
                     ", Environment:"+env+
                     ", Executing:" + cmdLine.toString());
             
-            NativeCommand nativeCommand = new NativeCommand(directory, env);
+            NativeCommand nativeCommand = new NativeCommand(directory, env, getStdin(), getStdout(), getStderr());
             
             String responseData = null;
             try {
@@ -166,6 +175,7 @@ public class SystemSampler extends Abstr
             results.setResponseData((responseData+"\nProcess Output:\n"+nativeCommand.getOutResult()).getBytes());
             
         } catch (Exception e) {
+            log.warn("Unexpected error",e);
             results.setSuccessful(false);
             results.setResponseData(("Unknown Exception caught: "+e).getBytes());
             results.setSampleLabel("ERROR: " + getName());
@@ -278,4 +288,29 @@ public class SystemSampler extends Abstr
     public Arguments getEnvironmentVariables() {
         return (Arguments) getProperty(ENVIRONMENT).getObjectValue();
     }
+
+    public String getStdout() {
+        return getPropertyAsString(STDOUT, "");
+    }
+
+    public void setStdout(String filename) {
+        setProperty(STDOUT, filename, "");
+    }
+
+    public String getStderr() {
+        return getPropertyAsString(STDERR, "");
+    }
+
+    public void setStderr(String filename) {
+        setProperty(STDERR, filename, "");
+    }
+
+    public String getStdin() {
+        return getPropertyAsString(STDIN, "");
+    }
+
+    public void setStdin(String filename) {
+        setProperty(STDIN, filename, "");
+    }
+
 }
\ No newline at end of file

Modified: jmeter/trunk/src/protocol/native/org/apache/jmeter/protocol/system/gui/SystemSamplerGui.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/native/org/apache/jmeter/protocol/system/gui/SystemSamplerGui.java?rev=1380074&r1=1380073&r2=1380074&view=diff
==============================================================================
--- jmeter/trunk/src/protocol/native/org/apache/jmeter/protocol/system/gui/SystemSamplerGui.java (original)
+++ jmeter/trunk/src/protocol/native/org/apache/jmeter/protocol/system/gui/SystemSamplerGui.java Sun Sep  2 22:35:25 2012
@@ -32,6 +32,7 @@ import org.apache.commons.lang3.StringUt
 import org.apache.jmeter.config.Argument;
 import org.apache.jmeter.config.Arguments;
 import org.apache.jmeter.config.gui.ArgumentsPanel;
+import org.apache.jmeter.gui.util.FilePanelEntry;
 import org.apache.jmeter.gui.util.VerticalPanel;
 import org.apache.jmeter.protocol.system.SystemSampler;
 import org.apache.jmeter.samplers.gui.AbstractSamplerGui;
@@ -53,6 +54,9 @@ public class SystemSamplerGui extends Ab
     
     private JCheckBox checkReturnCode;
     private JLabeledTextField desiredReturnCode;
+    private final FilePanelEntry stdin = new FilePanelEntry("stdin ");
+    private final FilePanelEntry stdout = new FilePanelEntry("stdout");
+    private final FilePanelEntry stderr = new FilePanelEntry("stderr");
     private JLabeledTextField directory;
     private JLabeledTextField command;
     private ArgumentsPanel argsPanel;
@@ -116,6 +120,9 @@ public class SystemSamplerGui extends Ab
         systemSampler.setArguments((Arguments)argsPanel.createTestElement());
         systemSampler.setEnvironmentVariables((Arguments)envPanel.createTestElement());
         systemSampler.setDirectory(directory.getText());
+        systemSampler.setStdin(stdin.getFilename());
+        systemSampler.setStdout(stdout.getFilename());
+        systemSampler.setStderr(stderr.getFilename());
     }
 
     /* Overrides AbstractJMeterGuiComponent.configure(TestElement) */
@@ -130,6 +137,9 @@ public class SystemSamplerGui extends Ab
         argsPanel.configure(systemSampler.getArguments());
         envPanel.configure(systemSampler.getEnvironmentVariables());
         directory.setText(systemSampler.getDirectory());
+        stdin.setFilename(systemSampler.getStdin());
+        stdout.setFilename(systemSampler.getStdout());
+        stderr.setFilename(systemSampler.getStderr());
     }
 
     /**
@@ -153,10 +163,7 @@ public class SystemSamplerGui extends Ab
     /**
      * @return JPanel Command + directory
      */
-    private JPanel makeCommandPanel() {
-        JPanel panel = new JPanel(new BorderLayout());
-        panel.setBorder(BorderFactory.createTitledBorder(JMeterUtils.getResString("command_config_box_title")));
-        
+    private JPanel makeCommandPanel() {       
         JPanel cmdPanel = new JPanel();
         cmdPanel.setLayout(new BoxLayout(cmdPanel, BoxLayout.X_AXIS));
         
@@ -165,9 +172,18 @@ public class SystemSamplerGui extends Ab
         cmdPanel.add(Box.createHorizontalStrut(5));
         command = new JLabeledTextField(JMeterUtils.getResString("command_field_title"));
         cmdPanel.add(command);
-        panel.add(cmdPanel, BorderLayout.NORTH);
-        panel.add(makeArgumentsPanel(), BorderLayout.CENTER);
-        panel.add(makeEnvironmentPanel(), BorderLayout.SOUTH);
+        
+        JPanel panel = new VerticalPanel();
+        panel.setBorder(BorderFactory.createTitledBorder(JMeterUtils.getResString("command_config_box_title")));
+        panel.add(cmdPanel);
+        panel.add(makeArgumentsPanel());
+        panel.add(makeEnvironmentPanel());
+        panel.add(Box.createVerticalStrut(5));
+        panel.add(stdin);
+        panel.add(Box.createVerticalStrut(5));
+        panel.add(stdout);
+        panel.add(Box.createVerticalStrut(5));
+        panel.add(stderr);
         return panel;
     }
     
@@ -207,6 +223,9 @@ public class SystemSamplerGui extends Ab
         desiredReturnCode.setText("");
         checkReturnCode.setSelected(false);
         desiredReturnCode.setEnabled(false);
+        stdin.clearGui();
+        stdout.clearGui();
+        stderr.clearGui();
     }
 
     public void itemStateChanged(ItemEvent e) {

Modified: jmeter/trunk/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/changes.xml?rev=1380074&r1=1380073&r2=1380074&view=diff
==============================================================================
--- jmeter/trunk/xdocs/changes.xml (original)
+++ jmeter/trunk/xdocs/changes.xml Sun Sep  2 22:35:25 2012
@@ -147,6 +147,7 @@ The original behaviour can be restored b
 <li><bugzilla>55310</bugzilla> - TestAction should implement Interruptible</li>
 <li><bugzilla>53318</bugzilla> - Add Embedded URL Filter to HTTP Request Defaults Control </li>
 <li><bugzilla>53782</bugzilla> - Enhance JavaSampler handling of JavaSamplerClient cleanup to use less memory</li>
+<li><bugzilla>53168</bugzilla> - OS Process - allow specification of stdout/stderr/stdin</li>
 </ul>
 
 <h3>Controllers</h3>