From 4fe05e3764786355c7f698d4b439abb53e3acb02 Mon Sep 17 00:00:00 2001 From: Philippe Mouawad Date: Sat, 29 Jun 2013 20:08:15 +0000 Subject: [PATCH] Bug 55085 - UX Improvement : Ability to create New Test Plan from Templates Bugzilla Id: 55085 git-svn-id: https://svn.apache.org/repos/asf/jmeter/trunk@1498018 13f79535-47bb-0310-9956-ffa450edef68 Former-commit-id: f184d4a74d64018466fe8bf0d9f2fd168d0b3323 --- bin/jmeter.properties | 6 +- bin/templates/jdbc.jmx | 93 ++++++++ bin/templates/recording.jmx | 158 +++++++++++++ bin/templates/templates.xml | 53 +++++ .../apache/jmeter/gui/action/ActionNames.java | 1 + .../gui/action/SelectTemplateDialog.java | 222 ++++++++++++++++++ .../jmeter/gui/action/TemplateCommand.java | 54 +++++ .../jmeter/gui/action/template/Template.java | 65 +++++ .../gui/action/template/TemplateManager.java | 140 +++++++++++ .../apache/jmeter/gui/util/JMeterMenuBar.java | 6 + .../jmeter/resources/messages.properties | 4 + .../jmeter/resources/messages_fr.properties | 4 + xdocs/changes.xml | 1 + 13 files changed, 806 insertions(+), 1 deletion(-) create mode 100644 bin/templates/jdbc.jmx create mode 100644 bin/templates/recording.jmx create mode 100644 bin/templates/templates.xml create mode 100644 src/core/org/apache/jmeter/gui/action/SelectTemplateDialog.java create mode 100644 src/core/org/apache/jmeter/gui/action/TemplateCommand.java create mode 100644 src/core/org/apache/jmeter/gui/action/template/Template.java create mode 100644 src/core/org/apache/jmeter/gui/action/template/TemplateManager.java diff --git a/bin/jmeter.properties b/bin/jmeter.properties index 14fed36ded..acaf1912d6 100644 --- a/bin/jmeter.properties +++ b/bin/jmeter.properties @@ -935,4 +935,8 @@ user.properties=user.properties # Should JMeter automatically load additional system properties? # File name to look for (comment to disable) -system.properties=system.properties \ No newline at end of file +system.properties=system.properties + +# Comma separated list of files that contain reference to templates and their description +# Path must be relative to jmeter root folder +#template.files=/bin/templates/templates.xml \ No newline at end of file diff --git a/bin/templates/jdbc.jmx b/bin/templates/jdbc.jmx new file mode 100644 index 0000000000..0ca8a700b5 --- /dev/null +++ b/bin/templates/jdbc.jmx @@ -0,0 +1,93 @@ + + + + + + false + false + + + + + + + + true + Select 1 + 5000 + jdbcConfig + jdbc:postgresql://hostname:port/dbname + org.postgresql.Driver + true + password + 10 + 10000 + DEFAULT + 60000 + username + + + + continue + + false + 1 + + 1 + 1 + 1370729701000 + 1370729701000 + false + + + + + + jdbcConfig + select column1 from table + + + Select Statement + + col1 + + + + + false + + saveConfig + + + true + true + true + + true + true + true + false + false + true + false + false + false + false + true + false + false + true + true + 0 + true + true + true + true + + + + + + + + diff --git a/bin/templates/recording.jmx b/bin/templates/recording.jmx new file mode 100644 index 0000000000..7c713abb9f --- /dev/null +++ b/bin/templates/recording.jmx @@ -0,0 +1,158 @@ + + + + + + false + false + + + + + + + + + + + + + + + + + + + + + + 4 + + + + + true + + + + continue + + false + 1 + + 1 + 1 + 1370726934000 + 1370726934000 + false + + + + + + + + + false + + saveConfig + + + true + true + true + + true + true + true + false + false + true + false + false + false + false + true + false + false + true + true + 0 + true + true + true + true + + + + + + + + true + + + + 8888 + + .*\.jpg + .*\.js + .*\.png + .*\.gif + .*\.bmp + .*\.swf + .*\.css + + + true + 4 + false + + false + true + true + false + true + + + + + + false + + saveConfig + + + true + true + true + + true + true + true + false + false + true + false + false + false + false + true + false + false + true + true + 0 + true + true + true + true + + + + + + + + + diff --git a/bin/templates/templates.xml b/bin/templates/templates.xml new file mode 100644 index 0000000000..2c2b5f1ea6 --- /dev/null +++ b/bin/templates/templates.xml @@ -0,0 +1,53 @@ + + + + \ No newline at end of file diff --git a/src/core/org/apache/jmeter/gui/action/ActionNames.java b/src/core/org/apache/jmeter/gui/action/ActionNames.java index fd02ae45a2..1f0132c2ff 100644 --- a/src/core/org/apache/jmeter/gui/action/ActionNames.java +++ b/src/core/org/apache/jmeter/gui/action/ActionNames.java @@ -62,6 +62,7 @@ public final class ActionNames { public static final String MERGE = "merge"; // $NON-NLS-1$ public static final String OPEN = "open"; // $NON-NLS-1$ public static final String OPEN_RECENT = "open_recent"; // $NON-NLS-1$ + public static final String CREATE_FROM_TEMPLATE = "create_from_template"; // $NON-NLS-1$ public static final String PASTE = "Paste"; // $NON-NLS-1$ public static final String REMOTE_EXIT = "remote_exit"; // $NON-NLS-1$ public static final String REMOTE_EXIT_ALL = "remote_exit_all"; // $NON-NLS-1$ diff --git a/src/core/org/apache/jmeter/gui/action/SelectTemplateDialog.java b/src/core/org/apache/jmeter/gui/action/SelectTemplateDialog.java new file mode 100644 index 0000000000..d92865c407 --- /dev/null +++ b/src/core/org/apache/jmeter/gui/action/SelectTemplateDialog.java @@ -0,0 +1,222 @@ +/* + * 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.gui.action; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Set; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.ActionMap; +import javax.swing.InputMap; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JRootPane; +import javax.swing.JScrollPane; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import org.apache.commons.io.IOUtils; +import org.apache.jmeter.gui.action.template.Template; +import org.apache.jmeter.gui.action.template.TemplateManager; +import org.apache.jmeter.swing.HtmlPane; +import org.apache.jmeter.util.JMeterUtils; +import org.apache.jorphan.gui.ComponentUtil; +import org.apache.jorphan.gui.JLabeledChoice; +import org.apache.jorphan.logging.LoggingManager; +import org.apache.jorphan.util.JOrphanUtils; +import org.apache.log.Logger; + +/** + * Dialog used for Templates selection + * @since 2.10 + */ +public class SelectTemplateDialog extends JDialog implements ChangeListener, ActionListener { + /** + * + */ + private static final long serialVersionUID = -4436834972710248247L; + + private static final Logger log = LoggingManager.getLoggerForClass(); + + private JLabeledChoice templateList; + + private HtmlPane helpDoc = new HtmlPane(); + + private JButton createFromTemplateButton; + + private JButton cancelButton; + + private JScrollPane scroller = new JScrollPane(helpDoc); + + public SelectTemplateDialog() { + super((JFrame) null, JMeterUtils.getResString("template_title"), true); //$NON-NLS-1$ + init(); + } + + @Override + protected JRootPane createRootPane() { + JRootPane rootPane = new JRootPane(); + // Hide Window on ESC + Action escapeAction = new AbstractAction("ESCAPE") { //$NON-NLS-1$ + /** + * + */ + private static final long serialVersionUID = -6543764044868772971L; + + @Override + public void actionPerformed(ActionEvent actionEvent) { + setVisible(false); + } + }; + // Do search on Enter + Action enterAction = new AbstractAction("ENTER") { //$NON-NLS-1$ + /** + * + */ + private static final long serialVersionUID = -3661361497864527363L; + + @Override + public void actionPerformed(ActionEvent actionEvent) { + doOpen(actionEvent); + } + }; + ActionMap actionMap = rootPane.getActionMap(); + actionMap.put(escapeAction.getValue(Action.NAME), escapeAction); + actionMap.put(enterAction.getValue(Action.NAME), enterAction); + InputMap inputMap = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); + inputMap.put(KeyStrokes.ESC, escapeAction.getValue(Action.NAME)); + inputMap.put(KeyStrokes.ENTER, enterAction.getValue(Action.NAME)); + + return rootPane; + } + + private void init() { + initializeTemplateList(); + this.getContentPane().setLayout(new BorderLayout(10, 10)); + JPanel comboPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); + comboPanel.add(templateList); + this.getContentPane().add(comboPanel, BorderLayout.NORTH); + helpDoc.setContentType("text/html"); //$NON-NLS-1$ + helpDoc.setEditable(false); + fillDescription(); + JPanel jPanel = new JPanel(new GridLayout(1,1)); + scroller.setPreferredSize(new Dimension(300, 400)); + jPanel.setPreferredSize(new Dimension(310, 410)); + jPanel.add(scroller); + this.getContentPane().add(jPanel, BorderLayout.CENTER); + + JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); + + createFromTemplateButton = new JButton(JMeterUtils.getResString("template_create_from")); //$NON-NLS-1$ + createFromTemplateButton.addActionListener(this); + + cancelButton = new JButton(JMeterUtils.getResString("cancel")); //$NON-NLS-1$ + cancelButton.addActionListener(this); + buttonsPanel.add(createFromTemplateButton); + buttonsPanel.add(cancelButton); + this.getContentPane().add(buttonsPanel, BorderLayout.SOUTH); + + this.pack(); + ComponentUtil.centerComponentInWindow(this); + } + + private void initializeTemplateList() { + Set templatesAsSet = TemplateManager.getInstance().getTemplateNames(); + String[] templateNames = templatesAsSet.toArray(new String[templatesAsSet.size()]); + Arrays.sort(templateNames, new Comparator() { + @Override + public int compare(String o1, String o2) { + return o1.compareToIgnoreCase(o2); + } + }); + templateList = new JLabeledChoice(JMeterUtils.getResString("template_choose"), templateNames); //$NON-NLS-1$ + templateList.addChangeListener(this); + } + + /** + * Do search + * @param e {@link ActionEvent} + */ + @Override + public void actionPerformed(ActionEvent e) { + if(e.getSource()==cancelButton) { + this.setVisible(false); + return; + } + doOpen(e); + } + + @Override + public void stateChanged(ChangeEvent event) { + fillDescription(); + } + + /** + * + */ + protected void fillDescription() { + String selectedTemplate = templateList.getText(); + Template template = TemplateManager.getInstance().getTemplateByName(selectedTemplate); + helpDoc.setText(template.getDescription()); + } + + /** + * @param e {@link ActionEvent} + */ + private void doOpen(ActionEvent e) { + InputStream inputStream = null; + OutputStream outputStream = null; + try { + String selectedTemplate = templateList.getText(); + Template template = TemplateManager.getInstance().getTemplateByName(selectedTemplate); + File fileToCopy = new File(JMeterUtils.getJMeterHome(), template.getFileName()); + File targetFile = new File( System.getProperty("user.dir"), + template.getFileName().substring(template.getFileName().lastIndexOf("/"))); + inputStream = new BufferedInputStream(new FileInputStream(fileToCopy)); + outputStream = new BufferedOutputStream(new FileOutputStream(targetFile)); + IOUtils.copy(inputStream, outputStream); + outputStream.close(); + Load.loadProjectFile(e, targetFile, false); + this.setVisible(false); + } catch (Exception e1) { + throw new Error(e1); + } finally { + JOrphanUtils.closeQuietly(inputStream); + JOrphanUtils.closeQuietly(outputStream); + } + } +} \ No newline at end of file diff --git a/src/core/org/apache/jmeter/gui/action/TemplateCommand.java b/src/core/org/apache/jmeter/gui/action/TemplateCommand.java new file mode 100644 index 0000000000..dee7cdfe12 --- /dev/null +++ b/src/core/org/apache/jmeter/gui/action/TemplateCommand.java @@ -0,0 +1,54 @@ +/* + * 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.gui.action; + +import java.awt.event.ActionEvent; +import java.util.HashSet; +import java.util.Set; + +/** + * Open Templates + * @since 2.10 + */ +public class TemplateCommand extends AbstractAction { + + private static final Set commands = new HashSet(); + + static { + commands.add(ActionNames.CREATE_FROM_TEMPLATE); + } + + private SelectTemplateDialog dialog = new SelectTemplateDialog(); + /** + * @see Command#doAction(ActionEvent) + */ + @Override + public void doAction(ActionEvent e) { + dialog.setVisible(true); + } + + + /** + * @see Command#getActionNames() + */ + @Override + public Set getActionNames() { + return commands; + } +} diff --git a/src/core/org/apache/jmeter/gui/action/template/Template.java b/src/core/org/apache/jmeter/gui/action/template/Template.java new file mode 100644 index 0000000000..f1f11b21ba --- /dev/null +++ b/src/core/org/apache/jmeter/gui/action/template/Template.java @@ -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.gui.action.template; + +/** + * Template Bean + * @since 2.10 + */ +public class Template { + private String name; + private String fileName; + private String description; + /** + * @return the name + */ + public String getName() { + return name; + } + /** + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } + /** + * @return the relativeFileName + */ + public String getFileName() { + return fileName; + } + /** + * @param relativeFileName the relativeFileName to set + */ + public void setFileName(String relativeFileName) { + fileName = relativeFileName; + } + /** + * @return the description + */ + public String getDescription() { + return description; + } + /** + * @param description the description to set + */ + public void setDescription(String description) { + this.description = description; + } +} \ No newline at end of file diff --git a/src/core/org/apache/jmeter/gui/action/template/TemplateManager.java b/src/core/org/apache/jmeter/gui/action/template/TemplateManager.java new file mode 100644 index 0000000000..aa15904098 --- /dev/null +++ b/src/core/org/apache/jmeter/gui/action/template/TemplateManager.java @@ -0,0 +1,140 @@ +/* + * 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.gui.action.template; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang3.StringUtils; +import org.apache.jmeter.util.JMeterUtils; +import org.apache.jorphan.logging.LoggingManager; +import org.apache.jorphan.util.JOrphanUtils; +import org.apache.log.Logger; + +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.io.xml.DomDriver; + +/** + * Manages Test Plan templates + * @since 2.10 + */ +public class TemplateManager { + private class Templates { + private Map templates = new HashMap(); + } + private static final String TEMPLATE_FILES = JMeterUtils.getPropDefault("template.files", // $NON-NLS-1$ + "/bin/templates/templates.xml"); + + private static final Logger log = LoggingManager.getLoggerForClass(); + + private static final TemplateManager SINGLETON = new TemplateManager(); + + private Map templates = new HashMap(); + + private XStream xstream = initXStream(); + + /** + * + * @return + */ + public static final TemplateManager getInstance() { + return SINGLETON; + } + + private TemplateManager() { + try { + templates = readTemplates(); + } catch(IOException e) { + log.error("Error loading templates from files referenced in templates.files property:"+ + TEMPLATE_FILES, e); + } + } + + private XStream initXStream() { + XStream xstream = new XStream(new DomDriver()); + xstream.alias("template", Template.class); + xstream.alias("templates", Templates.class); + + // templates i + xstream.addImplicitMap(Templates.class, + // field TemplateManager#templates + "templates", // $NON-NLS-1$ + Template.class, + // field Template#name + "name" // $NON-NLS-1$ + ); + + return xstream; + } + + public void addTemplate(Template template) { + templates.put(template.getName(), template); + } + + /** + * @return Set the templates names + */ + public Set getTemplateNames() { + return templates.keySet(); + } + + + private Map readTemplates() throws FileNotFoundException { + Map templates = new HashMap(); + + String[] templateFiles = TEMPLATE_FILES.split(","); + for (int i = 0; i < templateFiles.length; i++) { + if(!StringUtils.isEmpty(templateFiles[i])) { + InputStream inputStream = null; + File f = new File(JMeterUtils.getJMeterHome(), + templateFiles[i]); + try { + if(f.exists() && f.canRead()) { + log.info("Reading templates from:"+f.getAbsolutePath()); + inputStream = new BufferedInputStream(new FileInputStream(f)); + + templates.putAll(((Templates) xstream.fromXML(inputStream)).templates); + } else { + log.warn("Ignoring template file:'"+f.getAbsolutePath()+"' as it does not exist or is not readable"); + } + } catch(Exception ex) { + log.warn("Ignoring template file:'"+f.getAbsolutePath()+"', an error occured parsing the file", ex); + } finally { + JOrphanUtils.closeQuietly(inputStream); + } + } + } + return templates; + } + + /** + * @param selectedTemplate Template name + * @return {@link Template} + */ + public Template getTemplateByName(String selectedTemplate) { + return templates.get(selectedTemplate); + } +} diff --git a/src/core/org/apache/jmeter/gui/util/JMeterMenuBar.java b/src/core/org/apache/jmeter/gui/util/JMeterMenuBar.java index 9d460ed370..855fdd7d48 100644 --- a/src/core/org/apache/jmeter/gui/util/JMeterMenuBar.java +++ b/src/core/org/apache/jmeter/gui/util/JMeterMenuBar.java @@ -66,6 +66,8 @@ public class JMeterMenuBar extends JMenuBar implements LocaleChangeListener { private JMenuItem file_load; + private JMenuItem create_from_template; + private List file_load_recent_files; private JMenuItem file_merge; @@ -460,6 +462,9 @@ public class JMeterMenuBar extends JMenuBar implements LocaleChangeListener { // is selected is ROOT, which does not allow items to be inserted. file_load.setEnabled(false); + create_from_template = makeMenuItemRes("create_from_template", 'T', ActionNames.CREATE_FROM_TEMPLATE); //$NON-NLS-1$ + create_from_template.setEnabled(true); + file_close = makeMenuItemRes("menu_close", 'C', ActionNames.CLOSE, KeyStrokes.CLOSE); //$NON-NLS-1$ file_exit = makeMenuItemRes("exit", 'X', ActionNames.EXIT, KeyStrokes.EXIT); //$NON-NLS-1$ @@ -473,6 +478,7 @@ public class JMeterMenuBar extends JMenuBar implements LocaleChangeListener { fileMenu.add(file_close); fileMenu.add(file_load); + fileMenu.add(create_from_template); fileMenu.add(file_merge); fileMenu.addSeparator(); fileMenu.add(file_save); diff --git a/src/core/org/apache/jmeter/resources/messages.properties b/src/core/org/apache/jmeter/resources/messages.properties index 12aca6ca8b..e0b7e85936 100644 --- a/src/core/org/apache/jmeter/resources/messages.properties +++ b/src/core/org/apache/jmeter/resources/messages.properties @@ -206,6 +206,7 @@ counter_config_title=Counter counter_per_user=Track counter independently for each user counter_reset_per_tg_iteration=Reset counter on each Thread Group Iteration countlim=Size limit +create_from_template=New from templates csvread_file_file_name=CSV file to get values from | *alias cut=Cut cut_paste_function=Copy and paste function string @@ -1042,7 +1043,10 @@ tcp_request_data=Text to send tcp_sample_title=TCP Sampler tcp_timeout=Timeout (milliseconds)\: teardown_on_shutdown=Run tearDown Thread Groups after shutdown of main threads +template_choose=Select Template +template_create_from=Create template_field=Template\: +template_title=Create from Template test=Test test_action_action=Action test_action_duration=Duration (milliseconds) diff --git a/src/core/org/apache/jmeter/resources/messages_fr.properties b/src/core/org/apache/jmeter/resources/messages_fr.properties index f1a2bf642c..d589568756 100644 --- a/src/core/org/apache/jmeter/resources/messages_fr.properties +++ b/src/core/org/apache/jmeter/resources/messages_fr.properties @@ -194,6 +194,7 @@ counter_config_title=Compteur counter_per_user=Suivre le compteur ind\u00E9pendamment pour chaque unit\u00E9 de test counter_reset_per_tg_iteration=R\u00E9initialiser le compteur \u00E0 chaque it\u00E9ration du groupe d'unit\u00E9s countlim=Limiter le nombre d'\u00E9l\u00E9ments retourn\u00E9s \u00E0 +create_from_template=Mod\u00E8les cssjquery_attribute=Attribut cssjquery_impl=Impl\u00E9mentation CSS/JQuery\: cssjquery_render_no_text=Les donn\u00E9es de r\u00E9ponse ne sont pas du texte. @@ -1035,7 +1036,10 @@ tcp_request_data=Texte \u00E0 envoyer \: tcp_sample_title=Requ\u00EAte TCP tcp_timeout=Expiration (millisecondes) \: teardown_on_shutdown=Ex\u00E9cuter le Groupe d'unit\u00E9s de fin m\u00EAme apr\u00E8s un arr\u00EAt manuel des Groupes d'unit\u00E9s principaux +template_choose=Choisir le mod\u00E8le +template_create_from=Cr\u00E9er template_field=Canevas \: +template_title=Cr\u00E9er \u00E0 partir du mod\u00E8le test=Test test_action_action=Action \: test_action_duration=Dur\u00E9e (millisecondes) \: diff --git a/xdocs/changes.xml b/xdocs/changes.xml index e99e4658b7..155c4f7602 100644 --- a/xdocs/changes.xml +++ b/xdocs/changes.xml @@ -217,6 +217,7 @@ Transaction Controller now sets Response Code of Generated Parent Sampler (if Ge
  • 54864 - Enable multi selection drag & drop in the tree without having to start dragging before releasing Shift or Control
  • 54945 - Add Shutdown Hook to enable trapping kill or CTRL+C signals
  • 54990 - Download large files avoiding outOfMemory
  • +
  • 55085 - UX Improvement : Ability to create New Test Plan from Templates
  • Non-functional changes