You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jmeter.apache.org by pm...@apache.org on 2018/12/19 09:54:42 UTC
svn commit: r1849285 - in /jmeter/trunk:
src/core/org/apache/jmeter/gui/action/ src/core/org/apache/jmeter/resources/
src/protocol/http/org/apache/jmeter/protocol/http/curl/
src/protocol/http/org/apache/jmeter/protocol/http/gui/action/
test/src/org/apa...
Author: pmouawad
Date: Wed Dec 19 09:54:42 2018
New Revision: 1849285
URL: http://svn.apache.org/viewvc?rev=1849285&view=rev
Log:
Bug 62959 - Ability to create a Test plan from a Curl command
Contributed by UbikLoadPack
This closes #436
Bugzilla Id: 62959
Added:
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/curl/
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/curl/BasicCurlParser.java (with props)
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/gui/action/
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/gui/action/ParseCurlCommandAction.java (with props)
jmeter/trunk/test/src/org/apache/jmeter/curl/
jmeter/trunk/test/src/org/apache/jmeter/curl/BasicCurlParserTest.java (with props)
Modified:
jmeter/trunk/src/core/org/apache/jmeter/gui/action/ActionNames.java
jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties
jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties
jmeter/trunk/xdocs/changes.xml
Modified: jmeter/trunk/src/core/org/apache/jmeter/gui/action/ActionNames.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/action/ActionNames.java?rev=1849285&r1=1849284&r2=1849285&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/gui/action/ActionNames.java (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/gui/action/ActionNames.java Wed Dec 19 09:54:42 2018
@@ -115,6 +115,7 @@ public final class ActionNames {
public static final String VALIDATE_TG = "validate_tg"; //$NON-NLS-1$
public static final String ZOOM_IN = "zoom_in"; //$NON-NLS-1$
public static final String ZOOM_OUT = "zoom_out"; //$NON-NLS-1$
+ public static final String PARSE_CURL = "parse_curl"; ////$NON-NLS-1$
// Prevent instantiation
private ActionNames() {}
Modified: jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties?rev=1849285&r1=1849284&r2=1849285&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties Wed Dec 19 09:54:42 2018
@@ -243,6 +243,11 @@ cssjquery_tester_button_test=Test
cssjquery_tester_field=Selector\:
cssjquery_tester_title=CSS Selector Tester
csvread_file_file_name=CSV file to get values from | *alias
+curl_import_menu=Import from cURL (alpha)
+curl_import=Create Test plan from cURL
+curl_create_request=Create Test plan
+curl_create_success=Successfully created test plan
+curl_create_failure=Error creating test plan, error:{0}
cut=Cut
cut_paste_function=Function syntax\:
database_conn_pool_max_usage=Max Usage For Each Connection\:
Modified: jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties?rev=1849285&r1=1849284&r2=1849285&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties Wed Dec 19 09:54:42 2018
@@ -238,6 +238,11 @@ cssjquery_tester_error=Une erreur s''est
cssjquery_tester_field=S\u00E9lecteur\:
cssjquery_tester_title=Testeur Selecteur CSS
csvread_file_file_name=Fichier CSV pour obtenir les valeurs de | *alias
+curl_import_menu_import=Import depuis cURL (alpha)
+curl_import=Cr\u00e9er un plan de test \u00e0 partir de cURL
+curl_create_request=Cr\u00e9er plan de test
+curl_create_success=Plan de test cr\u00e9\u00e9 avec succ\u00e8s
+curl_create_failure=Erreur de cr\u00e9ation de plan de test, erreur:{0}.
cut=Couper
cut_paste_function=Syntaxe de la fonction \:
database_conn_pool_max_usage=Utilisation max pour chaque connexion\:
Added: jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/curl/BasicCurlParser.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/curl/BasicCurlParser.java?rev=1849285&view=auto
==============================================================================
--- jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/curl/BasicCurlParser.java (added)
+++ jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/curl/BasicCurlParser.java Wed Dec 19 09:54:42 2018
@@ -0,0 +1,255 @@
+/*
+ * 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.http.curl;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import org.apache.commons.cli.avalon.CLArgsParser;
+import org.apache.commons.cli.avalon.CLOption;
+import org.apache.commons.cli.avalon.CLOptionDescriptor;
+
+/**
+ * Basic cURL command parser that handles:
+ * -X
+ * -H
+ * --compressed
+ * --data POST with Body data
+ *
+ * @since 5.1
+ */
+public class BasicCurlParser {
+ private static final int METHOD_OPT = 'X';
+ private static final int COMPRESSED_OPT = 'c';// $NON-NLS-1$
+ private static final int HEADER_OPT = 'H';// $NON-NLS-1$
+ private static final int DATA_OPT = 'd';// $NON-NLS-1$
+
+ public static final class Request {
+ private boolean compressed;
+ private String url;
+ private Map<String, String> headers = new LinkedHashMap<>();
+ private String method = "GET";
+ private String postData;
+ /**
+ */
+ public Request() {
+ super();
+ }
+ /**
+ * @return the compressed
+ */
+ public boolean isCompressed() {
+ return compressed;
+ }
+ /**
+ * @param compressed the compressed to set
+ */
+ public void setCompressed(boolean compressed) {
+ this.compressed = compressed;
+ }
+
+ public void addHeader(String name, String value) {
+ headers.put(name, value);
+ }
+ /**
+ * @return the url
+ */
+ public String getUrl() {
+ return url;
+ }
+ /**
+ * @param url the url to set
+ */
+ public void setUrl(String url) {
+ this.url = url;
+ }
+ /**
+ * @return the headers
+ */
+ public Map<String, String> getHeaders() {
+ return headers;
+ }
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("Request [compressed=");
+ builder.append(compressed);
+ builder.append(", url=");
+ builder.append(url);
+ builder.append(", method=");
+ builder.append(method);
+ builder.append(", headers=");
+ builder.append(headers);
+ builder.append("]");
+ return builder.toString();
+ }
+ public String getMethod() {
+ return method;
+ }
+ /**
+ * @param method the method to set
+ */
+ public void setMethod(String method) {
+ this.method = method;
+ }
+ public void setPostData(String value) {
+ this.postData = value;
+ }
+ /**
+ * @return the postData
+ */
+ public String getPostData() {
+ return postData;
+ }
+ }
+ private static final CLOptionDescriptor D_COMPRESSED_OPT =
+ new CLOptionDescriptor("compressed", CLOptionDescriptor.ARGUMENT_DISALLOWED, COMPRESSED_OPT,
+ "Request compressed response (using deflate or gzip)");
+ private static final CLOptionDescriptor D_HEADER_OPT =
+ new CLOptionDescriptor("header", CLOptionDescriptor.ARGUMENT_REQUIRED | CLOptionDescriptor.DUPLICATES_ALLOWED, HEADER_OPT,
+ "Pass custom header LINE to server");
+ private static final CLOptionDescriptor D_METHOD_OPT =
+ new CLOptionDescriptor("command", CLOptionDescriptor.ARGUMENT_REQUIRED, METHOD_OPT,
+ "Pass custom header LINE to server");
+ private static final CLOptionDescriptor D_DATA_OPT =
+ new CLOptionDescriptor("data", CLOptionDescriptor.ARGUMENT_REQUIRED, DATA_OPT,
+ "HTTP POST data");
+
+
+ private static final CLOptionDescriptor[] OPTIONS = new CLOptionDescriptor[] {
+ D_COMPRESSED_OPT,
+ D_HEADER_OPT,
+ D_METHOD_OPT,
+ D_DATA_OPT
+ };
+
+ public BasicCurlParser() {
+ super();
+ }
+
+ public Request parse(String commandLine) {
+ String[] args = translateCommandline(commandLine);
+ CLArgsParser parser = new CLArgsParser(args, OPTIONS);
+ String error = parser.getErrorString();
+ if(error == null) {
+ List<CLOption> clOptions = parser.getArguments();
+ Request request = new Request();
+ for (CLOption option : clOptions) {
+ if (option.getDescriptor().getId() == CLOption.TEXT_ARGUMENT) {
+ // Curl or URL
+ if(!"CURL".equalsIgnoreCase(option.getArgument())) {
+ request.setUrl(option.getArgument());
+ continue;
+ }
+ } else if (option.getDescriptor().getId() == COMPRESSED_OPT) {
+ request.setCompressed(true);
+ } else if (option.getDescriptor().getId() == HEADER_OPT) {
+ String nameAndValue = option.getArgument(0);
+ int indexOfSemicolon = nameAndValue.indexOf(':');
+ String name = nameAndValue.substring(0, indexOfSemicolon).trim();
+ String value = nameAndValue.substring(indexOfSemicolon+1).trim();
+ request.addHeader(name, value);
+ } else if (option.getDescriptor().getId() == METHOD_OPT) {
+ String value = option.getArgument(0);
+ request.setMethod(value);
+ } else if (option.getDescriptor().getId() == DATA_OPT) {
+ String value = option.getArgument(0);
+ request.setMethod("POST");
+ request.setPostData(value);
+ }
+ }
+ return request;
+ } else {
+ throw new IllegalArgumentException("Unexpected format for command line:"+commandLine+", error:"+error);
+ }
+ }
+
+ /**
+ * Crack a command line.
+ * @param toProcess the command line to process.
+ * @return the command line broken into strings.
+ * An empty or null toProcess parameter results in a zero sized array.
+ */
+ public static String[] translateCommandline(String toProcess) {
+ if (toProcess == null || toProcess.isEmpty()) {
+ //no command? no string
+ return new String[0];
+ }
+ // parse with a simple finite state machine
+
+ final int normal = 0;
+ final int inQuote = 1;
+ final int inDoubleQuote = 2;
+ int state = normal;
+ final StringTokenizer tok = new StringTokenizer(toProcess, "\"\' ", true);
+ final ArrayList<String> result = new ArrayList<>();
+ final StringBuilder current = new StringBuilder();
+ boolean lastTokenHasBeenQuoted = false;
+
+ while (tok.hasMoreTokens()) {
+ String nextTok = tok.nextToken();
+ switch (state) {
+ case inQuote:
+ if ("\'".equals(nextTok)) {
+ lastTokenHasBeenQuoted = true;
+ state = normal;
+ } else {
+ current.append(nextTok);
+ }
+ break;
+ case inDoubleQuote:
+ if ("\"".equals(nextTok)) {
+ lastTokenHasBeenQuoted = true;
+ state = normal;
+ } else {
+ current.append(nextTok);
+ }
+ break;
+ default:
+ if ("\'".equals(nextTok)) {
+ state = inQuote;
+ } else if ("\"".equals(nextTok)) {
+ state = inDoubleQuote;
+ } else if (" ".equals(nextTok)) {
+ if (lastTokenHasBeenQuoted || current.length() > 0) {
+ result.add(current.toString());
+ current.setLength(0);
+ }
+ } else {
+ current.append(nextTok);
+ }
+ lastTokenHasBeenQuoted = false;
+ break;
+ }
+ }
+ if (lastTokenHasBeenQuoted || current.length() > 0) {
+ result.add(current.toString());
+ }
+ if (state == inQuote || state == inDoubleQuote) {
+ throw new IllegalArgumentException("unbalanced quotes in " + toProcess);
+ }
+ return result.toArray(new String[result.size()]);
+ }
+}
Propchange: jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/curl/BasicCurlParser.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/curl/BasicCurlParser.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/gui/action/ParseCurlCommandAction.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/gui/action/ParseCurlCommandAction.java?rev=1849285&view=auto
==============================================================================
--- jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/gui/action/ParseCurlCommandAction.java (added)
+++ jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/gui/action/ParseCurlCommandAction.java Wed Dec 19 09:54:42 2018
@@ -0,0 +1,272 @@
+/*
+ * 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.http.gui.action;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Container;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.text.MessageFormat;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JPanel;
+import javax.swing.MenuElement;
+import javax.swing.SwingUtilities;
+import javax.swing.tree.TreePath;
+
+import org.apache.jmeter.config.Arguments;
+import org.apache.jmeter.control.LoopController;
+import org.apache.jmeter.control.gui.TestPlanGui;
+import org.apache.jmeter.exceptions.IllegalUserActionException;
+import org.apache.jmeter.gui.GuiPackage;
+import org.apache.jmeter.gui.action.AbstractAction;
+import org.apache.jmeter.gui.action.ActionNames;
+import org.apache.jmeter.gui.action.ActionRouter;
+import org.apache.jmeter.gui.plugin.MenuCreator;
+import org.apache.jmeter.gui.tree.JMeterTreeNode;
+import org.apache.jmeter.gui.util.EscapeDialog;
+import org.apache.jmeter.gui.util.JSyntaxTextArea;
+import org.apache.jmeter.gui.util.JTextScrollPane;
+import org.apache.jmeter.protocol.http.control.Header;
+import org.apache.jmeter.protocol.http.control.HeaderManager;
+import org.apache.jmeter.protocol.http.control.gui.HttpTestSampleGui;
+import org.apache.jmeter.protocol.http.curl.BasicCurlParser;
+import org.apache.jmeter.protocol.http.curl.BasicCurlParser.Request;
+import org.apache.jmeter.protocol.http.gui.HeaderPanel;
+import org.apache.jmeter.protocol.http.sampler.HTTPSamplerFactory;
+import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy;
+import org.apache.jmeter.reporters.ResultCollector;
+import org.apache.jmeter.services.FileServer;
+import org.apache.jmeter.testelement.TestElement;
+import org.apache.jmeter.testelement.TestPlan;
+import org.apache.jmeter.threads.ThreadGroup;
+import org.apache.jmeter.threads.gui.ThreadGroupGui;
+import org.apache.jmeter.util.JMeterUtils;
+import org.apache.jmeter.visualizers.ViewResultsFullVisualizer;
+import org.apache.jorphan.collections.HashTree;
+import org.apache.jorphan.gui.ComponentUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Opens a popup where user can enter a cURL command line and create a test plan from it
+ * @since 5.1
+ */
+public class ParseCurlCommandAction extends AbstractAction implements MenuCreator, ActionListener { // NOSONAR
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ParseCurlCommandAction.class);
+ private static final String ACCEPT_ENCODING = "Accept-Encoding";
+ private static final Set<String> commands = new HashSet<>();
+ public static final String IMPORT_CURL = "import_curl";
+ private static final String CREATE_REQUEST = "CREATE_REQUEST";
+
+ static {
+ commands.add(IMPORT_CURL);
+ }
+
+ private JSyntaxTextArea cURLCommandTA;
+ private JLabel statusText;
+
+ /**
+ *
+ */
+ public ParseCurlCommandAction() {
+ super();
+ }
+
+ @Override
+ public void doAction(ActionEvent e) {
+ ActionRouter.getInstance().doActionNow(new ActionEvent(e.getSource(), e.getID(), ActionNames.CLOSE));
+ showInputDialog();
+ }
+
+ /**
+ * Show popup where user can import cURL command
+ */
+ private final void showInputDialog() {
+ EscapeDialog messageDialog = new EscapeDialog(GuiPackage.getInstance().getMainFrame(),
+ JMeterUtils.getResString("curl_import"), true); //$NON-NLS-1$
+ Container contentPane = messageDialog.getContentPane();
+ contentPane.setLayout(new BorderLayout());
+ statusText = new JLabel("", JLabel.CENTER);
+ statusText.setForeground(Color.RED);
+ contentPane.add(statusText, BorderLayout.NORTH);
+
+ cURLCommandTA = JSyntaxTextArea.getInstance(10, 80, false);
+ cURLCommandTA.setCaretPosition(0);
+ contentPane.add(JTextScrollPane.getInstance(cURLCommandTA), BorderLayout.CENTER);
+
+ JPanel buttonPanel = new JPanel(new GridLayout(1, 1));
+ JButton button = new JButton(JMeterUtils.getResString("curl_create_request"));
+ button.setActionCommand(CREATE_REQUEST);
+ button.addActionListener(this);
+ buttonPanel.add(button);
+ contentPane.add(buttonPanel, BorderLayout.SOUTH);
+ messageDialog.pack();
+ ComponentUtil.centerComponentInComponent(GuiPackage.getInstance().getMainFrame(), messageDialog);
+ SwingUtilities.invokeLater(() -> messageDialog.setVisible(true));
+ }
+
+ private void createTestPlan(ActionEvent e, Request request) throws MalformedURLException, IllegalUserActionException {
+ GuiPackage guiPackage = GuiPackage.getInstance();
+
+ guiPackage.clearTestPlan();
+ FileServer.getFileServer().setScriptName(null);
+
+ ThreadGroup threadGroup = new ThreadGroup();
+ threadGroup.setProperty(TestElement.GUI_CLASS, ThreadGroupGui.class.getName());
+ threadGroup.setProperty(TestElement.NAME, "Thread Group");
+ threadGroup.setNumThreads(1);
+ threadGroup.setRampUp(1);
+
+ LoopController loopCtrl = new LoopController();
+ loopCtrl.setLoops(1);
+ loopCtrl.setContinueForever(false);
+ threadGroup.setSamplerController(loopCtrl);
+
+ TestPlan testPlan = new TestPlan();
+ testPlan.setProperty(TestElement.NAME, "Test Plan");
+ testPlan.setProperty(TestElement.GUI_CLASS, TestPlanGui.class.getName());
+
+ HashTree tree = new HashTree();
+ HashTree testPlanHT = tree.add(testPlan);
+ HashTree threadGroupHT = testPlanHT.add(threadGroup);
+
+ createHttpRequest(request, threadGroupHT);
+
+ ResultCollector resultCollector = new ResultCollector();
+ resultCollector.setProperty(TestElement.NAME, "View Results Tree");
+ resultCollector.setProperty(TestElement.GUI_CLASS, ViewResultsFullVisualizer.class.getName());
+ tree.add(tree.getArray()[0], resultCollector);
+
+ final HashTree newTree = guiPackage.addSubTree(tree);
+ guiPackage.updateCurrentGui();
+ guiPackage.getMainFrame().getTree().setSelectionPath(
+ new TreePath(((JMeterTreeNode) newTree.getArray()[0]).getPath()));
+ final HashTree subTree = guiPackage.getCurrentSubTree();
+ // Send different event wether we are merging a test plan into another test plan,
+ // or loading a testplan from scratch
+ ActionEvent actionEvent =
+ new ActionEvent(subTree.get(subTree.getArray()[subTree.size() - 1]), e.getID(), ActionNames.SUB_TREE_LOADED);
+ ActionRouter.getInstance().actionPerformed(actionEvent);
+ ActionRouter.getInstance().doActionNow(new ActionEvent(e.getSource(), e.getID(), ActionNames.EXPAND_ALL));
+ }
+
+ private HTTPSamplerProxy createHttpRequest(Request request, HashTree parentHT) throws MalformedURLException {
+ HTTPSamplerProxy httpSampler = (HTTPSamplerProxy) HTTPSamplerFactory.newInstance(HTTPSamplerFactory.DEFAULT_CLASSNAME);
+ httpSampler.setProperty(TestElement.GUI_CLASS, HttpTestSampleGui.class.getName());
+ httpSampler.setProperty(TestElement.NAME, "HTTP Request");
+ httpSampler.setProtocol(new URL(request.getUrl()).getProtocol());
+ httpSampler.setPath(request.getUrl());
+ httpSampler.setMethod(request.getMethod());
+
+ HashTree samplerHT = parentHT.add(httpSampler);
+
+ HeaderManager headerManager = new HeaderManager();
+ headerManager.setProperty(TestElement.GUI_CLASS, HeaderPanel.class.getName());
+ headerManager.setProperty(TestElement.NAME, "HTTP HeaderManager");
+ Map<String, String> map = request.getHeaders();
+
+ boolean hasAcceptEncoding = false;
+ for (Map.Entry<String, String> header : map.entrySet()) {
+ String key = header.getKey();
+ hasAcceptEncoding = hasAcceptEncoding || key.equalsIgnoreCase(ACCEPT_ENCODING);
+ headerManager.getHeaders().addItem(new Header(key, header.getValue()));
+ }
+ if(!hasAcceptEncoding) {
+ headerManager.getHeaders().addItem(new Header(ACCEPT_ENCODING, "gzip, deflate"));
+ }
+ if (!"GET".equals(request.getMethod())) {
+ Arguments arguments = new Arguments();
+ httpSampler.setArguments(arguments);
+ httpSampler.addNonEncodedArgument("", request.getPostData(), "");
+ }
+ httpSampler.addTestElement(headerManager);
+ samplerHT.add(headerManager);
+ return httpSampler;
+ }
+
+ @Override
+ public Set<String> getActionNames() {
+ return commands;
+ }
+
+ @Override
+ public JMenuItem[] getMenuItemsAtLocation(MENU_LOCATION location) {
+ if(location == MENU_LOCATION.HELP) {
+ JMenuItem menuItemIC = new JMenuItem(
+ JMeterUtils.getResString("curl_import_menu"), KeyEvent.VK_UNDEFINED);
+ menuItemIC.setName(IMPORT_CURL);
+ menuItemIC.setActionCommand(IMPORT_CURL);
+ menuItemIC.setAccelerator(null);
+ menuItemIC.addActionListener(ActionRouter.getInstance());
+ return new JMenuItem[]{menuItemIC};
+ }
+ return new JMenuItem[0];
+ }
+
+ @Override
+ public JMenu[] getTopLevelMenus() {
+ return new JMenu[0];
+ }
+
+ @Override
+ public boolean localeChanged(MenuElement menu) {
+ return false;
+ }
+
+ @Override
+ public void localeChanged() {
+ // NOOP
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ statusText.setText("");
+ statusText.setForeground(Color.GREEN);
+ if(e.getActionCommand().equals(CREATE_REQUEST)) {
+ String curlCommand = cURLCommandTA.getText();
+ try {
+ LOGGER.info("Transforming CURL command {}", curlCommand);
+ BasicCurlParser basicCurlParser = new BasicCurlParser();
+ BasicCurlParser.Request request = basicCurlParser.parse(curlCommand);
+ LOGGER.info("Parsed CURL command {} into {}", curlCommand, request);
+ GuiPackage guiPackage = GuiPackage.getInstance();
+ guiPackage.updateCurrentNode();
+ createTestPlan(e, request);
+ statusText.setText(JMeterUtils.getResString("curl_create_success"));
+ } catch (Exception ex) {
+ LOGGER.error("Error creating test plan from cURL command:{}, error:{}", curlCommand, ex.getMessage(), ex);
+ statusText.setText(MessageFormat.format(JMeterUtils.getResString("curl_create_failure"), ex.getMessage()));
+ statusText.setForeground(Color.RED);
+ }
+ }
+ }
+}
Propchange: jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/gui/action/ParseCurlCommandAction.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/gui/action/ParseCurlCommandAction.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: jmeter/trunk/test/src/org/apache/jmeter/curl/BasicCurlParserTest.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/test/src/org/apache/jmeter/curl/BasicCurlParserTest.java?rev=1849285&view=auto
==============================================================================
--- jmeter/trunk/test/src/org/apache/jmeter/curl/BasicCurlParserTest.java (added)
+++ jmeter/trunk/test/src/org/apache/jmeter/curl/BasicCurlParserTest.java Wed Dec 19 09:54:42 2018
@@ -0,0 +1,98 @@
+/*
+ * 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.curl;
+
+import org.apache.jmeter.protocol.http.curl.BasicCurlParser;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @since 5.1
+ */
+public class BasicCurlParserTest {
+
+ /**
+ *
+ */
+ public BasicCurlParserTest() {
+ super();
+ }
+
+ @Test
+ public void testFFParsing() {
+ String cmdLine = "curl 'http://jmeter.apache.org/' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:63.0) Gecko/20100101 Firefox/63.0' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' -H 'Accept-Language: en-US,en;q=0.5' --compressed -H 'DNT: 1' -H 'Connection: keep-alive' -H 'Upgrade-Insecure-Requests: 1'";
+ BasicCurlParser basicCurlParser = new BasicCurlParser();
+ BasicCurlParser.Request request = basicCurlParser.parse(cmdLine);
+ Assert.assertEquals("http://jmeter.apache.org/", request.getUrl());
+ Assert.assertEquals(6, request.getHeaders().size());
+ Assert.assertTrue(request.isCompressed());
+ Assert.assertEquals("GET", request.getMethod());
+ }
+
+ @Test
+ public void testChromeParsing() {
+ String cmdLine = "curl 'https://jmeter.apache.org/' -H 'Proxy-Connection: keep-alive' -H 'Proxy-Authorization: Basic XXXXXXXXX/' -H 'Upgrade-Insecure-Requests: 1' -H 'User-Agent: Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Mobile Safari/537.36' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8' -H 'Accept-Encoding: gzip, deflate' -H 'Accept-Language: en-US,en;q=0.9,fr;q=0.8' --compressed";
+ BasicCurlParser basicCurlParser = new BasicCurlParser();
+ BasicCurlParser.Request request = basicCurlParser.parse(cmdLine);
+ Assert.assertEquals("https://jmeter.apache.org/", request.getUrl());
+ Assert.assertEquals(7, request.getHeaders().size());
+ Assert.assertTrue(request.isCompressed());
+ Assert.assertEquals("GET", request.getMethod());
+ }
+
+ @Test
+ public void testChromeParsingNotCompressed() {
+ String cmdLine = "curl 'https://jmeter.apache.org/' -H 'Proxy-Connection: keep-alive' -H 'Proxy-Authorization: Basic XXXXXXXXX/' -H 'Upgrade-Insecure-Requests: 1' -H 'User-Agent: Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Mobile Safari/537.36' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8' -H 'Accept-Encoding: gzip, deflate' -H 'Accept-Language: en-US,en;q=0.9,fr;q=0.8'";
+ BasicCurlParser basicCurlParser = new BasicCurlParser();
+ BasicCurlParser.Request request = basicCurlParser.parse(cmdLine);
+ Assert.assertEquals("https://jmeter.apache.org/", request.getUrl());
+ Assert.assertEquals(7, request.getHeaders().size());
+ Assert.assertFalse(request.isCompressed());
+ Assert.assertEquals("GET", request.getMethod());
+ }
+
+ @Test
+ public void testChromeParsingNoHeaders() {
+ String cmdLine = "curl 'https://jmeter.apache.org/'";
+ BasicCurlParser basicCurlParser = new BasicCurlParser();
+ BasicCurlParser.Request request = basicCurlParser.parse(cmdLine);
+ Assert.assertEquals("https://jmeter.apache.org/", request.getUrl());
+ Assert.assertTrue(request.getHeaders().isEmpty());
+ Assert.assertFalse(request.isCompressed());
+ Assert.assertEquals("GET", request.getMethod());
+ }
+
+ @Test
+ public void testPost() {
+ String cmdLine = "curl 'https://jmeter.apache.org/test' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:63.0) Gecko/20100101 Firefox/63.0' -H 'Accept: */*' -H 'Accept-Language: en-US,en;q=0.5' --compressed -H 'Referer: https://www.example.com/' -H 'content-type: application/json;charset=UTF-8' -H 'Origin: https://www.example.com' -H 'DNT: 1' -H 'Connection: keep-alive' -H 'TE: Trailers' --data '{\"abc\":\"123\",\"no\":\"matter on sunshine\"}'";
+ BasicCurlParser basicCurlParser = new BasicCurlParser();
+ BasicCurlParser.Request request = basicCurlParser.parse(cmdLine);
+ Assert.assertEquals("https://jmeter.apache.org/test", request.getUrl());
+ Assert.assertEquals(9, request.getHeaders().size());
+ Assert.assertTrue(request.isCompressed());
+ Assert.assertEquals("POST", request.getMethod());
+ }
+
+ @Test(expected=IllegalArgumentException.class)
+ public void testError() {
+ String cmdLine = "curl 'https://jmeter.apache.org/' -u -H 'Proxy-Connection: keep-alive' -H 'Proxy-Authorization: Basic XXXXXXXXX/' -H 'Upgrade-Insecure-Requests: 1' -H 'User-Agent: Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Mobile Safari/537.36' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8' -H 'Accept-Encoding: gzip, deflate' -H 'Accept-Language: en-US,en;q=0.9,fr;q=0.8'";
+ BasicCurlParser basicCurlParser = new BasicCurlParser();
+ basicCurlParser.parse(cmdLine);
+ }
+}
Propchange: jmeter/trunk/test/src/org/apache/jmeter/curl/BasicCurlParserTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jmeter/trunk/test/src/org/apache/jmeter/curl/BasicCurlParserTest.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: jmeter/trunk/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/changes.xml?rev=1849285&r1=1849284&r2=1849285&view=diff
==============================================================================
--- jmeter/trunk/xdocs/changes.xml [utf-8] (original)
+++ jmeter/trunk/xdocs/changes.xml [utf-8] Wed Dec 19 09:54:42 2018
@@ -117,16 +117,17 @@ of previous time slot as a base. Startin
<h3>General</h3>
<ul>
- <li><pr>394</pr>Allow <code>null</code> values in <code>FieldStringEditor</code>. Based on patch by Mingun (alexander_sergey at mail.ru)</li>
- <li><bug>62826</bug>When changing LAF, make JMeter restart if user clicks yes to popup</li>
- <li><bug>62744</bug>Upgrade jquery to version 3.3.1, jquery-ui to 1.12.1, bootstrap to 3.3.7</li>
- <li><bug>62257</bug><pr>401</pr>Expand/Collapse short key <keysym>-</keysym> (minus sign) on numpad doesn't work. Contributed by Ori Marko (orimarko at gmail.com)</li>
- <li><bug>62752</bug>Add to Documentation: <code>ctx.getThreadNum()</code> is zero-based while <code>${__threadNum}</code> is one-based</li>
- <li><pr>411</pr>Use <code>SHA-1</code> instead of <code>SHA1</code> in <code>org.apache.jmeter.save.SaveService</code>. Contributed by Paco (paco.xu at daocloud.io)</li>
- <li><bug>62914</bug>Add a hint in Thread Group UI about duration of test</li>
- <li><bug>62925</bug>Add support for ThreadDump to the JMeter non-GUI</li>
- <li><bug>62870</bug>Templates : Add ability to provide parameters. Contributed by Ubik Load Pack (support at ubikloadpack.com)</li>
- <li><bug>62829</bug>Allow specifying Proxy server scheme for HTTP request sampler, Advanced tab and command line option. Contributed by Hitesh Patel (hitesh.h.patel at gmail.com)</li>
+ <li><bug>62959</bug>Ability to create a Test plan from a cURL command. Contributed by Ubik Load Pack (support at ubikloadpack.com)</li>
+ <li><pr>394</pr>Allow <code>null</code> values in <code>FieldStringEditor</code>. Based on patch by Mingun (alexander_sergey at mail.ru)</li>
+ <li><bug>62826</bug>When changing LAF, make JMeter restart if user clicks yes to popup</li>
+ <li><bug>62744</bug>Upgrade jquery to version 3.3.1, jquery-ui to 1.12.1, bootstrap to 3.3.7</li>
+ <li><bug>62257</bug><pr>401</pr>Expand/Collapse short key <keysym>-</keysym> (minus sign) on numpad doesn't work. Contributed by Ori Marko (orimarko at gmail.com)</li>
+ <li><bug>62752</bug>Add to Documentation: <code>ctx.getThreadNum()</code> is zero-based while <code>${__threadNum}</code> is one-based</li>
+ <li><pr>411</pr>Use <code>SHA-1</code> instead of <code>SHA1</code> in <code>org.apache.jmeter.save.SaveService</code>. Contributed by Paco (paco.xu at daocloud.io)</li>
+ <li><bug>62914</bug>Add a hint in Thread Group UI about duration of test</li>
+ <li><bug>62925</bug>Add support for ThreadDump to the JMeter non-GUI</li>
+ <li><bug>62870</bug>Templates : Add ability to provide parameters. Contributed by Ubik Load Pack (support at ubikloadpack.com)</li>
+ <li><bug>62829</bug>Allow specifying Proxy server scheme for HTTP request sampler, Advanced tab and command line option. Contributed by Hitesh Patel (hitesh.h.patel at gmail.com)</li>
</ul>
<ch_section>Non-functional changes</ch_section>