diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..20ea5d9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +# binaries +dependency-reduced-pom.xml +target + +# eclipse +.classpath +.project +.settings/ + +# linux +*~ +\#*# diff --git a/LICENCE b/LICENCE new file mode 100644 index 0000000..b4bd858 --- /dev/null +++ b/LICENCE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2014 University Joseph Fourier, LIG Laboratory, ERODS Team + + 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. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..12a1e2c --- /dev/null +++ b/README.md @@ -0,0 +1,185 @@ +mqttws-jmeter +=========== + +Jmeter MQTT sampler with support for websockets + +Initially a fork of https://github.com/tuanhiep/mqtt-jmeter by +Tuan Hiep, ERODS Team, LIG- Grenoble-France + + +# Introduction + +The MQTTWS Plugin in Jmeter is used for the injection testing of MQTT brokers. +It uses a paho based client that supports MQTT over tcp and websockets. + + +# How to install MQTT plugin in Jmeter + +From the repository: https://github.com/winglet/mqtt-jmeter +Get the source code, go to mqtt-jemeter folder and and use the command maven in terminal (Ubuntu): + + mvn clean install package + +You also need to build (TODO) + +to obtain the file **mqtt-jmeter.jar** in **mqtt-jemeter/target**. +Put the **mqtt-jemeter.jar** in the folder **lib/ext** of Jmeter +(to be downloaded on http://jmeter.apache.org/download_jmeter.cgi ). + +Remind that, it's necessary to update the file **ApacheJMeter_core.jar** in the repository lib/ext of Jmeter. +Update the file messages.properties in the folder :/org/apache/jmeter/resources/ +in **ApacheJMeter_core.jar** by new file messages.properties from +https://github.com/tuanhiep/mqtt-jmeter/tree/master/ressource + +# How to use MQTT plugin in Jmeter + +## MQTT Publisher + +The interface graphic of Jmeter: + +![Alt text](images/Main_Interface_Jmeter.png) + +Right-click “Thread” and choose : Add → Sampler → MQTT Publisher + +![Alt text](images/MQTT_Publisher.png) + +In the principal interface of MQTT Publisher we have the fields: +*Connection Info* + +**Name:** Name of the MQTT Publisher +**Comments:** Your comments +**Provider URL:** the address of MQTT server example: tcp://localhost:1883 +**Client Id:** Your Id in the session with MQTT server example: Noel De Palma +**List Topic:** The list of topic's names you want to publish to +The topic's names are separated by a comma "," +For example: List Topic: GRENOBLE/LIG,GRENOBLE/UJF-LIG +This means, you'll publish to 2 topics: GRENOBLE/LIG and GRENOBLE/UJF-LIG +You can choose the option **One connection per topic** : It means that for each topic in the list above, the plugin will create one correspondant + connection. Note that, if the client Id is "Noel De Palma", for example, and you have 2 topics in the list, so the plugin will create 2 connections with 2 Client +Id : "Noel De Palma 0" and "Noel De Palma 1" +The plugin provide two strategies to publish: + **1: Round Robin** : You'll publish to the topics in equal portions and in circular order + **2: Random** : You'll publish to a random topic in the list above +If the list of topic has only one topic, so regardless the strategies, you'll publish to the topic for sure. + **Use Authorization check box:** Necessary in the case the connection needs the username and +password +**User:** Your username +**Password:** Your password +**Number of samples to aggregate:** In other way, the number of messages you want to publish to +the MQTT sever in this MQTT Publisher thread, with the value like the configuration below. +**Message Type:** You can choose : Text, Generated Value, Fixed Value, Random Byte Array (more detail below) + +![Alt text](images/Publisher_Text.png) + +*Encoding* + +**Message Format** : The type of encoding that you'll encode your data before publish .You can choose Binary Codec, Base64, BinHex or Plain Text +If you choose Plain Text, you can choose 6 types of charsets : UTF-8, UTF-16, US-ASCII,UTF-16LE, UTF-16BE, ISO-8859-1. +Of course, you can choose to no encoding too. + +*Option* + +**Add TimeStamp check box:** Add the timestamps to the message. The timestamps is 8 bytes +**Add Number Sequence check box:** Add the number sequence to the message. Example: if you +publish 100 messages in your session, the message is numbered from 0 to 99. The number sequence +field in the message is 4 bytes. +**Retained check box:** You publish the messages as retained messages or not. The retain flag for an +MQTT message is set to false by default. This means that a broker will not hold onto the message +so that any subscribers arriving after the message was sent will not see the message. By setting +the retain flag, the message is held onto by the broker, so when the late arrivers connect to the +broker or clients create a new subscription they get all the relevant retained messages” +**Quality of service:** Three levels: +0 : At most once +1 : At least once +2 : Exactly once +Each message in MQTT can have its quality of service and retain flag set. The quality of service +advises the code if and how it should ensure the message arrives. There are three options, 0 (At Most Once), +1 (At Least Once) and 2 (Exactly Once). By default, a new message instance is set to "At Least Once",a Quality +of Service (QoS) of 1, which means the sender will deliver the message at least once and, if there's no acknowledgement + of it, it will keep sending it with a duplicate flag set until an acknowledgement turns up, at which point the +client removes the message from its persisted set of messages. +A QoS of 0, "At Most Once", is the fastest mode, where the client doesn't wait for an +acknowledgement. This means, of course, that if there’s a disconnection or server failure, a message +may be lost. At the other end of the scale is a QoS of 2, "Exactly Once", which uses two pairs of +exchanges, first to transfer the message and then to ensure only one copy has been received and is +being processed. This does make Exactly Once the slower but most reliable QoS setting. + +With MQTT Publisher in Jmeter, three type of messages can be sent (Message Type): +**Text:** The text message, without flag header and the server MQTT can deliver it like a normal +text if you choose *No Encoding* or *Plain Text*. + +![Alt text](images/Publisher_Text.png) + +![Alt text](images/Receive.png) + +1 byte “flag header” for the messages of type: Generated value, Fixed value + +![Alt text](images/Flag_Header.png) +In the flag header, if one field is set to 1, it means, we use the header in the message. +For example: With this flag header + +![Alt text](images/Flag_Header_Example.png) +It means that, in the message, we have : +![Alt text](images/Message.png) + +**Generated Value:** +The generated value can be of type: Integer, Long, Float, Double within the range [Min,Max] . +The type of random can be: Pseudo random or Secure random. In the two cases, we can set the Seed +for the generator. + +![Alt text](images/Publisher_generated_value.png) + +**Fixed Value:** +The fixed value can be of type: Integer, Long, Float, Double, String within the range [Min,Max]. + +![Alt text](images/Publisher_fixed_value.png) +**Random Byte Array:** + +The data in form of random byte array with the size array as an input. +For example, if you type 9 in the field size array, so without encoding, time header, number sequence, the message has 9 bytes of content(random data) and 1 byte of flag header +and so, 10 bytes to publish. +The images below show when you publish with option : One Connection Per Topic and the data is type of Random Byte Array. +In the terminal,you see that there are two connections of 2 client Id : "Didier Donsez 0" and "Didier Donsez 1" + +![Alt text](images/One_connection_per_topic.png) + +![Alt text](images/Random_Byte_Array.png) + + +For mesuring, thanks to Jmeter, we can add some listeners: + +![Alt text](images/Publisher_result.png) + +## MQTT Subscriber + + +![Alt text](images/MQTT_Subscriber.png) + + + +*Name:* Name of the MQTT Subscriber +*Comments:* Your comments +*Provider URL:* The address of MQTT server +*Client Id:* Your Id in the session +*Topic:* The topic you want to subscribe. +*Use Authorization :* Necessary in the case the connection need username and password +*User:* your username +*Password:* your password +*Number of samples to aggregate:* In other way, the number of message you want to receive from +the topic in one session +*Time out (milliseconds):* Timeout for the connection to receive message from the topic + +![Alt text](images/Subscriber_result.png) + + +![Alt text](images/Publisher_Subscriber.png) + + + + Grenoble, France 14/03/2014, + + ERODS Team + + http://www.liglab.fr/erods?lang=fr&var_mode=calcul + + diff --git a/images/Flag_Header.png b/images/Flag_Header.png new file mode 100644 index 0000000..d7031c7 Binary files /dev/null and b/images/Flag_Header.png differ diff --git a/images/Flag_Header_Example.png b/images/Flag_Header_Example.png new file mode 100644 index 0000000..3263864 Binary files /dev/null and b/images/Flag_Header_Example.png differ diff --git a/images/MQTT_Publisher.png b/images/MQTT_Publisher.png new file mode 100644 index 0000000..396de6e Binary files /dev/null and b/images/MQTT_Publisher.png differ diff --git a/images/MQTT_Subscriber.png b/images/MQTT_Subscriber.png new file mode 100644 index 0000000..6211e19 Binary files /dev/null and b/images/MQTT_Subscriber.png differ diff --git a/images/Main_Interface_Jmeter.png b/images/Main_Interface_Jmeter.png new file mode 100644 index 0000000..9172dad Binary files /dev/null and b/images/Main_Interface_Jmeter.png differ diff --git a/images/Message.png b/images/Message.png new file mode 100644 index 0000000..b1fbd8c Binary files /dev/null and b/images/Message.png differ diff --git a/images/One_connection_per_topic.png b/images/One_connection_per_topic.png new file mode 100644 index 0000000..240efdf Binary files /dev/null and b/images/One_connection_per_topic.png differ diff --git a/images/Publisher_Subscriber.png b/images/Publisher_Subscriber.png new file mode 100644 index 0000000..ec64e8b Binary files /dev/null and b/images/Publisher_Subscriber.png differ diff --git a/images/Publisher_Text.png b/images/Publisher_Text.png new file mode 100644 index 0000000..fffad13 Binary files /dev/null and b/images/Publisher_Text.png differ diff --git a/images/Publisher_fixed_value.png b/images/Publisher_fixed_value.png new file mode 100644 index 0000000..836c5e8 Binary files /dev/null and b/images/Publisher_fixed_value.png differ diff --git a/images/Publisher_generated_value.png b/images/Publisher_generated_value.png new file mode 100644 index 0000000..946210b Binary files /dev/null and b/images/Publisher_generated_value.png differ diff --git a/images/Publisher_result.png b/images/Publisher_result.png new file mode 100644 index 0000000..f8feede Binary files /dev/null and b/images/Publisher_result.png differ diff --git a/images/Random_Byte_Array.png b/images/Random_Byte_Array.png new file mode 100644 index 0000000..64eef3a Binary files /dev/null and b/images/Random_Byte_Array.png differ diff --git a/images/Receive.png b/images/Receive.png new file mode 100644 index 0000000..e660dc7 Binary files /dev/null and b/images/Receive.png differ diff --git a/images/Subscriber_result.png b/images/Subscriber_result.png new file mode 100644 index 0000000..55e588f Binary files /dev/null and b/images/Subscriber_result.png differ diff --git a/libs/mqtt-websocket-java-1.0.1.jar b/libs/mqtt-websocket-java-1.0.1.jar new file mode 100644 index 0000000..3541284 Binary files /dev/null and b/libs/mqtt-websocket-java-1.0.1.jar differ diff --git a/libs/org.eclipse.paho.client.mqttv3-1.0.0.jar b/libs/org.eclipse.paho.client.mqttv3-1.0.0.jar new file mode 100644 index 0000000..79e4413 Binary files /dev/null and b/libs/org.eclipse.paho.client.mqttv3-1.0.0.jar differ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..ce94d46 --- /dev/null +++ b/pom.xml @@ -0,0 +1,90 @@ + + + + 4.0.0 + + winglet.jmeter.mqttws + mqttws-jmeter + 0.0.1-SNAPSHOT + Apache JMeter :: MQTT WS Sampler + MQTT Sampler with WebSockets support for Apache JMeter + + + 2.10 + + + + + org.apache.jmeter + ApacheJMeter_core + ${jmeter-version} + provided + + + + org.apache.jmeter + ApacheJMeter_java + ${jmeter-version} + provided + + + + io.inventit.dev + mqtt-websocket-java + 1.0.1 + + + + + ${project.artifactId} + install + + + org.apache.maven.plugins + maven-compiler-plugin + 2.5.1 + + 1.6 + 1.6 + + + + org.apache.maven.plugins + maven-shade-plugin + 2.1 + + + package + + shade + + + + + + + + diff --git a/ressource/messages.properties b/ressource/messages.properties new file mode 100644 index 0000000..54c80ad --- /dev/null +++ b/ressource/messages.properties @@ -0,0 +1,1378 @@ +# 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. + +# Warning: JMeterUtils.getResString() replaces space with '_' +# and converts keys to lowercase before lookup +# => All keys in this file must also be lower case or they won't match +# + +# Please add new entries in alphabetical order + +about=About Apache JMeter +active_threads_tooltip=Running threads +add=Add +add_from_clipboard=Add from Clipboard +add_from_suggested_excludes=Add suggested Excludes +add_as_child=Add as Child +add_parameter=Add Variable +add_pattern=Add Pattern\: +add_test=Add Test +add_user=Add User +add_value=Add Value +addtest=Add test +aggregate_graph=Statistical Graphs +aggregate_graph_choose_color=Choose color +aggregate_graph_choose_foreground_color=Foreground color +aggregate_graph_color_bar=Color\: +aggregate_graph_column=Column\: +aggregate_graph_column_selection=Column label selection\: +aggregate_graph_column_settings=Column settings +aggregate_graph_columns_to_display=Columns to display\: +aggregate_graph_dimension=Graph size +aggregate_graph_display=Display Graph +aggregate_graph_draw_outlines=Draw outlines bar? +aggregate_graph_dynamic_size=Dynamic graph size +aggregate_graph_font=Font\: +aggregate_graph_height=Height\: +aggregate_graph_increment_scale=Increment scale\: +aggregate_graph_legend=Legend +aggregate_graph_legend.placement.bottom=Bottom +aggregate_graph_legend.placement.left=Left +aggregate_graph_legend.placement.right=Right +aggregate_graph_legend.placement.top=Top +aggregate_graph_legend_placement=Placement\: +aggregate_graph_max_length_xaxis_label=Max length of x-axis label\: +aggregate_graph_ms=Milliseconds +aggregate_graph_no_values_to_graph=No values to graph +aggregate_graph_number_grouping=Show number grouping? +aggregate_graph_response_time=Response Time +aggregate_graph_save=Save Graph +aggregate_graph_save_table=Save Table Data +aggregate_graph_save_table_header=Save Table Header +aggregate_graph_size=Size\: +aggregate_graph_style=Style\: +aggregate_graph_sync_with_name=Synchronize with name +aggregate_graph_tab_graph=Graph +aggregate_graph_tab_settings=Settings +aggregate_graph_title=Aggregate Graph +aggregate_graph_title_group=Title +aggregate_graph_use_group_name=Include group name in label? +aggregate_graph_user_title=Graph title\: +aggregate_graph_value_font=Value font\: +aggregate_graph_value_labels_vertical=Value labels vertical? +aggregate_graph_width=Width\: +aggregate_graph_xaxis_group=X Axis +aggregate_graph_yaxis_group=Y Axis (milli-seconds) +aggregate_graph_yaxis_max_value=Scale maximum value\: +aggregate_report=Aggregate Report +aggregate_report_90=90% +aggregate_report_90%_line=90% Line +aggregate_report_bandwidth=KB/sec +aggregate_report_count=# Samples +aggregate_report_error=Error +aggregate_report_error%=Error % +aggregate_report_max=Max +aggregate_report_median=Median +aggregate_report_min=Min +aggregate_report_rate=Throughput +aggregate_report_stddev=Std. Dev. +aggregate_report_total_label=TOTAL +ajp_sampler_title=AJP/1.3 Sampler +als_message=Note\: The Access Log Parser is generic in design and allows you to plugin +als_message2=your own parser. To do so, implement the LogParser, add the jar to the +als_message3=/lib directory and enter the class in the sampler. +analyze=Analyze Data File... +anchor_modifier_title=HTML Link Parser +appearance=Look and Feel +argument_must_not_be_negative=The Argument must not be negative\! +arguments_panel_title=Command parameters +assertion_assume_success=Ignore Status +assertion_body_resp=Response Body +assertion_code_resp=Response Code +assertion_contains=Contains +assertion_equals=Equals +assertion_headers=Response Headers +assertion_matches=Matches +assertion_message_resp=Response Message +assertion_network_size=Full Response +assertion_not=Not +assertion_pattern_match_rules=Pattern Matching Rules +assertion_patterns_to_test=Patterns to Test +assertion_resp_field=Response Field to Test +assertion_resp_size_field=Response Size Field to Test +assertion_substring=Substring +assertion_text_document=Document (text) +assertion_text_resp=Text Response +assertion_textarea_label=Assertions\: +assertion_title=Response Assertion +assertion_url_samp=URL Sampled +assertion_visualizer_title=Assertion Results +attribute=Attribute +attribute_field=Attribute\: +attrs=Attributes +auth_base_url=Base URL +auth_manager_title=HTTP Authorization Manager +auth_manager_options=Options +auth_manager_clear_per_iter=Clear auth on each iteration? +auths_stored=Authorizations Stored in the Authorization Manager +average=Average +average_bytes=Avg. Bytes +bind=Thread Bind +bouncy_castle_unavailable_message=The jars for bouncy castle are unavailable, please add them to your classpath. +browse=Browse... +bsf_sampler_title=BSF Sampler +bsf_script=Script to run (variables: ctx vars props SampleResult sampler log Label FileName Parameters args[] OUT) +bsf_script_file=Script file to run +bsf_script_language=Scripting language\: +bsf_script_parameters=Parameters to pass to script/file\: +bsh_assertion_script=Script (see below for variables that are defined) +bsh_assertion_script_variables=The following variables are defined for the script:\nRead/Write: Failure, FailureMessage, SampleResult, vars, props, log.\nReadOnly: Response[Data|Code|Message|Headers], RequestHeaders, SampleLabel, SamplerData, ctx +bsh_assertion_title=BeanShell Assertion +bsh_function_expression=Expression to evaluate +bsh_sampler_title=BeanShell Sampler +bsh_script=Script (see below for variables that are defined) +bsh_script_file=Script file +bsh_script_parameters=Parameters (-> String Parameters and String []bsh.args) +bsh_script_reset_interpreter=Reset bsh.Interpreter before each call +bsh_script_variables=The following variables are defined for the script\:\nSampleResult, ResponseCode, ResponseMessage, IsSuccess, Label, FileName, ctx, vars, props, log +busy_testing=I'm busy testing, please stop the test before changing settings +cache_manager_size=Max Number of elements in cache +cache_manager_title=HTTP Cache Manager +cache_session_id=Cache Session Id? +cancel=Cancel +cancel_exit_to_save=There are test items that have not been saved. Do you wish to save before exiting? +cancel_new_from_template=There are test items that have not been saved. Do you wish to save before creating a test plan from selected template? +cancel_new_to_save=There are test items that have not been saved. Do you wish to save before clearing the test plan? +cancel_revert_project=There are test items that have not been saved. Do you wish to revert to the previously saved test plan? +cssjquery_attribute=Attribute\: +cssjquery_impl=CSS/JQuery implementation\: +cssjquery_render_no_text=Data response result isn't text. +cssjquery_tester_button_test=Test +cssjquery_tester_field=Selector\: +cssjquery_tester_title=CSS/JQuery Tester +change_parent=Change Controller +char_value=Unicode character number (decimal or 0xhex) +check_return_code_title=Check Return Code +choose_function=Choose a function +choose_language=Choose Language +clear=Clear +clear_all=Clear All +clear_cache_per_iter=Clear cache each iteration? +clear_cookies_per_iter=Clear cookies each iteration? +clipboard_node_read_error=An error occurred while copying node +close=Close +closeconnection=Close connection +column_delete_disallowed=Deleting this column is not permitted +column_number=Column number of CSV file | next | *alias +command_config_box_title=Command to Execute +command_config_std_streams_title=Standard streams (files) +command_field_title=Command: +compare=Compare +comparefilt=Compare filter +comparison_differ_content=Responses differ in content +comparison_differ_time=Responses differ in response time by more than +comparison_invalid_node=Invalid Node +comparison_regex_string=Regex String +comparison_regex_substitution=Substitution +comparison_response_time=Response Time: +comparison_unit=\ ms +comparison_visualizer_title=Comparison Assertion Visualizer +config_element=Config Element +config_save_settings=Configure +configure_wsdl=Configure +confirm=Confirm +constant_throughput_timer_memo=Add a delay between sampling to attain constant throughput +constant_timer_delay=Thread Delay (in milliseconds)\: +constant_timer_memo=Add a constant delay between sampling +constant_timer_title=Constant Timer +content_encoding=Content encoding\: +controller=Controller +cookie_implementation_choose=Implementation: +cookie_manager_policy=Cookie Policy: +cookie_manager_title=HTTP Cookie Manager +cookie_options=Options +cookies_stored=User-Defined Cookies +copy=Copy +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 +csvread_file_file_name=CSV file to get values from | *alias +cut=Cut +cut_paste_function=Copy and paste function string +database_conn_pool_max_usage=Max Usage For Each Connection\: +database_conn_pool_props=Database Connection Pool +database_conn_pool_size=Number of Connections in Pool\: +database_conn_pool_title=JDBC Database Connection Pool Defaults +database_driver_class=Driver Class\: +database_login_title=JDBC Database Login Defaults +database_sql_query_string=SQL Query String\: +database_sql_query_title=JDBC SQL Query Defaults +database_testing_title=JDBC Request +database_url=JDBC URL\: +database_url_jdbc_props=Database URL and JDBC Driver +ddn=DN +de=German +debug_off=Disable debug +debug_on=Enable debug +default_parameters=Default Parameters +default_value_field=Default Value\: +delay=Startup delay (seconds) +delayed_start=Delay Thread creation until needed +delete=Delete +delete_parameter=Delete Variable +delete_test=Delete Test +delete_user=Delete User +deltest=Deletion test +deref=Dereference aliases +description=Description +detail=Detail +directory_field_title=Working directory: +disable=Disable +distribution_graph_title=Distribution Graph (alpha) +distribution_note1=The graph will update every 10 samples +dn=DN +domain=Domain +done=Done +down=Down +duplicate=Duplicate +duration=Duration (seconds) +duration_assertion_duration_test=Duration to Assert +duration_assertion_failure=The operation lasted too long\: It took {0} milliseconds, but should not have lasted longer than {1} milliseconds. +duration_assertion_input_error=Please enter a valid positive integer. +duration_assertion_label=Duration in milliseconds\: +duration_assertion_title=Duration Assertion +edit=Edit +email_results_title=Email Results +en=English +enable=Enable +encode?=Encode? +encoded_value=URL Encoded Value +endtime=End Time +entry_dn=Entry DN +entrydn=Entry DN +environment_panel_title=Environment Variables +eolbyte=End of line(EOL) byte value: +error_indicator_tooltip=Show the number of errors in log, click to open Log Viewer panel +error_loading_help=Error loading help page +error_occurred=Error Occurred +error_title=Error +es=Spanish +escape_html_string=String to escape +eval_name_param=Text containing variable and function references +evalvar_name_param=Name of variable +example_data=Sample Data +example_title=Example Sampler +exit=Exit +expand=Expand +expected_return_code_title=Expected Return Code: +expiration=Expiration +expression_field=CSS/JQuery expression\: +field_name=Field name +file=File +file_already_in_use=That file is already in use +file_visualizer_append=Append to Existing Data File +file_visualizer_auto_flush=Automatically Flush After Each Data Sample +file_visualizer_browse=Browse... +file_visualizer_close=Close +file_visualizer_file_options=File Options +file_visualizer_filename=Filename +file_visualizer_flush=Flush +file_visualizer_missing_filename=No output filename specified. +file_visualizer_open=Open +file_visualizer_output_file=Write results to file / Read from file +file_visualizer_submit_data=Include Submitted Data +file_visualizer_title=File Reporter +file_visualizer_verbose=Verbose Output +filename=File Name +follow_redirects=Follow Redirects +follow_redirects_auto=Redirect Automatically +font.sansserif=Sans Serif +font.serif=Serif +fontstyle.bold=Bold +fontstyle.italic=Italic +fontstyle.normal=Normal +foreach_controller_title=ForEach Controller +foreach_end_index=End index for loop (inclusive) +foreach_input=Input variable prefix +foreach_output=Output variable name +foreach_start_index=Start index for loop (exclusive) +foreach_use_separator=Add "_" before number ? +format=Number format +fr=French +ftp_binary_mode=Use Binary mode ? +ftp_get=get(RETR) +ftp_local_file=Local File: +ftp_local_file_contents=Local File Contents: +ftp_put=put(STOR) +ftp_remote_file=Remote File: +ftp_sample_title=FTP Request Defaults +ftp_save_response_data=Save File in Response ? +ftp_testing_title=FTP Request +function_dialog_menu_item=Function Helper Dialog +function_helper_title=Function Helper +function_name_param=Name of variable in which to store the result (required) +function_name_paropt=Name of variable in which to store the result (optional) +function_params=Function Parameters +functional_mode=Functional Test Mode (i.e. save Response Data and Sampler Data) +functional_mode_explanation=Selecting Functional Test Mode may adversely affect performance. +gaussian_timer_delay=Constant Delay Offset (in milliseconds)\: +gaussian_timer_memo=Adds a random delay with a gaussian distribution +gaussian_timer_range=Deviation (in milliseconds)\: +gaussian_timer_title=Gaussian Random Timer +generate=Generate +generator=Name of Generator class +generator_cnf_msg=Could not find the generator class. Please make sure you place your jar file in the /lib directory. +generator_illegal_msg=Could not access the generator class due to IllegalAccessException. +generator_instantiate_msg=Could not create an instance of the generator parser. Please make sure the generator implements Generator interface. +get_xml_from_file=File with SOAP XML Data (overrides above text) +get_xml_from_random=Message(s) Folder +graph_apply_filter=Apply filter +graph_choose_graphs=Graphs to Display +graph_full_results_title=Graph Full Results +graph_pointshape_circle=Circle +graph_pointshape_diamond=Diamond +graph_pointshape_square=Square +graph_pointshape_triangle=Triangle +graph_pointshape_none=None +graph_resp_time_interval_label=Interval (ms): +graph_resp_time_interval_reload=Apply interval +graph_resp_time_not_enough_data=Unable to graph, not enough data +graph_resp_time_series_selection=Sampler label selection: +graph_resp_time_settings_line=Line settings +graph_resp_time_settings_pane=Graph settings +graph_resp_time_shape_label=Shape point: +graph_resp_time_stroke_width=Stroke width: +graph_resp_time_title=Response Time Graph +graph_resp_time_title_label=Graph title: +graph_resp_time_xaxis_time_format=Time format (SimpleDateFormat): +graph_results_average=Average +graph_results_data=Data +graph_results_deviation=Deviation +graph_results_latest_sample=Latest Sample +graph_results_median=Median +graph_results_ms=ms +graph_results_no_samples=No of Samples +graph_results_throughput=Throughput +graph_results_title=Graph Results +grouping_add_separators=Add separators between groups +grouping_in_controllers=Put each group in a new controller +grouping_in_transaction_controllers=Put each group in a new transaction controller +grouping_mode=Grouping\: +grouping_no_groups=Do not group samplers +grouping_store_first_only=Store 1st sampler of each group only +header_manager_title=HTTP Header Manager +headers_stored=Headers Stored in the Header Manager +heap_dump=Create a heap dump +help=Help +help_node=What's this node? +html_assertion_file=Write JTidy report to file +html_assertion_label=HTML Assertion +html_assertion_title=HTML Assertion +html_extractor_type=CSS/JQuery Extractor Implementation +html_extractor_title=CSS/JQuery Extractor +html_parameter_mask=HTML Parameter Mask (DEPRECATED) +http_implementation=Implementation: +http_response_code=HTTP response code +http_url_rewriting_modifier_title=HTTP URL Re-writing Modifier +http_user_parameter_modifier=HTTP User Parameter Modifier +httpmirror_title=HTTP Mirror Server +httpmirror_settings=Settings +httpmirror_max_pool_size=Max number of Threads: +httpmirror_max_queue_size=Max queue size: +id_prefix=ID Prefix +id_suffix=ID Suffix +if_controller_evaluate_all=Evaluate for all children? +if_controller_expression=Interpret Condition as Variable Expression? +if_controller_label=Condition (default Javascript) +if_controller_title=If Controller +ignore_subcontrollers=Ignore sub-controller blocks +include_controller=Include Controller +include_equals=Include Equals? +include_path=Include Test Plan +increment=Increment +infinite=Forever +initial_context_factory=Initial Context Factory +insert_after=Insert After +insert_before=Insert Before +insert_parent=Insert Parent +interleave_control_title=Interleave Controller +intsum_param_1=First int to add. +intsum_param_2=Second int to add - further ints can be summed by adding further arguments. +invalid_data=Invalid data +invalid_mail=Error occurred sending the e-mail +invalid_mail_address=One or more invalid e-mail addresses detected +invalid_mail_server=Problem contacting the e-mail server (see JMeter log file) +invalid_variables=Invalid variables +iteration_counter_arg_1=TRUE, for each user to have own counter, FALSE for a global counter +iterator_num=Loop Count\: +ja=Japanese +jar_file=Jar Files +java_request=Java Request +java_request_defaults=Java Request Defaults +javascript_expression=JavaScript expression to evaluate +jexl_expression=JEXL expression to evaluate +############################################################ MQTT ############################################################ +mqtt_clean_session= Clean Session +mqtt_suffix_length= Length +mqtt_suffix_client_id= Random Suffix +mqtt_publisher=MQTT Publisher +mqtt_provider_url=Provider URL +mqtt_topic=List topic +mqtt_dest_setup=Setup +mqtt_dest_setup_static=At startup +mqtt_dest_setup_dynamic=Each sample +mqtt_use_auth=Use Authorization? +mqtt_user=User +mqtt_pwd=Password +mqtt_itertions=Number of samples to aggregate +mqtt_config=Message source +mqtt_use_file=From file +mqtt_use_random_file=Random File from folder specified below +mqtt_use_text=Textarea +mqtt_message_type=Message Type +mqtt_text_message=Text +mqtt_map_message=Map Message +mqtt_object_message=Object Message +mqtt_bytes_message=Bytes Message +mqtt_file=File +mqtt_random_file=Random folder containing files ending with .dat for bytes messages, .txt or .obj for text and Object messages +mqtt_auth_required=Required +mqtt_text_area=Text Message +mqtt_subscriber_title=MQTT Subscriber +mqtt_durable_subscription_id=Durable Subscription ID +mqtt_client_id=Client ID +mqtt_read_response=Read Response +mqtt_timeout=Timeout (milliseconds) +mqtt_client_type=Client +mqtt_stop_between_samples=Stop between samples? +mqtt_subscriber_on_message=Use MessageListener.onMessage() +mqtt_subscriber_receive=Use MessageConsumer.receive() +mqtt_separator=Separator +mqtt_use_time_stamp= Add TimeStamp +mqtt_use_number_seq= Add Number Sequence +mqtt_generated_value= Generated Value +mqtt_fixed_value= Fixed Value +mqtt_type_of_generated_value = Type of generated value +mqtt_long_value = Long +mqtt_int_value = Integer +mqtt_double_value = Double +mqtt_float_value = Float +mqtt_string_value = String +mqtt_type_of_fixed_value = Type of fixed value +mqtt_min_value = Min +mqtt_max_value = Max +mqtt_value = Value +mqtt_pseudo_random = Pseudo +mqtt_secure_random = Secure +mqtt_type_random = Type of random +mqtt_seed_random = Seed +mqtt_send_as_retained_msg = Retained +mqtt_qos = Quality of service +mqtt_extactly_once = Exactly once [2] +mqtt_at_least_once = At least once [1] +mqtt_at_most_once = At most once [0] +mqtt_client_id= Client Id +mqtt_plain_text= Plain Text +mqtt_base64= Base64 +mqtt_binhex= BinHex +mqtt_binary= Binary +mqtt_message_format= Message Format +mqtt_big_volume= Random Byte Array +mqtt_size_array= Size Array +mqtt_no_encoding= No Encoding +mqtt_round_robin= Round Robin +mqtt_random= Random +mqtt_topic_choice= Strategy +mqtt_connection_per_topic= One connection per topic +################################################################################################################################ + +jms_auth_required=Required +jms_bytes_message=Bytes Message +jms_client_caption=Receiver client uses MessageConsumer.receive() to listen for message. +jms_client_caption2=MessageListener uses onMessage(Message) interface to listen for new messages. +jms_client_id=Client ID +jms_client_type=Client +jms_communication_style=Communication style +jms_concrete_connection_factory=Concrete Connection Factory +jms_config=Message source +jms_config_title=JMS Configuration +jms_connection_factory=Connection Factory +jms_correlation_title=Use alternate fields for message correlation +jms_dest_setup=Setup +jms_dest_setup_dynamic=Each sample +jms_dest_setup_static=At startup +jms_durable_subscription_id=Durable Subscription ID +jms_file=File +jms_initial_context_factory=Initial Context Factory +jms_itertions=Number of samples to aggregate +jms_jndi_defaults_title=JNDI Default Configuration +jms_jndi_props=JNDI Properties +jms_map_message=Map Message +jms_message_title=Message properties +jms_message_type=Message Type +jms_msg_content=Content +jms_object_message=Object Message +jms_point_to_point=JMS Point-to-Point +jms_properties=JMS Properties +jms_properties_title=JMS Properties +jms_properties_name=Name +jms_properties_type=Class of value +jms_properties_value=Value +jms_props=JMS Properties +jms_provider_url=Provider URL +jms_publisher=JMS Publisher +jms_pwd=Password +jms_queue=Queue +jms_queue_connection_factory=QueueConnection Factory +jms_queueing=JMS Resources +jms_random_file=Random folder containing files ending with .dat for bytes messages, .txt or .obj for text and Object messages +jms_read_response=Read Response +jms_receive_queue=JNDI name Receive queue +jms_request=Request Only +jms_requestreply=Request Response +jms_sample_title=JMS Default Request +jms_selector=JMS Selector +jms_send_queue=JNDI name Request queue +jms_separator=Separator +jms_stop_between_samples=Stop between samples? +jms_subscriber_on_message=Use MessageListener.onMessage() +jms_subscriber_receive=Use MessageConsumer.receive() +jms_subscriber_title=JMS Subscriber +jms_testing_title=Messaging Request +jms_text_area=Text Message or Object Message serialized to XML by XStream +jms_text_message=Text Message +jms_timeout=Timeout (milliseconds) +jms_topic=Destination +jms_use_auth=Use Authorization? +jms_use_file=From file +jms_use_non_persistent_delivery=Use non-persistent delivery mode? +jms_use_properties_file=Use jndi.properties file +jms_use_random_file=Random File from folder specified below +jms_use_req_msgid_as_correlid=Use Request Message Id +jms_use_res_msgid_as_correlid=Use Response Message Id +jms_use_text=Textarea +jms_user=User +jndi_config_title=JNDI Configuration +jndi_lookup_name=Remote Interface +jndi_lookup_title=JNDI Lookup Configuration +jndi_method_button_invoke=Invoke +jndi_method_button_reflect=Reflect +jndi_method_home_name=Home Method Name +jndi_method_home_parms=Home Method Parameters +jndi_method_name=Method Configuration +jndi_method_remote_interface_list=Remote Interfaces +jndi_method_remote_name=Remote Method Name +jndi_method_remote_parms=Remote Method Parameters +jndi_method_title=Remote Method Configuration +jndi_testing_title=JNDI Request +jndi_url_jndi_props=JNDI Properties +junit_append_error=Append assertion errors +junit_append_exception=Append runtime exceptions +junit_constructor_error=Unable to create an instance of the class +junit_constructor_string=Constructor String Label +junit_create_instance_per_sample=Create a new instance per sample +junit_do_setup_teardown=Do not call setUp and tearDown +junit_error_code=Error Code +junit_error_default_code=9999 +junit_error_default_msg=An unexpected error occured +junit_error_msg=Error Message +junit_failure_code=Failure Code +junit_failure_default_code=0001 +junit_failure_default_msg=Test failed +junit_failure_msg=Failure Message +junit_junit4=Search for JUnit 4 annotations (instead of JUnit 3) +junit_pkg_filter=Package Filter +junit_request=JUnit Request +junit_request_defaults=JUnit Request Defaults +junit_success_code=Success Code +junit_success_default_code=1000 +junit_success_default_msg=Test successful +junit_success_msg=Success Message +junit_test_config=JUnit Test Parameters +junit_test_method=Test Method +ldap_argument_list=LDAPArgument List +ldap_connto=Connection timeout (in milliseconds) +ldap_parse_results=Parse the search results ? +ldap_sample_title=LDAP Request Defaults +ldap_search_baseobject=Perform baseobject search +ldap_search_onelevel=Perform onelevel search +ldap_search_subtree=Perform subtree search +ldap_secure=Use Secure LDAP Protocol ? +ldap_testing_title=LDAP Request +ldapext_sample_title=LDAP Extended Request Defaults +ldapext_testing_title=LDAP Extended Request +library=Library +load=Load +load_wsdl=Load WSDL +log_errors_only=Errors +log_file=Location of log File +log_function_comment=Additional comment (optional) +log_function_level=Log level (default INFO) or OUT or ERR +log_function_string=String to be logged +log_function_string_ret=String to be logged (and returned) +log_function_throwable=Throwable text (optional) +log_only=Log/Display Only: +log_parser=Name of Log Parser class +log_parser_cnf_msg=Could not find the class. Please make sure you place your jar file in the /lib directory. +log_parser_illegal_msg=Could not access the class due to IllegalAccessException. +log_parser_instantiate_msg=Could not create an instance of the log parser. Please make sure the parser implements LogParser interface. +log_sampler=Tomcat Access Log Sampler +log_success_only=Successes +logic_controller_title=Simple Controller +login_config=Login Configuration +login_config_element=Login Config Element +longsum_param_1=First long to add +longsum_param_2=Second long to add - further longs can be summed by adding further arguments. +loop_controller_title=Loop Controller +looping_control=Looping Control +lower_bound=Lower Bound +mail_reader_account=Username: +mail_reader_all_messages=All +mail_reader_delete=Delete messages from the server +mail_reader_folder=Folder: +mail_reader_num_messages=Number of messages to retrieve: +mail_reader_password=Password: +mail_reader_port=Server Port (optional): +mail_reader_server=Server Host: +mail_reader_server_type=Protocol (e.g. pop3, imaps): +mail_reader_storemime=Store the message using MIME (raw) +mail_reader_title=Mail Reader Sampler +mail_sent=Mail sent successfully +mailer_addressees=Addressee(s): +mailer_attributes_panel=Mailing attributes +mailer_connection_security=Connection security: +mailer_error=Couldn't send mail. Please correct any misentries. +mailer_failure_limit=Failure Limit: +mailer_failure_subject=Failure Subject: +mailer_failures=Failures: +mailer_from=From: +mailer_host=Host: +mailer_login=Login: +mailer_msg_title_error=Error +mailer_msg_title_information=Information +mailer_password=Password: +mailer_port=Port: +mailer_string=E-Mail Notification +mailer_success_limit=Success Limit: +mailer_success_subject=Success Subject: +mailer_test_mail=Test Mail +mailer_title_message=Message +mailer_title_settings=Mailer settings +mailer_title_smtpserver=SMTP server +mailer_visualizer_title=Mailer Visualizer +match_num_field=Match No. (0 for Random)\: +max=Maximum +maximum_param=The maximum value allowed for a range of values +md5hex_assertion_failure=Error asserting MD5 sum : got {0} but should have been {1} +md5hex_assertion_label=MD5Hex +md5hex_assertion_md5hex_test=MD5Hex to Assert +md5hex_assertion_title=MD5Hex Assertion +mechanism=Mechanism +memory_cache=Memory Cache +menu_assertions=Assertions +menu_close=Close +menu_collapse_all=Collapse All +menu_config_element=Config Element +menu_edit=Edit +menu_expand_all=Expand All +menu_fragments=Test Fragment +menu_generative_controller=Sampler +menu_listener=Listener +menu_logic_controller=Logic Controller +menu_logger_panel=Log Viewer +menu_merge=Merge +menu_modifiers=Modifiers +menu_non_test_elements=Non-Test Elements +menu_open=Open +menu_post_processors=Post Processors +menu_pre_processors=Pre Processors +menu_response_based_modifiers=Response Based Modifiers +menu_search=Search +menu_search_reset=Reset Search +menu_tables=Table +menu_threads=Threads (Users) +menu_timer=Timer +menu_toolbar=Toolbar +metadata=MetaData +method=Method\: +mimetype=Mimetype +minimum_param=The minimum value allowed for a range of values +minute=minute +modddn=Old entry name +modification_controller_title=Modification Controller +modification_manager_title=Modification Manager +modify_test=Modify Test +modtest=Modification test +module_controller_module_to_run=Module To Run +module_controller_title=Module Controller +module_controller_warning=Could not find module: +monitor_equation_active=Active: (busy/max) > 25% +monitor_equation_dead=Dead: no response +monitor_equation_healthy=Healthy: (busy/max) < 25% +monitor_equation_load=Load: ( (busy / max) * 50) + ( (used memory / max memory) * 50) +monitor_equation_warning=Warning: (busy/max) > 67% +monitor_health_tab_title=Health +monitor_health_title=Monitor Results +monitor_is_title=Use as Monitor +monitor_label_left_bottom=0 % +monitor_label_left_middle=50 % +monitor_label_left_top=100 % +monitor_label_prefix=Connection Prefix +monitor_label_right_active=Active +monitor_label_right_dead=Dead +monitor_label_right_healthy=Healthy +monitor_label_right_warning=Warning +monitor_legend_health=Health +monitor_legend_load=Load +monitor_legend_memory_per=Memory % (used/total) +monitor_legend_thread_per=Thread % (busy/max) +monitor_load_factor_mem=50 +monitor_load_factor_thread=50 +monitor_performance_servers=Servers +monitor_performance_tab_title=Performance +monitor_performance_title=Performance Graph +name=Name\: +new=New +newdn=New distinguished name +next=Next +no=Norwegian +number_of_threads=Number of Threads (users)\: +obsolete_test_element=This test element is obsolete +once_only_controller_title=Once Only Controller +opcode=opCode +open=Open... +option=Options +optional_tasks=Optional Tasks +paramtable=Send Parameters With the Request\: +password=Password +paste=Paste +paste_insert=Paste As Insert +path=Path\: +path_extension_choice=Path Extension (use ";" as separator) +path_extension_dont_use_equals=Do not use equals in path extension (Intershop Enfinity compatibility) +path_extension_dont_use_questionmark=Do not use questionmark in path extension (Intershop Enfinity compatibility) +patterns_to_exclude=URL Patterns to Exclude +patterns_to_include=URL Patterns to Include +pkcs12_desc=PKCS 12 Key (*.p12) +pl=Polish +poisson_timer_delay=Constant Delay Offset (in milliseconds)\: +poisson_timer_memo=Adds a random delay with a poisson distribution +poisson_timer_range=Lambda (in milliseconds)\: +poisson_timer_title=Poisson Random Timer +port=Port\: +post_as_parameters=Parameters +post_body=Body Data +post_body_raw=Body Data +post_thread_group_title=tearDown Thread Group +previous=Previous +property_as_field_label={0}\: +property_default_param=Default value +property_edit=Edit +property_editor.value_is_invalid_message=The text you just entered is not a valid value for this property.\nThe property will be reverted to its previous value. +property_editor.value_is_invalid_title=Invalid input +property_name_param=Name of property +property_returnvalue_param=Return Original Value of property (default false) ? +#property_tool_tip={0}\: {1} +property_tool_tip={0}

{1} +property_undefined=Undefined +property_value_param=Value of property +property_visualiser_title=Property Display +protocol=Protocol [http]\: +protocol_java_border=Java class +protocol_java_classname=Classname\: +protocol_java_config_tile=Configure Java Sample +protocol_java_test_title=Java Testing +provider_url=Provider URL +proxy_assertions=Add Assertions +proxy_cl_error=If specifying a proxy server, host and port must be given +proxy_content_type_exclude=Exclude\: +proxy_content_type_filter=Content-type filter +proxy_content_type_include=Include\: +proxy_daemon_bind_error=Could not create script recording proxy - port in use. Choose another port. +proxy_daemon_error=Could not create script recording proxy - see log for details +proxy_daemon_error_from_clipboard=from clipboard +proxy_daemon_error_not_retrieve=Could not add retrieve +proxy_daemon_error_read_args=Could not add read arguments from clipboard\: +proxy_daemon_msg_check_details=Please check the details below when installing the certificate in the browser +proxy_daemon_msg_created_in_bin=created in JMeter bin directory +proxy_daemon_msg_install_as_in_doc=You can install it following instructions in Component Reference documentation (see Installing the JMeter CA certificate for HTTPS recording paragraph) +proxy_daemon_msg_rootca_cert=Root CA certificate\: +proxy_domains=HTTPS Domains \: +proxy_domains_dynamic_mode_tooltip=List of domain names for HTTPS url, ex. jmeter.apache.org or wildcard domain like *.apache.org. Use comma as separator. +proxy_domains_dynamic_mode_tooltip_java6=To activate this field, use a Java 7+ runtime environment +proxy_general_settings=Global Settings +proxy_headers=Capture HTTP Headers +proxy_regex=Regex matching +proxy_sampler_settings=HTTP Sampler settings +proxy_sampler_type=Type\: +proxy_separators=Add Separators +proxy_settings_port_error_digits=Only digits allowed +proxy_settings_port_error_invalid_data=Invalid data +proxy_target=Target Controller\: +proxy_test_plan_content=Test plan content +proxy_title=HTTP(S) Test Script Recorder +pt_br=Portugese (Brazilian) +ramp_up=Ramp-Up Period (in seconds)\: +random_control_title=Random Controller +random_order_control_title=Random Order Controller +random_string_chars_to_use=Chars to use for random string generation +random_string_length=Random string length +read_response_message=Read response is not checked. To see the response, please check the box in the sampler. +read_response_note=If read response is unchecked, the sampler will not read the response +read_response_note2=or set the SampleResult. This improves performance, but it means +read_response_note3=the response content won't be logged. +read_soap_response=Read SOAP Response +realm=Realm +record_controller_title=Recording Controller +ref_name_field=Reference Name\: +regex_extractor_title=Regular Expression Extractor +regex_field=Regular Expression\: +regex_params_names_field=Parameter names regexp group number +regex_params_values_field=Parameter values regex group number +regex_params_ref_name_field=Regular Expression Reference Name +regex_params_title=RegEx User Parameters +regex_source=Response Field to check +regex_src_body=Body +regex_src_body_as_document=Body as a Document +regex_src_body_unescaped=Body (unescaped) +regex_src_hdrs=Headers +regex_src_url=URL +regexfunc_param_1=Regular expression used to search previous sample - or variable. +regexfunc_param_2=Template for the replacement string, using groups from the regular expression. Format is $[group]$. Example $1$. +regexfunc_param_3=Which match to use. An integer 1 or greater, RAND to indicate JMeter should randomly choose, A float, or ALL indicating all matches should be used ([1]) +regexfunc_param_4=Between text. If ALL is selected, the between text will be used to generate the results ([""]) +regexfunc_param_5=Default text. Used instead of the template if the regular expression finds no matches ([""]) +regexfunc_param_7=Input variable name containing the text to be parsed ([previous sample]) +regexp_render_no_text=Data response result isn't text. +regexp_tester_button_test=Test +regexp_tester_field=Regular expression\: +regexp_tester_title=RegExp Tester +remote_error_init=Error initialising remote server +remote_error_starting=Error starting remote server +remote_exit=Remote Exit +remote_exit_all=Remote Exit All +remote_shut=Remote Shutdown +remote_shut_all=Remote Shutdown All +remote_start=Remote Start +remote_start_all=Remote Start All +remote_stop=Remote Stop +remote_stop_all=Remote Stop All +remove=Remove +remove_confirm_title=Confirm remove? +remove_confirm_msg=Are you sure you want remove the selected element(s)? +rename=Rename entry +report=Report +report_bar_chart=Bar Chart +report_bar_graph_url=URL +report_base_directory=Base Directory +report_chart_caption=Chart Caption +report_chart_x_axis=X Axis +report_chart_x_axis_label=Label for X Axis +report_chart_y_axis=Y Axis +report_chart_y_axis_label=Label for Y Axis +report_line_graph=Line Graph +report_line_graph_urls=Include URLs +report_output_directory=Output Directory for Report +report_page=Report Page +report_page_element=Page Element +report_page_footer=Page Footer +report_page_header=Page Header +report_page_index=Create Page Index +report_page_intro=Page Introduction +report_page_style_url=Stylesheet url +report_page_title=Page Title +report_pie_chart=Pie Chart +report_plan=Report Plan +report_select=Select +report_summary=Report Summary +report_table=Report Table +report_writer=Report Writer +report_writer_html=HTML Report Writer +request_data=Request Data +reset_gui=Reset Gui +response_save_as_md5=Save response as MD5 hash? +restart=Restart +resultaction_title=Result Status Action Handler +resultsaver_addtimestamp=Add timestamp +resultsaver_errors=Save Failed Responses only +resultsaver_numberpadlen=Minumum Length of sequence number +resultsaver_prefix=Filename prefix\: +resultsaver_skipautonumber=Don't add number to prefix +resultsaver_skipsuffix=Don't add suffix +resultsaver_success=Save Successful Responses only +resultsaver_title=Save Responses to a file +resultsaver_variable=Variable Name: +retobj=Return object +return_code_config_box_title=Return Code Configuration +reuseconnection=Re-use connection +revert_project=Revert +revert_project?=Revert project? +root=Root +root_title=Root +run=Run +running_test=Running test +runtime_controller_title=Runtime Controller +runtime_seconds=Runtime (seconds) +sample_result_save_configuration=Sample Result Save Configuration +sample_scope=Apply to: +sample_scope_all=Main sample and sub-samples +sample_scope_children=Sub-samples only +sample_scope_parent=Main sample only +sample_scope_variable=JMeter Variable +sampler_label=Label +sampler_on_error_action=Action to be taken after a Sampler error +sampler_on_error_continue=Continue +sampler_on_error_start_next_loop=Start Next Thread Loop +sampler_on_error_stop_test=Stop Test +sampler_on_error_stop_test_now=Stop Test Now +sampler_on_error_stop_thread=Stop Thread +save=Save +save?=Save? +save_all_as=Save Test Plan as +save_as=Save Selection As... +save_as_error=More than one item selected! +save_as_test_fragment=Save as Test Fragment +save_as_test_fragment_error=One of the selected nodes cannot be put inside a Test Fragment +save_as_image=Save Node As Image +save_as_image_all=Save Screen As Image +save_assertionresultsfailuremessage=Save Assertion Failure Message +save_assertions=Save Assertion Results (XML) +save_asxml=Save As XML +save_bytes=Save byte count +save_code=Save Response Code +save_datatype=Save Data Type +save_encoding=Save Encoding +save_fieldnames=Save Field Names (CSV) +save_filename=Save Response Filename +save_graphics=Save Graph +save_hostname=Save Hostname +save_idletime=Save Idle Time +save_label=Save Label +save_latency=Save Latency +save_message=Save Response Message +save_overwrite_existing_file=The selected file already exists, do you want to overwrite it? +save_requestheaders=Save Request Headers (XML) +save_responsedata=Save Response Data (XML) +save_responseheaders=Save Response Headers (XML) +save_samplecount=Save Sample and Error Counts +save_samplerdata=Save Sampler Data (XML) +save_subresults=Save Sub Results (XML) +save_success=Save Success +save_threadcounts=Save Active Thread Counts +save_threadname=Save Thread Name +save_time=Save Elapsed Time +save_timestamp=Save Time Stamp +save_url=Save URL +save_workbench=Save WorkBench +sbind=Single bind/unbind +scheduler=Scheduler +scheduler_configuration=Scheduler Configuration +scope=Scope +search_base=Search base +search_filter=Search Filter +search_test=Search Test +search_text_button_close=Close +search_text_button_find=Find +search_text_button_next=Find next +search_text_chkbox_case=Case sensitive +search_text_chkbox_regexp=Regular exp. +search_text_field=Search: +search_text_msg_not_found=Text not found +search_text_title_not_found=Not found +search_tree_title=Search Tree +search=Search +search_expand=Search & Expand +searchbase=Search base +searchfilter=Search Filter +searchtest=Search test +second=second +secure=Secure +send_file=Send Files With the Request\: +send_file_browse=Browse... +send_file_filename_label=File Path\: +send_file_mime_label=MIME Type\: +send_file_param_name_label=Parameter Name\: +server=Server Name or IP\: +servername=Servername \: +session_argument_name=Session Argument Name +setup_thread_group_title=setUp Thread Group +should_save=You should save your test plan before running it. \nIf you are using supporting data files (ie, for CSV Data Set or _StringFromFile), \nthen it is particularly important to first save your test script. \nDo you want to save your test plan first? +shutdown=Shutdown +simple_config_element=Simple Config Element +simple_data_writer_title=Simple Data Writer +size_assertion_comparator_error_equal=been equal to +size_assertion_comparator_error_greater=been greater than +size_assertion_comparator_error_greaterequal=been greater or equal to +size_assertion_comparator_error_less=been less than +size_assertion_comparator_error_lessequal=been less than or equal to +size_assertion_comparator_error_notequal=not been equal to +size_assertion_comparator_label=Type of Comparison +size_assertion_failure=The result was the wrong size\: It was {0} bytes, but should have {1} {2} bytes. +size_assertion_input_error=Please enter a valid positive integer. +size_assertion_label=Size in bytes\: +size_assertion_size_test=Size to Assert +size_assertion_title=Size Assertion +smime_assertion_issuer_dn=Issuer distinguished name +smime_assertion_message_position=Execute assertion on message at position +smime_assertion_not_signed=Message not signed +smime_assertion_signature=Signature +smime_assertion_signer=Signer certificate +smime_assertion_signer_by_file=Certificate file +smime_assertion_signer_constraints=Check values +smime_assertion_signer_dn=Signer distinguished name +smime_assertion_signer_email=Signer email address +smime_assertion_signer_no_check=No check +smime_assertion_signer_serial=Serial Number +smime_assertion_title=SMIME Assertion +smime_assertion_verify_signature=Verify signature +smtp_additional_settings=Additional Settings +smtp_attach_file=Attach file(s): +smtp_attach_file_tooltip=Separate multiple files with ";" +smtp_auth_settings=Auth settings +smtp_bcc=Address To BCC: +smtp_cc=Address To CC: +smtp_default_port=(Defaults: SMTP:25, SSL:465, StartTLS:587) +smtp_eml=Send .eml: +smtp_enabledebug=Enable debug logging? +smtp_enforcestarttls=Enforce StartTLS +smtp_enforcestarttls_tooltip=Enforces the server to use StartTLS.
If not selected and the SMTP-Server doesn't support StartTLS,
a normal SMTP-Connection will be used as fallback instead.
Please note that this checkbox creates a file in "/tmp/",
so this will cause problems under windows. +smtp_from=Address From: +smtp_header_add=Add Header +smtp_header_name=Header Name +smtp_header_remove=Remove +smtp_header_value=Header Value +smtp_mail_settings=Mail settings +smtp_message=Message: +smtp_message_settings=Message settings +smtp_messagesize=Calculate message size +smtp_password=Password: +smtp_plainbody=Send plain body (i.e. not multipart/mixed) +smtp_replyto=Address Reply-To: +smtp_sampler_title=SMTP Sampler +smtp_security_settings=Security settings +smtp_server=Server: +smtp_server_port=Port: +smtp_server_settings=Server settings +smtp_subject=Subject: +smtp_suppresssubj=Suppress Subject Header +smtp_timestamp=Include timestamp in subject +smtp_to=Address To: +smtp_trustall=Trust all certificates +smtp_trustall_tooltip=Enforces JMeter to trust all certificates, whatever CA it comes from. +smtp_truststore=Local truststore: +smtp_truststore_tooltip=The pathname of the truststore.
Relative paths are resolved against the current directory.
Failing that, against the directory containing the test script (JMX file) +smtp_useauth=Use Auth +smtp_usenone=Use no security features +smtp_username=Username: +smtp_usessl=Use SSL +smtp_usestarttls=Use StartTLS +smtp_usetruststore=Use local truststore +smtp_usetruststore_tooltip=Allows JMeter to use a local truststore. +soap_action=Soap Action +soap_data_title=Soap/XML-RPC Data +soap_sampler_title=SOAP/XML-RPC Request +soap_send_action=Send SOAPAction: +soap_sampler_file_invalid=Filename references a missing or unreadable file\: +solinger=SO_LINGER: +spline_visualizer_average=Average +spline_visualizer_incoming=Incoming +spline_visualizer_maximum=Maximum +spline_visualizer_minimum=Minimum +spline_visualizer_title=Spline Visualizer +spline_visualizer_waitingmessage=Waiting for samples +split_function_separator=String to split on. Default is , (comma). +split_function_string=String to split +ssl_alias_prompt=Please type your preferred alias +ssl_alias_select=Select your alias for the test +ssl_alias_title=Client Alias +ssl_error_title=Key Store Problem +ssl_pass_prompt=Please type your password +ssl_pass_title=KeyStore Password +ssl_port=SSL Port +sslmanager=SSL Manager +start=Start +start_no_timers=Start no pauses +starttime=Start Time +stop=Stop +stopping_test=Shutting down all test threads. You can see number of active threads in the upper right corner of GUI. Please be patient. +stopping_test_failed=One or more test threads won't exit; see log file. +stopping_test_host=Host +stopping_test_title=Stopping Test +string_from_file_encoding=File encoding if not the platform default (opt) +string_from_file_file_name=Enter path (absolute or relative) to file +string_from_file_seq_final=Final file sequence number (opt) +string_from_file_seq_start=Start file sequence number (opt) +summariser_title=Generate Summary Results +summary_report=Summary Report +switch_controller_label=Switch Value +switch_controller_title=Switch Controller +system_sampler_stderr=Standard error (stderr): +system_sampler_stdin=Standard input (stdin): +system_sampler_stdout=Standard output (stdout): +system_sampler_title=OS Process Sampler +table_visualizer_bytes=Bytes +table_visualizer_latency=Latency +table_visualizer_sample_num=Sample # +table_visualizer_sample_time=Sample Time(ms) +table_visualizer_start_time=Start Time +table_visualizer_status=Status +table_visualizer_success=Success +table_visualizer_thread_name=Thread Name +table_visualizer_warning=Warning +target_server=Target Server +tcp_classname=TCPClient classname\: +tcp_config_title=TCP Sampler Config +tcp_nodelay=Set NoDelay +tcp_port=Port Number\: +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_load?=Load template ? +template_menu=Templates... +template_merge_from=Merge +template_reload=Reload templates +template_title=Templates +test=Test +test_action_action=Action +test_action_duration=Duration (milliseconds) +test_action_pause=Pause +test_action_restart_next_loop=Go to next loop iteration +test_action_stop=Stop +test_action_stop_now=Stop Now +test_action_target=Target +test_action_target_test=All Threads +test_action_target_thread=Current Thread +test_action_title=Test Action +test_configuration=Test Configuration +test_fragment_title=Test Fragment +test_plan=Test Plan +test_plan_classpath_browse=Add directory or jar to classpath +testconfiguration=Test Configuration +testplan.serialized=Run Thread Groups consecutively (i.e. run groups one at a time) +testplan_comments=Comments\: +testt=Test +textbox_cancel=Cancel +textbox_close=Close +textbox_save_close=Save & Close +textbox_title_edit=Edit text +textbox_title_view=View text +textbox_tooltip_cell=Double click to view/edit +thread_delay_properties=Thread Delay Properties +thread_group_title=Thread Group +thread_properties=Thread Properties +threadgroup=Thread Group +throughput_control_bynumber_label=Total Executions +throughput_control_bypercent_label=Percent Executions +throughput_control_perthread_label=Per User +throughput_control_title=Throughput Controller +throughput_control_tplabel=Throughput +time_format=Format string for SimpleDateFormat (optional) +timelim=Time limit +timeout_config_box_title=Timeout configuration +timeout_title=Timeout (ms) +toggle=Toggle +toolbar_icon_set_not_found=The file description of toolbar icon set is not found. See logs. +total_threads_tooltip=Total number of threads to run +tr=Turkish +transaction_controller_include_timers=Include duration of timer and pre-post processors in generated sample +transaction_controller_parent=Generate parent sample +transaction_controller_title=Transaction Controller +unbind=Thread Unbind +unescape_html_string=String to unescape +unescape_string=String containing Java escapes +uniform_timer_delay=Constant Delay Offset (in milliseconds)\: +uniform_timer_memo=Adds a random delay with a uniform distribution +uniform_timer_range=Random Delay Maximum (in milliseconds)\: +uniform_timer_title=Uniform Random Timer +up=Up +update=Update +update_per_iter=Update Once Per Iteration +upload=File Upload +upper_bound=Upper Bound +url=URL +url_config_get=GET +url_config_http=HTTP +url_config_https=HTTPS +url_config_post=POST +url_config_protocol=Protocol\: +url_config_title=HTTP Request Defaults +url_full_config_title=UrlFull Sample +url_multipart_config_title=HTTP Multipart Request Defaults +urldecode_string=String with URL encoded chars to decode +urlencode_string=String to encode in URL encoded chars +use_expires=Use Cache-Control/Expires header when processing GET requests +use_keepalive=Use KeepAlive +use_multipart_for_http_post=Use multipart/form-data for POST +use_multipart_mode_browser=Browser-compatible headers +use_recording_controller=Use Recording Controller +user=User +user_defined_test=User Defined Test +user_defined_variables=User Defined Variables +user_param_mod_help_note=(Do not change this. Instead, modify the file of that name in JMeter's /bin directory) +user_parameters_table=Parameters +user_parameters_title=User Parameters +userdn=Username +username=Username +userpw=Password +value=Value +value_to_quote_meta=Value to escape from ORO Regexp meta chars +var_name=Reference Name +variable_name_param=Name of variable (may include variable and function references) +view_graph_tree_title=View Graph Tree +view_results_assertion_error=Assertion error: +view_results_assertion_failure=Assertion failure: +view_results_assertion_failure_message=Assertion failure message: +view_results_autoscroll=Scroll automatically? +view_results_childsamples=Child samples? +view_results_desc=Shows the text results of sampling in tree form +view_results_error_count=Error Count: +view_results_fields=fields: +view_results_in_table=View Results in Table +view_results_latency=Latency: +view_results_load_time=Load time: +view_results_render=Render: +view_results_render_document=Document +view_results_render_html=HTML +view_results_render_html_embedded=HTML (download resources) +view_results_render_json=JSON +view_results_render_text=Text +view_results_render_xml=XML +view_results_request_headers=Request Headers: +view_results_response_code=Response code: +view_results_response_headers=Response headers: +view_results_response_message=Response message: +view_results_response_missing_tika=Missing tika-app.jar in classpath. Unable to convert to plain text this kind of document.\nDownload the tika-app-x.x.jar file from http://tika.apache.org/download.html\nAnd put the file in /lib directory. +view_results_response_partial_message=Start of message: +view_results_response_too_large_message=Response too large to be displayed. Size: +view_results_sample_count=Sample Count: +view_results_sample_start=Sample Start: +view_results_search_pane=Search pane +view_results_size_body_in_bytes=Body size in bytes: +view_results_size_headers_in_bytes=Headers size in bytes: +view_results_size_in_bytes=Size in bytes: +view_results_tab_assertion=Assertion result +view_results_tab_request=Request +view_results_tab_response=Response data +view_results_tab_sampler=Sampler result +view_results_table_fields_key=Additional field +view_results_table_fields_value=Value +view_results_table_headers_key=Response header +view_results_table_headers_value=Value +view_results_table_request_headers_key=Request header +view_results_table_request_headers_value=Value +view_results_table_request_http_cookie=Cookie +view_results_table_request_http_host=Host +view_results_table_request_http_method=Method +view_results_table_request_http_nohttp=No HTTP Sample +view_results_table_request_http_path=Path +view_results_table_request_http_port=Port +view_results_table_request_http_protocol=Protocol +view_results_table_request_params_key=Parameter name +view_results_table_request_params_value=Value +view_results_table_request_raw_nodata=No data to display +view_results_table_request_tab_http=HTTP +view_results_table_request_tab_raw=Raw +view_results_table_result_tab_parsed=Parsed +view_results_table_result_tab_raw=Raw +view_results_thread_name=Thread Name: +view_results_title=View Results +view_results_tree_title=View Results Tree +warning=Warning! +web_cannot_convert_parameters_to_raw=Cannot convert parameters to Body Data \nbecause one of the parameters has a name +web_cannot_switch_tab=You cannot switch because data cannot be converted\n to target Tab data, empty data to switch +web_parameters_lost_message=Switching to Body Data will convert the parameters.\nParameter table will be cleared when you select\nanother node or save the test plan.\nOK to proceeed? +web_proxy_server_title=Proxy Server +web_request=HTTP Request +web_server=Web Server +web_server_client=Client implementation: +web_server_domain=Server Name or IP\: +web_server_port=Port Number\: +web_server_timeout_connect=Connect: +web_server_timeout_response=Response: +web_server_timeout_title=Timeouts (milliseconds) +web_testing2_title=HTTP Request HTTPClient +web_testing_concurrent_download=Use concurrent pool. Size: +web_testing_embedded_url_pattern=URLs must match\: +web_testing_retrieve_images=Retrieve All Embedded Resources +web_testing_retrieve_title=Embedded Resources from HTML Files +web_testing_source_ip=Source address +web_testing_source_ip_hostname=IP/Hostname +web_testing_source_ip_device=Device +web_testing_source_ip_device_ipv4=Device IPv4 +web_testing_source_ip_device_ipv6=Device IPv6 +web_testing_title=HTTP Request +webservice_configuration_wizard=WSDL helper +webservice_get_xml_from_random_title=Use random messages SOAP +webservice_maintain_session=Maintain HTTP Session +webservice_message_soap=WebService message +webservice_methods=Web Methods +webservice_proxy_host=Proxy Host +webservice_proxy_note=If Use HTTP Proxy is checked, but no host or port are provided, the sampler +webservice_proxy_note2=will look at command line options. If no proxy host or port are provided by +webservice_proxy_note3=either, it will fail silently. +webservice_proxy_port=Proxy Port +webservice_sampler_title=WebService(SOAP) Request (DEPRECATED) +webservice_soap_action=SOAPAction +webservice_timeout=Timeout: +webservice_use_proxy=Use HTTP Proxy +while_controller_label=Condition (function or variable) +while_controller_title=While Controller +workbench_title=WorkBench +wsdl_helper_error=The WSDL was not valid, please double check the url. +wsdl_url=WSDL URL +wsdl_url_error=The WSDL was emtpy. +xml_assertion_title=XML Assertion +xml_download_dtds=Fetch external DTDs +xml_namespace_button=Use Namespaces +xml_tolerant_button=Use Tidy (tolerant parser) +xml_validate_button=Validate XML +xml_whitespace_button=Ignore Whitespace +xmlschema_assertion_label=File Name: +xmlschema_assertion_title=XML Schema Assertion +xpath_assertion_button=Validate +xpath_assertion_check=Check XPath Expression +xpath_assertion_error=Error with XPath +xpath_assertion_failed=Invalid XPath Expression +xpath_assertion_label=XPath +xpath_assertion_negate=True if nothing matches +xpath_assertion_option=XML Parsing Options +xpath_assertion_test=XPath Assertion +xpath_assertion_tidy=Try and tidy up the input +xpath_assertion_title=XPath Assertion +xpath_assertion_valid=Valid XPath Expression +xpath_assertion_validation=Validate the XML against the DTD +xpath_assertion_whitespace=Ignore whitespace +xpath_expression=XPath expression to match against +xpath_extractor_fragment=Return entire XPath fragment instead of text content? +xpath_extractor_query=XPath query: +xpath_extractor_title=XPath Extractor +xpath_file_file_name=XML file to get values from +xpath_tester=XPath Tester +xpath_tester_button_test=Test +xpath_tester_field=XPath expression +xpath_tester_fragment=Return entire XPath fragment instead of text content? +xpath_tester_no_text=Data response result isn't text. +xpath_tester_title=XPath Tester +xpath_tidy_quiet=Quiet +xpath_tidy_report_errors=Report errors +xpath_tidy_show_warnings=Show warnings +you_must_enter_a_valid_number=You must enter a valid number +zh_cn=Chinese (Simplified) +zh_tw=Chinese (Traditional) diff --git a/sample-jmeter-testplans/mqtt.jmx b/sample-jmeter-testplans/mqtt.jmx new file mode 100644 index 0000000..8d4b603 --- /dev/null +++ b/sample-jmeter-testplans/mqtt.jmx @@ -0,0 +1,204 @@ + + + + + + false + false + + + + + + + + continue + + false + 1 + + 1 + 0 + 1442389004000 + 1442389004000 + false + + + + + + tcp://test.mosquitto.org:1883 + /mitsos/ + ewewew + ewewew + false + false + + false + mqtt_round_robin + mqtt_at_most_once + false + ttytytytytyt + 100 + 20000 + + + + + haha + + Assertion.response_data + false + 2 + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + false + false + false + false + false + 0 + true + true + + + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + false + false + false + false + false + 0 + true + true + + + + + + + + + continue + + false + 1 + + 1 + 6 + 1442316565000 + 1442316565000 + false + + + + + + tcp://test.mosquitto.org:1883 + /mitsos/ + + + hahaha + mqtt_text_message + 100 + false + mqtt_at_most_once + false + mqtt_int_value + + mqtt_pseudo_random + + + mqtt_int_value + + true + false + qraftgst + mqtt_no_encoding + UTF-8 + + mqtt_round_robin + false + false + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + false + false + false + false + false + 0 + true + true + + + + + + + + + diff --git a/script/TestPlan.tmpl.jmx b/script/TestPlan.tmpl.jmx new file mode 100644 index 0000000..03d6cfa --- /dev/null +++ b/script/TestPlan.tmpl.jmx @@ -0,0 +1,60 @@ + + + + + + false + false + + + + + + + + continue + + false + __LOOP_COUNT__ + + __NUMCLIENT__ + __RAMP_TIME__ + 1397652808000 + 1397652808000 + false + + + + + + __URL__ + __TOPIC__ + + + + mqtt_generated_value + __NUMBER_SAMPLE__ + false + __QOS__ + __RETAIN__ + mqtt_int_value + + mqtt_pseudo_random + 9999 + 9 + mqtt_float_value + 5 + false + false + __CLIENT_ID__ + mqtt_no_encoding + UTF-8 + + mqtt_round_robin + false + + + + + + diff --git a/script/execute.sh b/script/execute.sh new file mode 100644 index 0000000..f5648df --- /dev/null +++ b/script/execute.sh @@ -0,0 +1,81 @@ +#!/bin/bash + +target="azureuser@10.0.0.7" # target of the test +master="azureuser@10.0.0.4" # jmeter master of the test +#Generate number of clients (number of connection for each test) +i=0 # loop count number +step=200 # step for number of clients +for ((c=100;c<=10000;c=c+$step)) +do + ANUMCLIENT[$i]=$c; + i=$i+1; +done + +# Quality of services +AQOS=(0 1 2) +ARETAIN=(true false) + +# Jmeter server (slave ) +JMETERSERVERS=10.0.0.5 + +if [ ! -z "$JMETERSERVERS" ] +then + REMOTE="-R $JMETERSERVERS" +fi +#----------------------------------Create Directory-----------------------------------------------# +if [ -d ~/METRICS ] +then + rm -r ~/METRICS +fi + mkdir ~/METRICS ~/METRICS/CPU ~/METRICS/IO ~/METRICS/MEMO ~/METRICS/Logs ~/METRICS/Results ~/METRICS/Summarisers ~/METRICS/Summarisers/Total + +#------------------------------------Run The Test-------------------------------------------------# + +for NUMCLIENT in ${ANUMCLIENT[*]} +do +for QOS in ${AQOS[*]} +do +for RETAIN in ${ARETAIN[*]} +do + SUFFIX=$NUMCLIENT.$QOS.$RETAIN + echo "running testplan.$SUFFIX.jmx" + # Start mesuring the metrics + ssh $target ./getmetrics.sh + #-------------------------------------------------/ + ./../jmeter -n -t TestPlans/testplan.$SUFFIX.jmx -p specific.properties -l ~/METRICS/Results/result.$SUFFIX.jtl -j ~/METRICS/Logs/log.$SUFFIX.log $REMOTE + cat Logs/log.$SUFFIX.log | grep 'Summariser' > ~/METRICS/Summarisers/summariser.$SUFFIX.log + cat Logs/log.$SUFFIX.log | grep 'summary =' >> ~/METRICS/Summarisers/Total/total.$QOS.$RETAIN.log + + #Stop mesuring load at the target and get the result to local machine + + ssh $target ./stopgetmetrics.sh + scp $target:cpuload.log ~/METRICS/CPU/cpuload.$SUFFIX.log + scp $target:memo.log ~/METRICS/MEMO/memo.$SUFFIX.log + scp $target:io.log ~/METRICS/IO/io.$SUFFIX.log + #-------------------------------------------------/ +done +done +done + +#echo Please read 16.7 Reducing resource requirements http://jmeter.apache.org/usermanual/best-practices.html +#echo Please read 2.4.3 2.4.7 http://jmeter.apache.org/usermanual/get-started.html +#echo Please read http://jmeter.apache.org/usermanual/jmeter_distributed_testing_step_by_step.pdf +# 2.4.3 Non-GUI Mode (Command Line mode) + +# For non-interactive testing, you may choose to run JMeter without the GUI. To do so, use the following command options: + +# -n This specifies JMeter is to run in non-gui mode +# -t [name of JMX file that contains the Test Plan]. +# -l [name of JTL file to log sample results to]. +# -j [name of JMeter run log file]. +# -r Run the test in the servers specified by the JMeter property "remote_hosts" +# -R [list of remote servers] Run the test in the specified remote servers + +# The script also lets you specify the optional firewall/proxy server information: + +# -H [proxy server hostname or ip address] +# -P [proxy server port] + +# Example : jmeter -n -t my_test.jmx -l log.jtl -H my.proxy.server -P 8000 + +# If the property jmeterengine.stopfail.system.exit is set to true (default is false), then JMeter will invoke System.exit(1) if it cannot stop all threads. Normally this is not necessary. diff --git a/script/generate.sh b/script/generate.sh new file mode 100644 index 0000000..c6f3e4c --- /dev/null +++ b/script/generate.sh @@ -0,0 +1,35 @@ +#!/bin/bash +client_id=$(hostname -I) #client id of publisher +target="tcp:\/\/10.0.0.7:1883" # target for testing +loop_count=1 +ramp_time=1 +number_sample=1 +i=0 # loop count number +step=200 # step for number of clients +for ((c=100;c<=10000;c=c+$step)) +do + ANUMCLIENT[$i]=$c; + i=$i+1; +done +AQOS=(0 1 2) +ARETAIN=(true false) +qos[0]=mqtt_at_most_once +qos[1]=mqtt_at_least_once +qos[2]=mqtt_extactly_once +if [ -d "TestPlans" ]; then + rm -r TestPlans +fi + mkdir TestPlans +for NUMCLIENT in ${ANUMCLIENT[*]} +do +for QOS in ${AQOS[*]} +do +for RETAIN in ${ARETAIN[*]} +do + + SUFFIX=$NUMCLIENT.$QOS.$RETAIN + echo "generating testplan.$SUFFIX.jmx" + sed "s/__NUMCLIENT__/$NUMCLIENT/g" TestPlan.tmpl.jmx | sed "s/__QOS__/${qos[$QOS]}/g" | sed "s/__RETAIN__/$RETAIN/g" | sed "s/__RAMP_TIME__/$ramp_time/g" | sed "s/__LOOP_COUNT__/$loop_count/g" | sed "s/__NUMBER_SAMPLE__/$number_sample/g"| sed "s/__CLIENT_ID__/$client_id/g" | sed "s/__URL__/$target/g" > TestPlans/testplan.$SUFFIX.jmx +done +done +done diff --git a/script/getmetrics.sh b/script/getmetrics.sh new file mode 100644 index 0000000..d204348 --- /dev/null +++ b/script/getmetrics.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +sar -u 1 > cpuload.log & +pid_cpu=$! +echo $pid_cpu > pid_cpu.log +sar -r 1 > memo.log & +pid_memo=$! +echo $pid_memo > pid_memo.log +sar -b 1 > io.log & +pid_io=$! +echo $pid_io > pid_io.log +echo "Getting metrics with process id : $pid_cpu $pid_memo $pid_io" + diff --git a/script/stopgetmetrics.sh b/script/stopgetmetrics.sh new file mode 100644 index 0000000..c267365 --- /dev/null +++ b/script/stopgetmetrics.sh @@ -0,0 +1,9 @@ +#!/bin/bash +pid_cpu=$(cat pid_cpu.log) +kill $pid_cpu +pid_memo=$(cat pid_memo.log) +kill $pid_memo +pid_io=$(cat pid_io.log) +kill $pid_io +echo "Killed getmetrics process whose pid $pid_cpu $pid_memo $pid_io" +rm pid_cpu.log pid_memo.log pid_io.log diff --git a/src/main/java/org/apache/jmeter/protocol/mqttws/client/MqttPublisher.java b/src/main/java/org/apache/jmeter/protocol/mqttws/client/MqttPublisher.java new file mode 100644 index 0000000..faaf747 --- /dev/null +++ b/src/main/java/org/apache/jmeter/protocol/mqttws/client/MqttPublisher.java @@ -0,0 +1,383 @@ +/** + 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. + + Copyright 2014 University Joseph Fourier, LIG Laboratory, ERODS Team + +*/ + +package org.apache.jmeter.protocol.mqttws.client; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.Serializable; +import java.net.URISyntaxException; +import java.util.Random; +import java.util.concurrent.TimeUnit; +import java.util.Date; +import java.util.List; +import java.util.ArrayList; +import java.util.Timer; +import java.util.TimerTask; +import java.io.IOException; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.jmeter.config.Arguments; +import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient; +import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext; +import org.apache.jmeter.protocol.mqttws.control.gui.MQTTPublisherGui; +import org.apache.jmeter.protocol.mqttws.control.gui.MQTTSubscriberGui; +import org.apache.jmeter.samplers.SampleResult; +import org.apache.jmeter.threads.JMeterContext; +import org.apache.jmeter.threads.JMeterContextService; +import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; +import org.eclipse.paho.client.mqttv3.MqttCallback; +import org.eclipse.paho.client.mqttv3.MqttConnectOptions; +import org.eclipse.paho.client.mqttv3.MqttException; +import org.eclipse.paho.client.mqttv3.MqttMessage; +import org.eclipse.paho.client.mqttv3.MqttSecurityException; +import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.codec.binary.BinaryCodec; +import org.apache.commons.codec.binary.Hex; + + + + +import io.inventit.dev.mqtt.paho.MqttWebSocketAsyncClient; + +public class MqttPublisher extends AbstractJavaSamplerClient implements Serializable, MqttCallback { + private static final long serialVersionUID = 1L; + private MqttWebSocketAsyncClient client; + public static int numSeq=0; + public int quality = 0; + private AtomicInteger total = new AtomicInteger(0); + String myname = this.getClass().getName(); + + + + @Override + public Arguments getDefaultParameters() { + Arguments defaultParameters = new Arguments(); + defaultParameters.addArgument("HOST", "tcp://localhost:1883"); + defaultParameters.addArgument("CLIENT_ID", "${__time(YMDHMS)}${__threadNum}"); + defaultParameters.addArgument("TOPIC", "TEST.MQTT"); + defaultParameters.addArgument("AGGREGATE", "100"); + defaultParameters.addArgument("DURABLE", "false"); + return defaultParameters; + } + + public void setupTest(JavaSamplerContext context){ + //nothing yet + } + + public void delayedSetupTest(JavaSamplerContext context){ + System.out.println(myname + ">>>> in setupTest"); + String host = context.getParameter("HOST"); + String clientId = context.getParameter("CLIENT_ID"); + if("TRUE".equalsIgnoreCase(context.getParameter("RANDOM_SUFFIX"))){ + clientId= MqttPublisher.getClientId(clientId,Integer.parseInt(context.getParameter("SUFFIX_LENGTH"))); + } + try { + System.out.println("Host: " + host + "clientID: " + clientId); + client = new MqttWebSocketAsyncClient(host, clientId, new MemoryPersistence()); + } catch (MqttException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + MqttConnectOptions options = new MqttConnectOptions(); + options.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1_1); + options.setCleanSession(true); + /*String user = context.getParameter("USER"); + String pwd = context.getParameter("PASSWORD"); + boolean durable = Boolean.parseBoolean(context.getParameter("DURABLE")); + options.setCleanSession(!durable); + if (user != null) { + options.setUserName(user); + if ( pwd!=null ) { + options.setPassword(pwd.toCharArray()); + } + } + */ + //TODO more options here + try { + client.connect(options); + int i=0; + if (!client.isConnected() && (i<5) ) { + try { + i++; + Thread.sleep(2000); + System.out.println("."); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + } catch (MqttSecurityException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (MqttException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + client.setCallback(this); + } + + + public SampleResult runTest(JavaSamplerContext context) { + delayedSetupTest(context); + SampleResult result = new SampleResult(); + result.setSampleLabel(context.getParameter("SAMPLER_NAME")); + + if (!client.isConnected() ) { + System.out.println(myname + " >>>> Client is not connected - Aborting test"); + result.setSuccessful(false); + return result; + } + result.sampleStart(); // start stopwatch + try { + produce(context); + } catch (Exception e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + //consider it a success if client gets connected + //in future we might add more criteria for this + if (client.isConnected() ) { + result.setResponseOK(); + } + result.sampleEnd(); + System.out.println(myname + ">>>> ending runTest"); + return result; + + } + + + public void close(JavaSamplerContext context) { + + + } + + private static final String mycharset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + public static String getClientId(String clientPrefix, int suffixLength) { + Random rand = new Random(System.nanoTime()*System.currentTimeMillis()); + StringBuilder sb = new StringBuilder(); + sb.append(clientPrefix); + for (int i = 0; i < suffixLength; i++) { + int pos = rand.nextInt(mycharset.length()); + sb.append(mycharset.charAt(pos)); + } + return sb.toString(); + } + + @Override + public void connectionLost(Throwable arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void deliveryComplete(IMqttDeliveryToken arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void messageArrived(String str, MqttMessage msg) throws Exception { + System.out.println("got message: " + new String(msg.getPayload())); + // TODO Auto-generated method stub + + } + + +private void produce(JavaSamplerContext context) throws Exception { + + // ---------------------Type of message -------------------// + + if ("FIXED".equals(context.getParameter("TYPE_MESSAGE"))) { + System.out.println("Fixed - TODO"); + /* + produce(context.getParameter("MESSAGE"), + context.getParameter("TOPIC"), + Integer.parseInt(context.getParameter("AGGREGATE")), + context.getParameter("QOS"), + context.getParameter("RETAINED"), + context.getParameter("TIME_STAMP"), + context.getParameter("NUMBER_SEQUENCE"), + context.getParameter("TYPE_VALUE"), + context.getParameter("FORMAT"), + context.getParameter("CHARSET"), + context.getParameter("LIST_TOPIC"), + context.getParameter("STRATEGY"), + context.getParameter("PER_TOPIC")); +*/ + } else if ("RANDOM".equals(context.getParameter("TYPE_MESSAGE"))) { + + System.out.println("Randomly - TODO"); + /*produceRandomly(context.getParameter("SEED"),context.getParameter("MIN_RANDOM_VALUE"), + context.getParameter("MAX_RANDOM_VALUE"),context.getParameter("TYPE_RANDOM_VALUE"), + context.getParameter("TOPIC"),Integer.parseInt(context.getParameter("AGGREGATE")), + context.getParameter("QOS"),context.getParameter("RETAINED"), + context.getParameter("TIME_STAMP"),context.getParameter("NUMBER_SEQUENCE"), + context.getParameter("TYPE_VALUE"), + context.getParameter("FORMAT"), + context.getParameter("CHARSET"), + context.getParameter("LIST_TOPIC"), + context.getParameter("STRATEGY"), + context.getParameter("PER_TOPIC")); + */ + + } else if ("TEXT".equals(context.getParameter("TYPE_MESSAGE"))) { + produce(context.getParameter("MESSAGE"), + context.getParameter("TOPIC"), + Integer.parseInt(context.getParameter("AGGREGATE")), + context.getParameter("QOS"), + context.getParameter("RETAINED"), + context.getParameter("TIME_STAMP"), + context.getParameter("NUMBER_SEQUENCE"), + context.getParameter("TYPE_VALUE"), + context.getParameter("FORMAT"), + context.getParameter("CHARSET"), + //context.getParameter("LIST_TOPIC"), + "FALSE", + context.getParameter("STRATEGY"), + context.getParameter("PER_TOPIC")); + } else if("BYTE_ARRAY".equals(context.getParameter("TYPE_MESSAGE"))){ + System.out.println("Byte Array - TODO"); + /* + produceBigVolume( + context.getParameter("TOPIC"), + Integer.parseInt(context.getParameter("AGGREGATE")), + context.getParameter("QOS"), + context.getParameter("RETAINED"), + context.getParameter("TIME_STAMP"), + context.getParameter("NUMBER_SEQUENCE"), + context.getParameter("FORMAT"), + context.getParameter("CHARSET"), + context.getParameter("SIZE_ARRAY"), + context.getParameter("LIST_TOPIC"), + context.getParameter("STRATEGY"), + context.getParameter("PER_TOPIC")); + */ + } + + } + + + + + + + + private void produce(String message, String topic, int aggregate, + String qos, String isRetained, String useTimeStamp, String useNumberSeq,String type_value, String format, String charset,String isListTopic,String strategy,String isPerTopic) throws Exception { + System.out.println(myname + ">>>> Starting publishing: "); + try { + // Quality + if (MQTTPublisherGui.EXACTLY_ONCE.equals(qos)) { + quality = 0; + } else if (MQTTPublisherGui.AT_LEAST_ONCE.equals(qos)) { + quality = 1; + } else if (MQTTPublisherGui.AT_MOST_ONCE.equals(qos)) { + quality = 2; + } + // Retained + boolean retained = false; + if ("TRUE".equals(isRetained)) + retained = true; + //TODO send next one to GUI + boolean throttle = true; + // List topic + if("FALSE".equals(isListTopic)){ + for (int i = 0; i < aggregate; ++i) { + byte[] payload = createPayload(message, useTimeStamp, useNumberSeq, type_value,format, charset); + //if (quality!=0) { + if (throttle) { + Thread.sleep(100); + } + this.client.publish(topic,payload,quality,retained); + System.out.print("*"); + total.incrementAndGet(); + } + System.out.println(""); + } + } catch (Exception e) { + e.printStackTrace(); + getLogger().warn(e.getLocalizedMessage(), e); + } + } + + public byte[] createPayload(String message, String useTimeStamp, String useNumSeq ,String type_value, String format, String charset) throws IOException, NumberFormatException { + ByteArrayOutputStream b = new ByteArrayOutputStream(); + DataOutputStream d = new DataOutputStream(b); +// flags + byte flags=0x00; + if("TRUE".equals(useTimeStamp)) flags|=0x80; + if("TRUE".equals(useNumSeq)) flags|=0x40; + if (MQTTPublisherGui.INT.equals(type_value)) flags|=0x20; + if (MQTTPublisherGui.LONG.equals(type_value)) flags|=0x10; + if (MQTTPublisherGui.FLOAT.equals(type_value)) flags|=0x08; + if (MQTTPublisherGui.DOUBLE.equals(type_value)) flags|=0x04; + if (MQTTPublisherGui.STRING.equals(type_value)) flags|=0x02; + if(!"TEXT".equals(type_value)){ + d.writeByte(flags); + } +// TimeStamp + if("TRUE".equals(useTimeStamp)){ + Date date= new java.util.Date(); + d.writeLong(date.getTime()); + } +// Number Sequence + if("TRUE".equals(useNumSeq)){ + d.writeInt(numSeq++); + + } +// Value + if (MQTTPublisherGui.INT.equals(type_value)) { + d.writeInt(Integer.parseInt(message)); + } else if (MQTTPublisherGui.LONG.equals(type_value)) { + d.writeLong(Long.parseLong(message)); + } else if (MQTTPublisherGui.DOUBLE.equals(type_value)) { + d.writeDouble(Double.parseDouble(message)); + } else if (MQTTPublisherGui.FLOAT.equals(type_value)) { + d.writeDouble(Float.parseFloat(message)); + } else if (MQTTPublisherGui.STRING.equals(type_value)) { + d.write(message.getBytes()); + } else if ("TEXT".equals(type_value)) { + d.write(message.getBytes()); + } + +// Format: Encoding + if(MQTTPublisherGui.BINARY.equals(format)){ + BinaryCodec encoder= new BinaryCodec(); + return encoder.encode(b.toByteArray()); + } else if(MQTTPublisherGui.BASE64.equals(format)){ + return Base64.encodeBase64(b.toByteArray()); + } else if(MQTTPublisherGui.BINHEX.equals(format)){ + Hex encoder= new Hex(); + return encoder.encode(b.toByteArray()); + } else if(MQTTPublisherGui.PLAIN_TEXT.equals(format)){ + String s= new String (b.toByteArray(),charset); + return s.getBytes(); + + } else return b.toByteArray(); + } + + +} diff --git a/src/main/java/org/apache/jmeter/protocol/mqttws/client/MqttSubscriber.java b/src/main/java/org/apache/jmeter/protocol/mqttws/client/MqttSubscriber.java new file mode 100644 index 0000000..12d13d6 --- /dev/null +++ b/src/main/java/org/apache/jmeter/protocol/mqttws/client/MqttSubscriber.java @@ -0,0 +1,276 @@ +/** + 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. + + Copyright 2014 University Joseph Fourier, LIG Laboratory, ERODS Team + +*/ + +package org.apache.jmeter.protocol.mqttws.client; +import java.io.Serializable; +import java.util.Random; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.List; +import java.util.ArrayList; +import java.util.Timer; +import java.util.TimerTask; + +import org.apache.jmeter.config.Arguments; +import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient; +import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext; +import org.apache.jmeter.samplers.SampleResult; +import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; +import org.eclipse.paho.client.mqttv3.MqttCallback; +import org.eclipse.paho.client.mqttv3.MqttConnectOptions; +import org.eclipse.paho.client.mqttv3.MqttException; +import org.eclipse.paho.client.mqttv3.MqttMessage; +import org.eclipse.paho.client.mqttv3.MqttSecurityException; +import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; + +import io.inventit.dev.mqtt.paho.MqttWebSocketAsyncClient; + +public class MqttSubscriber extends AbstractJavaSamplerClient implements Serializable, MqttCallback { + private static final long serialVersionUID = 1L; + private MqttWebSocketAsyncClient client; + private List allmessages = new ArrayList(); + private AtomicInteger nummsgs = new AtomicInteger(0); + + static long msgs_aggregate = Long.MAX_VALUE; + static long timeout = 10000; + + static String host ; + static String clientId ; + + String myname = this.getClass().getName(); + + + @Override + public Arguments getDefaultParameters() { + Arguments defaultParameters = new Arguments(); + defaultParameters.addArgument("HOST", "tcp://localhost:1883"); + defaultParameters.addArgument("CLIENT_ID", "${__time(YMDHMS)}${__threadNum}"); + defaultParameters.addArgument("TOPIC", "TEST.MQTT"); + defaultParameters.addArgument("AGGREGATE", "100"); + defaultParameters.addArgument("DURABLE", "false"); + return defaultParameters; + } + + public void setupTest(JavaSamplerContext context){ + //do nothing yet + } + + public void delayedSetup(JavaSamplerContext context){ + //System.out.println(myname + ">>>> in setupTest"); + host = context.getParameter("HOST"); + clientId = context.getParameter("CLIENT_ID"); + + if("TRUE".equalsIgnoreCase(context.getParameter("RANDOM_SUFFIX"))){ + clientId= MqttPublisher.getClientId(clientId,Integer.parseInt(context.getParameter("SUFFIX_LENGTH"))); + } + try { + System.out.println("Host: " + host + "clientID: " + clientId); + client = new MqttWebSocketAsyncClient(host, clientId, new MemoryPersistence()); + //client = new MqttClient(host, clientId, new MemoryPersistence()); + } catch (MqttException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + /* + //wait out for messages till TIMEOUT expires or aggregate msgs count if set + if (!context.getParameter("AGGREGATE").trim().equals("")) { + try { + msgs_aggregate = Long.parseLong(context.getParameter("AGGREGATE")); + } catch (NumberFormatException e) { + msgs_aggregate = Long.MAX_VALUE; + } + } + */ + if ( !context.getParameter("AGGREGATE").equals("")) { + msgs_aggregate = Long.parseLong(context.getParameter("AGGREGATE")); + } + if ( !context.getParameter("TIMEOUT").equals("") ) { + timeout = Long.parseLong(context.getParameter("TIMEOUT")); + } + + System.out.println("nummsgs: " + msgs_aggregate + " - timeout: " + timeout); + + MqttConnectOptions options = new MqttConnectOptions(); + options.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1_1); + options.setCleanSession(true); + /*String user = context.getParameter("USER"); + String pwd = context.getParameter("PASSWORD"); + boolean durable = Boolean.parseBoolean(context.getParameter("DURABLE")); + options.setCleanSession(!durable); + if (user != null) { + options.setUserName(user); + if ( pwd!=null ) { + options.setPassword(pwd.toCharArray()); + } + } + */ + //TODO more options here + try { + client.connect(options); + int i=0; + if (!client.isConnected() && (i<5) ) { + try { + i++; + Thread.sleep(2000); + System.out.println("."); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + } catch (MqttSecurityException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (MqttException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + client.setCallback(this); + + } + + + private class EndTask extends TimerTask { + boolean timeup = false; + public void run() { + System.out.println("Time's up!"); + timeup = true; + } + public boolean isTimeUp(){ + return timeup; + } + } + + @Override + public SampleResult runTest(JavaSamplerContext context) { + delayedSetup(context); + //System.out.println(myname + " >>>> in runtest"); + SampleResult result = new SampleResult(); + result.setSampleLabel(context.getParameter("SAMPLER_NAME")); + + + if (!client.isConnected() ) { + System.out.println(myname + " >>>> Client is not connected - Returning false"); + result.setSuccessful(false); + return result; + } + result.sampleStart(); // start stopwatch + try { + System.out.println("Subscribing to topic: " + context.getParameter("TOPIC")); + client.subscribe(context.getParameter("TOPIC"), 0); + } catch (MqttException e) { + System.out.println("ohohohoh"); + // TODO Auto-generated catch block + e.printStackTrace(); + } + EndTask endtask = new EndTask(); + Timer timer = new Timer(); + timer.schedule( endtask, timeout); + while ( !endtask.isTimeUp() && nummsgs.get()>>> Stopping listening. Heard " + nummsgs.get() + " so far"); + result.sampleEnd(); + try { + StringBuilder allmsgs = new StringBuilder(); + if ( !allmessages.isEmpty() ) { + for (String s : this.allmessages) + { + allmsgs.append(s + "\n"); + } + result.setResponseMessage("Received " + allmessages.size() + " messages: \n" + allmsgs.toString() ); + result.setResponseData(allmsgs.toString(),null); + } else { + result.setResponseMessage("No messages received"); + result.setResponseCode("FAILED"); + } + if ( msgs_aggregate != Long.MAX_VALUE) { + if ( nummsgs.get() >= msgs_aggregate ) { + result.setResponseOK(); + } + else + result.setResponseCode("FAILED"); + } else { + if (nummsgs.get()!=0) { + result.setResponseOK(); + } + } + } catch (Exception e) { + result.sampleEnd(); // stop stopwatch + result.setSuccessful(false); + result.setResponseMessage("Exception: " + e); + // get stack trace as a String to return as document data + java.io.StringWriter stringWriter = new java.io.StringWriter(); + e.printStackTrace( new java.io.PrintWriter(stringWriter) ); + result.setResponseData(stringWriter.toString(), null); + result.setDataType(org.apache.jmeter.samplers.SampleResult.TEXT); + result.setResponseCode("FAILED"); + } + + System.out.println("ending runTest"); + return result; + } + + + public void close(JavaSamplerContext context) { + + + } + + private static final String mycharset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + public static String getClientId(String clientPrefix, int suffixLength) { + Random rand = new Random(System.nanoTime()*System.currentTimeMillis()); + StringBuilder sb = new StringBuilder(); + sb.append(clientPrefix); + for (int i = 0; i < suffixLength; i++) { + int pos = rand.nextInt(mycharset.length()); + sb.append(mycharset.charAt(pos)); + } + return sb.toString(); + } + + @Override + public void connectionLost(Throwable arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void deliveryComplete(IMqttDeliveryToken arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void messageArrived(String str, MqttMessage msg) throws Exception { + nummsgs.incrementAndGet(); + System.out.println("got message: " + new String(msg.getPayload())); + // TODO Auto-generated method stub + allmessages.add(new String(msg.getPayload())); + } +} diff --git a/src/main/java/org/apache/jmeter/protocol/mqttws/control/gui/MQTTPublisherGui.java b/src/main/java/org/apache/jmeter/protocol/mqttws/control/gui/MQTTPublisherGui.java new file mode 100644 index 0000000..05b3a6a --- /dev/null +++ b/src/main/java/org/apache/jmeter/protocol/mqttws/control/gui/MQTTPublisherGui.java @@ -0,0 +1,476 @@ +/** + 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. + + Copyright 2014 University Joseph Fourier, LIG Laboratory, ERODS Team + +*/ + +package org.apache.jmeter.protocol.mqttws.control.gui; +import org.apache.jmeter.gui.util.JLabeledRadioI18N; +import org.apache.jmeter.gui.util.JSyntaxTextArea; +import org.apache.jmeter.gui.util.JTextScrollPane; +import org.apache.jmeter.gui.util.VerticalPanel; +import org.apache.jmeter.protocol.mqttws.sampler.PublisherSampler; +import org.apache.jmeter.samplers.gui.AbstractSamplerGui; +import org.apache.jmeter.testelement.TestElement; +import org.apache.jmeter.util.JMeterUtils; +import org.apache.jorphan.gui.JLabeledPasswordField; +import org.apache.jorphan.gui.JLabeledTextField; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; + +/** + * @author Tuan Hiep + * + */ +public class MQTTPublisherGui extends AbstractSamplerGui implements + ChangeListener { + + private static final long serialVersionUID = 240L; + /** Take source from the named file */ + public static final String USE_FILE_RSC = "mqtt_use_file"; //$NON-NLS-1$ + /** Take source from a random file */ + public static final String USE_RANDOM_RSC = "mqtt_use_random_file"; //$NON-NLS-1$ + /** Take source from the text area */ + private static final String USE_TEXT_RSC = "mqtt_use_text"; //$NON-NLS-1$ + /** Create a TextMessage */ + public static final String TEXT_MSG_RSC = "mqtt_text_message"; //$NON-NLS-1$ + /** Create a big volume message */ + public static final String BIG_VOLUME = "mqtt_big_volume"; //$NON-NLS-1$ + /** Create a MapMessage */ + public static final String MAP_MSG_RSC = "mqtt_map_message"; //$NON-NLS-1$ + /** Create an ObjectMessage */ + public static final String OBJECT_MSG_RSC = "mqtt_object_message"; //$NON-NLS-1$ + /** Create a BytesMessage */ + public static final String BYTES_MSG_RSC = "mqtt_bytes_message"; //$NON-NLS-1$ + /** Create a message of type long number */ + public static final String LONG = "mqtt_long_value"; //$NON-NLS-1$ + /** Create a Message of type integer number */ + public static final String INT = "mqtt_int_value"; //$NON-NLS-1$ + /** Create a Message of type double number */ + public static final String DOUBLE = "mqtt_double_value"; //$NON-NLS-1$ + /** Create a Message of type double number */ + public static final String FLOAT = "mqtt_float_value"; //$NON-NLS-1$ + /** Create a Message of type String */ + public static final String STRING = "mqtt_string_value"; //$NON-NLS-1$ + + // These are the names of properties used to define the labels + private static final String DEST_SETUP_STATIC = "mqtt_dest_setup_static"; // $NON-NLS-1$ + private static final String DEST_SETUP_DYNAMIC = "mqtt_dest_setup_dynamic"; // $NON-NLS-1$ + public static final String GENERATED_VALUE = "mqtt_generated_value"; // $NON-NLS-1$ + public static final String FIXED_VALUE = "mqtt_fixed_value";// $NON-NLS-1$ + public static final String PSEUDO = "mqtt_pseudo_random";// $NON-NLS-1$ + public static final String SECURE = "mqtt_secure_random";// $NON-NLS-1$ + public static final String EXACTLY_ONCE = "mqtt_extactly_once";// $NON-NLS-1$ + public static final String AT_LEAST_ONCE = "mqtt_at_least_once";// $NON-NLS-1$ + public static final String AT_MOST_ONCE = "mqtt_at_most_once";// $NON-NLS-1$ + public static final String PLAIN_TEXT = "mqtt_plain_text";// $NON-NLS-1$ + public static final String BASE64 = "mqtt_base64";// $NON-NLS-1$ + public static final String BINHEX = "mqtt_binhex";// $NON-NLS-1$ + public static final String BINARY = "mqtt_binary";// $NON-NLS-1$ + public static final String NO_ENCODING = "mqtt_no_encoding";// $NON-NLS-1$ + public static final String ROUND_ROBIN = "mqtt_round_robin";// $NON-NLS-1$ + public static final String RANDOM = "mqtt_random";// $NON-NLS-1$ + // Button group resources + private static final String[] DEST_SETUP_ITEMS = { DEST_SETUP_STATIC,DEST_SETUP_DYNAMIC }; + private final JLabeledRadioI18N destSetup = new JLabeledRadioI18N("mqtt_dest_setup", DEST_SETUP_ITEMS, DEST_SETUP_STATIC); // $NON-NLS-1$ + private static final String[] MSGTYPES_ITEMS = { TEXT_MSG_RSC,GENERATED_VALUE,FIXED_VALUE,BIG_VOLUME }; + private static final String[] TOPIC_CHOICES={ROUND_ROBIN,RANDOM}; + private static final String[] MSGFORMAT_ITEMS = {NO_ENCODING,BINARY,BASE64,BINHEX,PLAIN_TEXT}; + private static final String[] VALTYPES_ITEMS = { INT,LONG,FLOAT,DOUBLE}; + private static final String[] FVALTYPES_ITEMS = {INT,LONG,FLOAT,DOUBLE,STRING}; + private static final String[] RANTYPES_ITEMS = {PSEUDO,SECURE}; + private static final String[] QTYPES_ITEMS = {AT_MOST_ONCE,AT_LEAST_ONCE,EXACTLY_ONCE}; + private final JLabeledTextField urlField = new JLabeledTextField(JMeterUtils.getResString("mqtt_provider_url")); //$NON-NLS-1$ + private final JLabeledTextField mqttDestination = new JLabeledTextField(JMeterUtils.getResString("mqtt_topic")); //$NON-NLS-1$ + private final JCheckBox useAuth = new JCheckBox(JMeterUtils.getResString("mqtt_use_auth"), false); //$NON-NLS-1$ + private final JLabeledTextField mqttUser = new JLabeledTextField(JMeterUtils.getResString("mqtt_user")); //$NON-NLS-1$ + private final JLabeledTextField mqttPwd = new JLabeledPasswordField(JMeterUtils.getResString("mqtt_pwd")); //$NON-NLS-1$ + private final JLabeledTextField iterations = new JLabeledTextField( JMeterUtils.getResString("mqtt_itertions")); //$NON-NLS-1$ + private final JSyntaxTextArea textMessage = new JSyntaxTextArea(10, 50); // $NON-NLS-1$ + private final JLabeledRadioI18N msgChoice = new JLabeledRadioI18N("mqtt_message_type", MSGTYPES_ITEMS, TEXT_MSG_RSC); //$NON-NLS-1$ + private final JLabeledRadioI18N msgFormat = new JLabeledRadioI18N("mqtt_message_format", MSGFORMAT_ITEMS,NO_ENCODING); //$NON-NLS-1$ + private final JLabeledRadioI18N topicChoice = new JLabeledRadioI18N("mqtt_topic_choice", TOPIC_CHOICES,ROUND_ROBIN); //$NON-NLS-1$ + private final JCheckBox connectionPerTopic = new JCheckBox(JMeterUtils.getResString("mqtt_connection_per_topic"), false); // $NON-NLS-1$ + private final JCheckBox suffixClientId = new JCheckBox(JMeterUtils.getResString("mqtt_suffix_client_id"),true); // $NON-NLS-1$ + private final JLabeledTextField suffixLength = new JLabeledTextField(JMeterUtils.getResString("mqtt_suffix_length")); //$NON-NLS-1$ + // For messages content + private final JCheckBox useTimeStamp = new JCheckBox(JMeterUtils.getResString("mqtt_use_time_stamp"), false); // $NON-NLS-1$ + private final JCheckBox useNumberSeq = new JCheckBox(JMeterUtils.getResString("mqtt_use_number_seq"), false); // $NON-NLS-1$ + private final JCheckBox isRetained = new JCheckBox(JMeterUtils.getResString("mqtt_send_as_retained_msg"), false); // $NON-NLS-1$ + private final JLabeledRadioI18N typeQoSValue = new JLabeledRadioI18N("mqtt_qos", QTYPES_ITEMS,AT_MOST_ONCE); //$NON-NLS-1$ + private final JLabeledRadioI18N typeGeneratedValue = new JLabeledRadioI18N("mqtt_type_of_generated_value", VALTYPES_ITEMS,INT); //$NON-NLS-1$ + private final JLabeledRadioI18N typeFixedValue = new JLabeledRadioI18N("mqtt_type_of_fixed_value", FVALTYPES_ITEMS,INT); //$NON-NLS-1$ + private final JLabeledTextField min = new JLabeledTextField(JMeterUtils.getResString("mqtt_min_value")); //$NON-NLS-1$ + private final JLabeledTextField max = new JLabeledTextField(JMeterUtils.getResString("mqtt_max_value")); //$NON-NLS-1$ + private final JLabeledTextField value = new JLabeledTextField(JMeterUtils.getResString("mqtt_value")); //$NON-NLS-1$ + private final JLabeledRadioI18N typeRandom = new JLabeledRadioI18N("mqtt_type_random", RANTYPES_ITEMS,PSEUDO); //$NON-NLS-1$ + private final JLabeledTextField seed = new JLabeledTextField(JMeterUtils.getResString("mqtt_seed_random")); //$NON-NLS-1$ + private final JLabel textArea = new JLabel(JMeterUtils.getResString("mqtt_text_area")); + private final JTextScrollPane textPanel = new JTextScrollPane(textMessage); + private final JLabeledTextField clientId = new JLabeledTextField(JMeterUtils.getResString("mqtt_client_id")); //$NON-NLS-1$ + private JComboBox CharsetChooser =new JComboBox(new String[] { "UTF-8", "UTF-16", "US-ASCII","UTF-16BE","UTF-16LE","ISO-8859-1"}); + private final JLabeledTextField sizeArray = new JLabeledTextField(JMeterUtils.getResString("mqtt_size_array")); //$NON-NLS-1$ + public MQTTPublisherGui() { + init(); + } + + private void init() { + setLayout(new BorderLayout()); + setBorder(makeBorder()); + add(makeTitlePanel(), BorderLayout.NORTH); + JPanel mainPanel = new VerticalPanel(); + add(mainPanel, BorderLayout.CENTER); +//-----------------------------------URL/CLIENT_ID---------------------------------------// + JPanel DPanel = new JPanel(); + DPanel.setLayout(new BoxLayout(DPanel, BoxLayout.X_AXIS)); + DPanel.add(urlField); + DPanel.add(clientId); + //DPanel.add(suffixClientId); + //DPanel.add(suffixLength); + JPanel ControlPanel = new VerticalPanel(); + ControlPanel.add(DPanel); + ControlPanel.add(createDestinationPane()); + ControlPanel.add(createAuthPane()); + ControlPanel.add(iterations); + ControlPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.gray),"Connection Info")); + mainPanel.add(ControlPanel); +//---------------------------------------Message Format----------------------------------// + JPanel FormatPanel = new JPanel(); + FormatPanel.setLayout(new BoxLayout(FormatPanel, BoxLayout.X_AXIS)); + msgFormat.setLayout(new BoxLayout(msgFormat, BoxLayout.X_AXIS)); + FormatPanel.add(msgFormat); + Dimension minSize = new Dimension(10, 15); + Dimension prefSize = new Dimension(10, 15); + Dimension maxSize = new Dimension(Short.MAX_VALUE, 100); + FormatPanel.add(new Box.Filler(minSize, prefSize, maxSize)); + FormatPanel.add(CharsetChooser); + JPanel EncodePanel = new VerticalPanel(); + EncodePanel.add(FormatPanel); + EncodePanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.gray),"Encoding")); + mainPanel.add(EncodePanel); + JPanel StampPanel = new VerticalPanel(); + StampPanel.add(useTimeStamp); + StampPanel.add(useNumberSeq); + StampPanel.add(isRetained); + typeQoSValue.setLayout(new BoxLayout(typeQoSValue, BoxLayout.X_AXIS)); + StampPanel.add(this.typeQoSValue); + StampPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.gray),"Option")); + mainPanel.add(StampPanel); +//--------------------------------------Message Type-------------------------------------// + JPanel ContentPanel = new VerticalPanel(); + msgChoice.setLayout(new BoxLayout(msgChoice, BoxLayout.X_AXIS)); + ContentPanel.add(msgChoice); + ContentPanel.add(sizeArray); + +//----------------------------------Fixed Value Panel------------------------------------// + JPanel FPanel = new JPanel(); + typeFixedValue.setLayout(new BoxLayout(typeFixedValue, BoxLayout.Y_AXIS)); + FPanel.add(typeFixedValue); + FPanel.add(value); + ContentPanel.add(FPanel); +//----------------------------------Generated Value Panel--------------------------------// + JPanel GPanel = new JPanel(); + typeGeneratedValue.setLayout(new BoxLayout(typeGeneratedValue, BoxLayout.Y_AXIS)); + GPanel.add(typeGeneratedValue); + GPanel.add(min); + GPanel.add(max); + this.typeRandom.setLayout(new BoxLayout(typeRandom, BoxLayout.Y_AXIS)); + GPanel.add(typeRandom); + GPanel.add(seed); + ContentPanel.add(GPanel); +//---------------------------------Big Volume ------------------------------------------// + + ContentPanel.add(sizeArray); +//-------------------------------------Content Panel -----------------------------------// + + JPanel messageContentPanel = new JPanel(new BorderLayout()); + messageContentPanel.add(this.textArea, BorderLayout.NORTH); + messageContentPanel.add(this.textPanel,BorderLayout.CENTER); + ContentPanel.add(messageContentPanel); + ContentPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.gray),"Content")); + mainPanel.add(ContentPanel); + useAuth.addChangeListener(this); + msgChoice.addChangeListener(this); + typeFixedValue.addChangeListener(this); + typeQoSValue.addChangeListener(this); + typeRandom.addChangeListener(this); + msgFormat.addChangeListener(this); + suffixClientId.addChangeListener(this); + + } + + /** + * + * @return JPanel Panel with checkbox to choose user and password + */ + private Component createAuthPane() { + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)); + panel.add(useAuth); + panel.add(Box.createHorizontalStrut(10)); + panel.add(mqttUser); + panel.add(Box.createHorizontalStrut(10)); + panel.add(mqttPwd); + return panel; + } + + /** + * + * @return JPanel that contains destination infos + */ + private Component createDestinationPane() { + JPanel panel = new VerticalPanel(); //new BorderLayout(3, 0) + this.mqttDestination.setLayout((new BoxLayout(mqttDestination, BoxLayout.X_AXIS))); + panel.add(mqttDestination); + JPanel TPanel = new JPanel(); + TPanel.setLayout(new BoxLayout(TPanel,BoxLayout.X_AXIS)); + this.connectionPerTopic.setLayout(new BoxLayout(connectionPerTopic,BoxLayout.X_AXIS)); + this.connectionPerTopic.setAlignmentX(CENTER_ALIGNMENT); + TPanel.add(connectionPerTopic); + TPanel.add(Box.createHorizontalStrut(100)); + this.topicChoice.setLayout(new BoxLayout(topicChoice,BoxLayout.X_AXIS)); + TPanel.add(topicChoice); + panel.add(TPanel); + return panel; + } + + /** + * To Clear the GUI + */ + @Override + public void clearGui() { + super.clearGui(); + urlField.setText(""); // $NON-NLS-1$ + mqttDestination.setText(""); // $NON-NLS-1$ + mqttUser.setText(""); // $NON-NLS-1$ + mqttPwd.setText(""); // $NON-NLS-1$ + textMessage.setInitialText(""); // $NON-NLS-1$ + msgChoice.setText(""); // $NON-NLS-1$ + updateConfig(USE_TEXT_RSC); + msgChoice.setText(TEXT_MSG_RSC); + iterations.setText("1"); // $NON-NLS-1$ + useAuth.setSelected(false); + mqttUser.setEnabled(false); + mqttPwd.setEnabled(false); + destSetup.setText(DEST_SETUP_STATIC); + textArea.setText(""); + clientId.setText(""); + connectionPerTopic.setSelected(false); + + + } + + private void setupSamplerProperties(PublisherSampler sampler) { + this.configureTestElement(sampler); + sampler.setProviderUrl(urlField.getText()); + sampler.setDestination(mqttDestination.getText()); + sampler.setUsername(mqttUser.getText()); + sampler.setPassword(mqttPwd.getText()); + sampler.setTextMessage(textMessage.getText()); + sampler.setMessageChoice(msgChoice.getText()); + sampler.setIterations(iterations.getText()); + sampler.setUseAuth(useAuth.isSelected()); + sampler.setQuality(typeQoSValue.getText()); + sampler.setRetained(isRetained.isSelected()); + sampler.setTYPE_FIXED_VALUE(typeFixedValue.getText()); + sampler.setFIXED_VALUE(this.value.getText()); + sampler.setTYPE_RANDOM_VALUE(this.typeRandom.getText()); + sampler.setMAX_RANDOM_VALUE(this.max.getText()); + sampler.setMIN_RANDOM_VALUE(this.min.getText()); + sampler.setTYPE_GENERATED_VALUE(this.typeGeneratedValue.getText()); + sampler.setSEED(this.seed.getText()); + sampler.setUSE_TIMESTAMP(useTimeStamp.isSelected()); + sampler.setUSE_NUMBER_SEQUENCE(useNumberSeq.isSelected()); + sampler.setCLIENT_ID(clientId.getText()); + sampler.setFORMAT(msgFormat.getText()); + sampler.setCHARSET((String) this.CharsetChooser.getSelectedItem()); + sampler.setSIZE_ARRAY(this.sizeArray.getText()); + sampler.setSTRATEGY(this.topicChoice.getText()); + sampler.setOneConnectionPerTopic(this.connectionPerTopic.isSelected()); + //we might need this in future + //sampler.setRandomSuffix(this.suffixClientId.isSelected()); + sampler.setRandomSuffix(false); + sampler.setLength(this.suffixLength.getText()); + } + + /** + * the implementation loads the URL and the soap action for the request. + */ + @Override + public void configure(TestElement el) { + super.configure(el); + PublisherSampler sampler = (PublisherSampler) el; + urlField.setText(sampler.getProviderUrl()); + mqttDestination.setText(sampler.getDestination()); + mqttUser.setText(sampler.getUsername()); + mqttPwd.setText(sampler.getPassword()); + textMessage.setInitialText(sampler.getTextMessage()); + textMessage.setCaretPosition(0); + clientId.setText(sampler.getCLIENT_ID()); + connectionPerTopic.setSelected(sampler.isOneConnectionPerTopic()); + msgChoice.setText(sampler.getMessageChoice()); + iterations.setText(sampler.getIterations()); + useAuth.setSelected(sampler.isUseAuth()); + mqttUser.setEnabled(useAuth.isSelected()); + mqttPwd.setEnabled(useAuth.isSelected()); + updateChoice(msgChoice.getText()); + updateChoice(msgFormat.getText()); + updateChoice("Suffix=" + String.valueOf(this.suffixClientId.isSelected())); + + } + + @Override + public TestElement createTestElement() { + PublisherSampler sampler = new PublisherSampler(); + setupSamplerProperties(sampler); + return sampler; + } + /** + * To Update the parameter of field in the GUI + * + * @param command + */ + + private void updateConfig(String command) { + + if (command.equals(USE_TEXT_RSC)) { + textMessage.setEnabled(true); + + } + + } + + @Override + public String getLabelResource() { + return "mqtt_publisher"; //$NON-NLS-1$ + } + + @Override + public void modifyTestElement(TestElement s) { + PublisherSampler sampler = (PublisherSampler) s; + setupSamplerProperties(sampler); + } + + /** + * When we change some parameter by clicking on the GUI + */ + @Override + public void stateChanged(ChangeEvent event) { + + + if (event.getSource() == msgChoice) { + updateChoice(msgChoice.getText()); + } else if (event.getSource() == useAuth) { + mqttUser.setEnabled(useAuth.isSelected()); + mqttPwd.setEnabled(useAuth.isSelected()); + } + else if (event.getSource()==msgFormat){ + updateChoice(msgFormat.getText()); + } + else if(event.getSource()==suffixClientId){ + updateChoice("Suffix="+String.valueOf(this.suffixClientId.isSelected())); + } + } + + /** + * To Update the choice of message to send + * + * @param command + */ + private void updateChoice(String command) { + + if(TEXT_MSG_RSC.equals(command)){ + this.typeGeneratedValue.setVisible(false); + this.typeFixedValue.setVisible(false); + this.max.setVisible(false); + this.min.setVisible(false); + this.value.setVisible(false); + this.typeRandom.setVisible(false); + this.seed.setVisible(false); + this.textArea.setVisible(true); + this.textPanel.setVisible(true); + this.sizeArray.setVisible(false); } + else if(GENERATED_VALUE.equals(command)) { + this.typeFixedValue.setVisible(false); + this.value.setVisible(false); + this.textArea.setVisible(false); + this.textPanel.setVisible(false); + this.typeGeneratedValue.setVisible(true); + this.max.setVisible(true); + this.min.setVisible(true); + this.typeRandom.setVisible(true); + this.seed.setVisible(true); + this.sizeArray.setVisible(false); + } else if(FIXED_VALUE.equals(command)){ + this.typeGeneratedValue.setVisible(false); + this.typeFixedValue.setVisible(true); + this.max.setVisible(false); + this.min.setVisible(false); + this.value.setVisible(true); + this.typeRandom.setVisible(false); + this.seed.setVisible(false); + this.textArea.setVisible(false); + this.textPanel.setVisible(false); + this.sizeArray.setVisible(false); } + else if(BIG_VOLUME.equals(command)){ + this.typeGeneratedValue.setVisible(false); + this.typeFixedValue.setVisible(false); + this.max.setVisible(false); + this.min.setVisible(false); + this.value.setVisible(false); + this.typeRandom.setVisible(false); + this.seed.setVisible(false); + this.textArea.setVisible(false); + this.textPanel.setVisible(false); + this.sizeArray.setVisible(true); + } + else if(BINARY.equals(command)){ + this.CharsetChooser.setVisible(false); + } + else if(BINHEX.equals(command)){ + this.CharsetChooser.setVisible(false); + } + else if(BASE64.equals(command)){ + this.CharsetChooser.setVisible(false); + } + else if(PLAIN_TEXT.equals(command)){ + this.CharsetChooser.setVisible(true); + } + else if(NO_ENCODING.equals(command)){ + this.CharsetChooser.setVisible(false); + } + else if("suffix=true".equalsIgnoreCase(command)){ + this.suffixLength.setVisible(true); + + } + else if("suffix=false".equalsIgnoreCase(command)){ + this.suffixLength.setVisible(false); + } + validate(); + } + +} + \ No newline at end of file diff --git a/src/main/java/org/apache/jmeter/protocol/mqttws/control/gui/MQTTSubscriberGui.java b/src/main/java/org/apache/jmeter/protocol/mqttws/control/gui/MQTTSubscriberGui.java new file mode 100644 index 0000000..4300729 --- /dev/null +++ b/src/main/java/org/apache/jmeter/protocol/mqttws/control/gui/MQTTSubscriberGui.java @@ -0,0 +1,247 @@ +/** + 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. + + Copyright 2014 University Joseph Fourier, LIG Laboratory, ERODS Team + +*/ + +package org.apache.jmeter.protocol.mqttws.control.gui; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; + +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JCheckBox; +import javax.swing.JPanel; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import org.apache.jmeter.gui.util.JLabeledRadioI18N; +import org.apache.jmeter.gui.util.VerticalPanel; +import org.apache.jmeter.protocol.mqttws.sampler.SubscriberSampler; +import org.apache.jmeter.samplers.gui.AbstractSamplerGui; +import org.apache.jmeter.testelement.TestElement; +import org.apache.jmeter.util.JMeterUtils; +import org.apache.jorphan.gui.JLabeledPasswordField; +import org.apache.jorphan.gui.JLabeledTextField; + +/** + * This is the GUI for mqtt Subscriber
+ * + */ +public class MQTTSubscriberGui extends AbstractSamplerGui implements ChangeListener { + + private static final long serialVersionUID = 240L; + public static final String AT_MOST_ONCE = "mqtt_at_most_once";// $NON-NLS-1$ + public static final String EXACTLY_ONCE = "mqtt_extactly_once";// $NON-NLS-1$ + public static final String AT_LEAST_ONCE = "mqtt_at_least_once";// $NON-NLS-1$ + private static final String[] QTYPES_ITEMS = {AT_MOST_ONCE,AT_LEAST_ONCE,EXACTLY_ONCE}; + public static final String ROUND_ROBIN = "mqtt_round_robin";// $NON-NLS-1$ + public static final String RANDOM = "mqtt_random";// $NON-NLS-1$ + private static final String[] TOPIC_CHOICES={ROUND_ROBIN,RANDOM}; + private final JLabeledTextField urlField = new JLabeledTextField(JMeterUtils.getResString("mqtt_provider_url")); // $NON-NLS-1$ + private final JLabeledTextField mqttDestination = new JLabeledTextField(JMeterUtils.getResString("mqtt_topic")); // $NON-NLS-1$ + private final JLabeledTextField mqttUser = new JLabeledTextField(JMeterUtils.getResString("mqtt_user")); // $NON-NLS-1$ + private final JLabeledTextField mqttPwd = new JLabeledPasswordField(JMeterUtils.getResString("mqtt_pwd")); // $NON-NLS-1$ + private final JCheckBox useAuth = new JCheckBox(JMeterUtils.getResString("mqtt_use_auth"), false); //$NON-NLS-1$ + private final JLabeledTextField timeout = new JLabeledTextField(JMeterUtils.getResString("mqtt_timeout")); //$NON-NLS-1$ + private final JLabeledTextField separator = new JLabeledTextField(JMeterUtils.getResString("mqtt_separator")); //$NON-NLS-1$ + private final JCheckBox suffixClientId = new JCheckBox(JMeterUtils.getResString("mqtt_suffix_client_id"),true); // $NON-NLS-1$ + private final JLabeledTextField suffixLength = new JLabeledTextField(JMeterUtils.getResString("mqtt_suffix_length")); //$NON-NLS-1$ + private final JCheckBox connectionPerTopic = new JCheckBox(JMeterUtils.getResString("mqtt_connection_per_topic"), false); // $NON-NLS-1$ + private final JLabeledRadioI18N topicChoice = new JLabeledRadioI18N("mqtt_topic_choice", TOPIC_CHOICES,ROUND_ROBIN); //$NON-NLS-1$ + private final JCheckBox stopBetweenSamples = new JCheckBox(JMeterUtils.getResString("mqtt_stop_between_samples"), true); // $NON-NLS-1$ + private final JLabeledTextField clientId = new JLabeledTextField(JMeterUtils.getResString("mqtt_client_id")); //$NON-NLS-1$ + private final JLabeledRadioI18N typeQoSValue = new JLabeledRadioI18N("mqtt_qos", QTYPES_ITEMS,AT_MOST_ONCE); //$NON-NLS-1$ + private final JCheckBox cleanSession = new JCheckBox(JMeterUtils.getResString("mqtt_clean_session"), false); // $NON-NLS-1$ + private final JLabeledTextField iterations = new JLabeledTextField( JMeterUtils.getResString("mqtt_itertions")); //$NON-NLS-1$ + + public MQTTSubscriberGui() { + init(); + } + + @Override + public String getLabelResource() { + return "mqtt_subscriber_title"; // $NON-NLS-1$ + } + + /** + * @see org.apache.jmeter.gui.JMeterGUIComponent#createTestElement() + */ + @Override + public TestElement createTestElement() { + SubscriberSampler sampler = new SubscriberSampler(); + modifyTestElement(sampler); + return sampler; + } + + /** + * Modifies a given TestElement to mirror the data in the gui components. + * + * @see org.apache.jmeter.gui.JMeterGUIComponent#modifyTestElement(TestElement) + */ + @Override + public void modifyTestElement(TestElement s) { + SubscriberSampler sampler = (SubscriberSampler) s; + this.configureTestElement(sampler); + sampler.setProviderUrl(urlField.getText()); + sampler.setDestination(mqttDestination.getText()); + sampler.setClientID(clientId.getText()); + sampler.setUsername(mqttUser.getText()); + sampler.setPassword(mqttPwd.getText()); + sampler.setUseAuth(useAuth.isSelected()); + sampler.setTimeout(timeout.getText()); + sampler.setIterations(iterations.getText()); + //we might need this in future - for now it's causing problems + //sampler.setRandomSuffix(this.suffixClientId.isSelected()); + sampler.setRandomSuffix(false); + sampler.setLength(this.suffixLength.getText()); + sampler.setOneConnectionPerTopic(this.connectionPerTopic.isSelected()); + sampler.setSTRATEGY(this.topicChoice.getText()); + sampler.setQuality(typeQoSValue.getText()); + sampler.setCLEANSESSION(cleanSession.isSelected()); + + } + + private void init() { + setLayout(new BorderLayout()); + setBorder(makeBorder()); + add(makeTitlePanel(), BorderLayout.NORTH); + JPanel mainPanel = new VerticalPanel(); + add(mainPanel, BorderLayout.CENTER); + JPanel DPanel = new JPanel(); + DPanel.setLayout(new BoxLayout(DPanel, BoxLayout.X_AXIS)); + DPanel.add(urlField); + DPanel.add(clientId); + //DPanel.add(suffixClientId); + //DPanel.add(suffixLength); + JPanel ControlPanel = new VerticalPanel(); + ControlPanel.add(DPanel); + ControlPanel.add(createDestinationPane()); + ControlPanel.add(cleanSession); + ControlPanel.add(createAuthPane()); + ControlPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.gray),"Connection Info")); + mainPanel.add(ControlPanel); + JPanel TPanel = new VerticalPanel(); + TPanel.setLayout(new BoxLayout(TPanel, BoxLayout.X_AXIS)); + timeout.setLayout(new BoxLayout(timeout, BoxLayout.X_AXIS)); + iterations.setLayout(new BoxLayout(iterations, BoxLayout.X_AXIS)); + typeQoSValue.setLayout(new BoxLayout(typeQoSValue, BoxLayout.X_AXIS)); + TPanel.add(typeQoSValue); + TPanel.add(timeout); + TPanel.add(iterations); + TPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.gray),"Option")); + mainPanel.add(TPanel); + useAuth.addChangeListener(this); + suffixClientId.addChangeListener(this); + + } + /** + * + * @return JPanel Panel with checkbox to choose user and password + */ + private Component createAuthPane() { + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)); + panel.add(useAuth); + panel.add(Box.createHorizontalStrut(10)); + panel.add(mqttUser); + panel.add(Box.createHorizontalStrut(10)); + panel.add(mqttPwd); + return panel; + } + /** + * the implementation loads the URL and the soap action for the request. + */ + @Override + public void configure(TestElement el) { + super.configure(el); + SubscriberSampler sampler = (SubscriberSampler) el; + urlField.setText(sampler.getProviderUrl()); + mqttDestination.setText(sampler.getDestination()); + clientId.setText(sampler.getClientId()); + mqttUser.setText(sampler.getUsername()); + mqttPwd.setText(sampler.getPassword()); + useAuth.setSelected(sampler.isUseAuth()); + mqttUser.setEnabled(useAuth.isSelected()); + mqttPwd.setEnabled(useAuth.isSelected()); + timeout.setText(sampler.getTimeout()); + iterations.setText(sampler.getIterations()); + } + + @Override + public void clearGui(){ + super.clearGui(); + urlField.setText(""); // $NON-NLS-1$ + mqttDestination.setText(""); // $NON-NLS-1$ + clientId.setText(""); // $NON-NLS-1$ + mqttUser.setText(""); // $NON-NLS-1$ + mqttPwd.setText(""); // $NON-NLS-1$ + timeout.setText(""); // $NON-NLS-1$ + iterations.setText("1");// $NON-NLS-1$ + separator.setText(""); // $NON-NLS-1$ + useAuth.setSelected(false); + mqttUser.setEnabled(false); + mqttPwd.setEnabled(false); + stopBetweenSamples.setSelected(false); + + } + + /** + * When the state of a widget changes, it will notify the gui. the method + * then enables or disables certain parameters. + */ + @Override + public void stateChanged(ChangeEvent event) { + if (event.getSource() == useAuth) { + mqttUser.setEnabled(useAuth.isSelected()); + mqttPwd.setEnabled(useAuth.isSelected()); + } + else if(event.getSource()==suffixClientId){ + updateChoice("Suffix="+String.valueOf(this.suffixClientId.isSelected())); + } + } + + private void updateChoice(String command) { + if("suffix=true".equalsIgnoreCase(command)){ + this.suffixLength.setVisible(true); + } + else if("suffix=false".equalsIgnoreCase(command)){ + this.suffixLength.setVisible(false); + } + validate(); + } + + private JPanel createDestinationPane() { + JPanel panel = new VerticalPanel(); //new BorderLayout(3, 0) + this.mqttDestination.setLayout((new BoxLayout(mqttDestination, BoxLayout.X_AXIS))); + panel.add(mqttDestination); + JPanel TPanel = new JPanel(); + TPanel.setLayout(new BoxLayout(TPanel,BoxLayout.X_AXIS)); + this.connectionPerTopic.setLayout(new BoxLayout(connectionPerTopic,BoxLayout.X_AXIS)); + this.connectionPerTopic.setAlignmentX(CENTER_ALIGNMENT); + TPanel.add(connectionPerTopic); + TPanel.add(Box.createHorizontalStrut(100)); + this.topicChoice.setLayout(new BoxLayout(topicChoice,BoxLayout.X_AXIS)); + TPanel.add(topicChoice); + panel.add(TPanel); + return panel; + } +} \ No newline at end of file diff --git a/src/main/java/org/apache/jmeter/protocol/mqttws/sampler/BaseMQTTSampler.java b/src/main/java/org/apache/jmeter/protocol/mqttws/sampler/BaseMQTTSampler.java new file mode 100644 index 0000000..7583f4a --- /dev/null +++ b/src/main/java/org/apache/jmeter/protocol/mqttws/sampler/BaseMQTTSampler.java @@ -0,0 +1,166 @@ +/** + 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. + + Copyright 2014 University Joseph Fourier, LIG Laboratory, ERODS Team + +*/ + +package org.apache.jmeter.protocol.mqttws.sampler; +import org.apache.jmeter.samplers.AbstractSampler; +import org.apache.jmeter.samplers.Entry; +import org.apache.jmeter.samplers.SampleResult; +import org.apache.jmeter.util.JMeterUtils; + +public abstract class BaseMQTTSampler extends AbstractSampler { + private static final long serialVersionUID = 240L; + private static final String PROVIDER_URL = "mqtt.provider_url"; // $NON-NLS-1$ + private static final String DEST = "mqtt.topic"; // $NON-NLS-1$ + private static final String PRINCIPAL = "mqtt.security_principle"; // $NON-NLS-1$ + private static final String CREDENTIALS = "mqtt.security_credentials"; // $NON-NLS-1$ + private static final String ITERATIONS = "mqtt.iterations"; // $NON-NLS-1$ + private static final String USE_AUTH = "mqtt.authenticate"; // $NON-NLS-1$ + private static final String REQUIRED = JMeterUtils.getResString("mqtt_auth_required"); // $NON-NLS-1$ + + + /** + * Constructor + */ + public BaseMQTTSampler() { + } + + @Override + public SampleResult sample(Entry e) { + return this.sample(); + } + public abstract SampleResult sample() ; + + // ------------- get/set properties ----------------------// + + /** + * + * @param url the provider URL + */ + public void setProviderUrl(String url) { + setProperty(PROVIDER_URL, url); + } + + /** + * + * @return the provider URL + */ + public String getProviderUrl() { + return getPropertyAsString(PROVIDER_URL); + } + /** + * set the destination (topic or queue name) + * + * @param dest the destination + */ + public void setDestination(String dest) { + setProperty(DEST, dest); + } + /** + * return the destination (topic or queue name) + * + * @return the destination + */ + public String getDestination() { + return getPropertyAsString(DEST); + } + + /** + * set the username to login into the mqtt server if needed + * + * @param user + */ + public void setUsername(String user) { + setProperty(PRINCIPAL, user); + } + + /** + * return the username used to login to the mqtt server + * + * @return the username used to login to the mqtt server + */ + public String getUsername() { + return getPropertyAsString(PRINCIPAL); + } + /** + * Set the password to login to the mqtt server + * + * @param pwd + */ + public void setPassword(String pwd) { + setProperty(CREDENTIALS, pwd); + } + + /** + * return the password used to login to the mqtt server + * + * @return the password used to login to the mqtt server + */ + public String getPassword() { + return getPropertyAsString(CREDENTIALS); + } + /** + * set the number of iterations the sampler should aggregate + * + * @param count + */ + public void setIterations(String count) { + setProperty(ITERATIONS, count); + } + + /** + * get the iterations as string + * + * @return the number of iterations + */ + public String getIterations() { + return getPropertyAsString(ITERATIONS); + } + + /** + * return the number of iterations as int instead of string + * + * @return the number of iterations as int instead of string + */ + public int getIterationCount() { + return getPropertyAsInt(ITERATIONS); + } + + /** + * Set whether authentication is required for mqtt server + * + * @param useAuth + */ + public void setUseAuth(boolean useAuth) { + setProperty(USE_AUTH, useAuth); + } + /** + * + * + * @return whether mqtt server requires authentication + */ + public boolean isUseAuth() { + final String useAuth = getPropertyAsString(USE_AUTH); + return useAuth.equalsIgnoreCase("true") || useAuth.equals(REQUIRED); // $NON-NLS-1$ + } + + +} diff --git a/src/main/java/org/apache/jmeter/protocol/mqttws/sampler/PublisherSampler.java b/src/main/java/org/apache/jmeter/protocol/mqttws/sampler/PublisherSampler.java new file mode 100644 index 0000000..2333634 --- /dev/null +++ b/src/main/java/org/apache/jmeter/protocol/mqttws/sampler/PublisherSampler.java @@ -0,0 +1,470 @@ +/** + 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. + + Copyright 2014 University Joseph Fourier, LIG Laboratory, ERODS Team + + */ + +package org.apache.jmeter.protocol.mqttws.sampler; +import java.io.IOException; +import java.util.Date; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.jmeter.config.Arguments; +import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext; +import org.apache.jmeter.protocol.mqttws.client.MqttPublisher; +import org.apache.jmeter.protocol.mqttws.control.gui.MQTTPublisherGui; +import org.apache.jmeter.samplers.SampleResult; +import org.apache.jmeter.testelement.TestStateListener; +import org.apache.jmeter.testelement.ThreadListener; +import org.apache.jorphan.logging.LoggingManager; +import org.apache.log.Logger; + +public class PublisherSampler extends BaseMQTTSampler implements ThreadListener,TestStateListener { + + private static final long serialVersionUID = 233L; + private static final Logger log = LoggingManager.getLoggerForClass(); + private static final String TEXT_MSG = "mqtt.text_message"; //$NON-NLS-1$ + private static final String CONFIG_CHOICE = "mqtt.config_choice"; //$NON-NLS-1$ + private static final String MESSAGE_CHOICE = "mqtt.config_msg_type"; //$NON-NLS-1$ + private static final String QUALITY = "mqtt.quality"; //$NON-NLS-1$ + private static final String TYPE_FIXED_VALUE = "mqtt.type_fixed_value"; //$NON-NLS-1$ + private static String CLIENT_ID = "mqtt.clientid"; //$NON-NLS-1$ + private static String RETAIN = "mqtt.retain"; //$NON-NLS-1$ + private static String USE_TIMESTAMP = "mqtt.use_timestamp"; //$NON-NLS-1$ + private static String USE_NUMBER_SEQUENCE = "mqtt.use_number_sequence"; //$NON-NLS-1$ + private static String FIXED_VALUE = "mqtt.fixed_value"; //$NON-NLS-1$ + private static String TYPE_RANDOM_VALUE = "mqtt.type_random_value"; //$NON-NLS-1$ + private static String MIN_RANDOM_VALUE = "mqtt.min_random_value"; //$NON-NLS-1$ + private static String MAX_RANDOM_VALUE = "mqtt.max_random_value"; //$NON-NLS-1$ + private static String TYPE_GENERATED_VALUE = "mqtt.type_generated_value"; //$NON-NLS-1$ + private static String SEED = "mqtt.seed"; //$NON-NLS-1$ + private static String FORMAT = "mqtt.format"; //$NON-NLS-1$ + private static String CHARSET = "mqtt.charset"; //$NON-NLS-1$ + private static String SIZE_ARRAY = "mqtt.size_array"; //$NON-NLS-1$ + private static String STRATEGY = "mqtt.strategy"; //$NON-NLS-1$ + private static String OneConnectionPerTopic = "mqtt.one_connection_per_topic"; //$NON-NLS-1$ + private static String RandomSuffix="mqtt.random_suffix_client_id";//$NON-NLS-1$ + private static String Length="mqtt.suffix.length";//$NON-NLS-1$ + public transient MqttPublisher producer = null; + public static AtomicInteger numberOfConnection= new AtomicInteger(0); + private JavaSamplerContext context = null; + + /** + * Constructor + */ + + public PublisherSampler() { + } + + // ---------------------Get/Set Property--------------------------// + + public void setTYPE_FIXED_VALUE(String type) { + setProperty(TYPE_FIXED_VALUE, type); + } + public String getLength() { + return getPropertyAsString(Length); + } + public void setLength(String length) { + setProperty(Length,length); + } + + public boolean useRandomSuffix() { + + String randomSuffix = getPropertyAsString(RandomSuffix); + if("TRUE".equalsIgnoreCase(randomSuffix)){ + return true; + } + else { + return false; + } + + } + + public void setRandomSuffix(boolean randomSuffix) { + setProperty(RandomSuffix,randomSuffix); + + } + + public boolean isOneConnectionPerTopic() { + + String perTopic = getPropertyAsString(OneConnectionPerTopic); + if("TRUE".equalsIgnoreCase(perTopic)){ + return true; + } + else { + return false; + } + + } + public void setOneConnectionPerTopic(boolean oneConnectionPerTopic) { + + setProperty(OneConnectionPerTopic, oneConnectionPerTopic); + } + + public String getSTRATEGY() { + return getPropertyAsString(STRATEGY); + + } + + public void setSTRATEGY(String sTRATEGY) { + setProperty(STRATEGY,sTRATEGY); + + } + + public String getSIZE_ARRAY() { + return getPropertyAsString(SIZE_ARRAY); + } + + public void setSIZE_ARRAY(String sIZE_ARRAY) { + setProperty(SIZE_ARRAY,sIZE_ARRAY); + } + + public String getCHARSET() { + return getPropertyAsString(CHARSET); + } + + public void setCHARSET(String cHARSET) { + setProperty(CHARSET,cHARSET); + } + + public String getFORMAT() { + return getPropertyAsString(FORMAT); + } + + public void setFORMAT(String fORMAT) { + setProperty(FORMAT,fORMAT); + } + + public String getCLIENT_ID() { + return getPropertyAsString(CLIENT_ID); + } + + public void setCLIENT_ID(String cLIENT_ID) { + setProperty(CLIENT_ID,cLIENT_ID); + } + + public boolean isUSE_TIMESTAMP() { + String isUseTimeStamp = getPropertyAsString(USE_TIMESTAMP); + if("TRUE".equalsIgnoreCase(isUseTimeStamp)){ + return true; + } + else { + return false; + } + } + + public void setUSE_TIMESTAMP(boolean uSE_TIMESTAMP) { + setProperty(USE_TIMESTAMP,uSE_TIMESTAMP); + } + + public boolean isUSE_NUMBER_SEQUENCE() { + String isUseNumberSequence = getPropertyAsString(USE_NUMBER_SEQUENCE); + if("TRUE".equalsIgnoreCase(isUseNumberSequence)){ + return true; + } + else { + return false; + } + } + + public void setUSE_NUMBER_SEQUENCE(boolean uSE_NUMBER_SEQUENCE) { + setProperty(USE_NUMBER_SEQUENCE,uSE_NUMBER_SEQUENCE); + } + public String getSEED() { + return getPropertyAsString(SEED); + } + public void setSEED(String sEED) { + setProperty(SEED,sEED); + } + public String getTYPE_GENERATED_VALUE() { + return getPropertyAsString(TYPE_GENERATED_VALUE); + } + public void setTYPE_GENERATED_VALUE(String tYPE_GENERATED_VALUE) { + setProperty(TYPE_GENERATED_VALUE,tYPE_GENERATED_VALUE); + } + + public String getTYPE_RANDOM_VALUE() { + return getPropertyAsString(TYPE_RANDOM_VALUE); + } + + public void setTYPE_RANDOM_VALUE(String tYPE_RANDOM_VALUE) { + setProperty(TYPE_RANDOM_VALUE,tYPE_RANDOM_VALUE); + } + + public String getMIN_RANDOM_VALUE() { + return getPropertyAsString(MIN_RANDOM_VALUE); + + } + + public void setMIN_RANDOM_VALUE(String mIN_RANDOM_VALUE) { + setProperty(MIN_RANDOM_VALUE,mIN_RANDOM_VALUE); + } + + public String getMAX_RANDOM_VALUE() { + return getPropertyAsString(MAX_RANDOM_VALUE); + } + + public void setMAX_RANDOM_VALUE(String mAX_RANDOM_VALUE) { + setProperty(MAX_RANDOM_VALUE,mAX_RANDOM_VALUE); + + } + + public String getFIXED_VALUE() { + return getPropertyAsString( FIXED_VALUE); + + } + + public void setFIXED_VALUE(String fIXED_VALUE) { + setProperty(FIXED_VALUE,fIXED_VALUE); + + } + + public String getTYPE_FIXED_VALUE() { + return getPropertyAsString(TYPE_FIXED_VALUE); + + } + public void setTextMessage(String message) { + setProperty(TEXT_MSG, message); + } + public void setConfigChoice(String choice) { + setProperty(CONFIG_CHOICE, choice); + + } + + public void setMessageChoice(String choice) { + setProperty(MESSAGE_CHOICE, choice); + + } + + public String getTextMessage() { + return getPropertyAsString(TEXT_MSG); + } + + /** + * To get the message choice + * + * @return + */ + public String getMessageChoice() { + return getPropertyAsString(MESSAGE_CHOICE); + } + + public String getQuality() { + return getPropertyAsString(QUALITY); + } + + public void setQuality(String quality) { + setProperty(QUALITY, quality); + } + + public void setRetained(boolean isRetained) { + + setProperty(RETAIN,isRetained); + } + + public boolean isRetained() { + String isRetain = getPropertyAsString(RETAIN); + if("TRUE".equalsIgnoreCase(isRetain)){ + return true; + } + else { + return false; + } + + } + + + private void logThreadStart() { + if (log.isDebugEnabled()) { + log.debug("Thread started " + new Date()); + log.debug("MQTT PublishSampler: [" + + Thread.currentThread().getName() + "], hashCode=[" + + hashCode() + "]"); + + } + + } + + @Override + public void threadStarted() { + logThreadStart(); + + if (producer == null) { + + try { + producer = new MqttPublisher(); + } catch (Exception e) { + log.warn(e.getLocalizedMessage(), e); + } + } + + this.producer.setupTest(this.context); + } + + @Override + public void threadFinished() { + log.debug("Thread ended " + new Date()); + + if (producer != null) { + + + } + + } + + // -------------------------Sample------------------------------------// + + @Override + public SampleResult sample() { + //get context just prior to our actual sampling + //so that we won't miss any updates by other samplers + //made prior to that point + context = getSamplerContext(); + return this.producer.runTest(context); + } + + @Override + public void testEnded() { + log.debug("Thread ended " + new Date()); + if (producer != null) { + } + } + + @Override + public void testEnded(String arg0) { + testEnded(); + } + + @Override + public void testStarted() { + } + + @Override + public void testStarted(String arg0) { + testStarted(); + } + + public JavaSamplerContext getSamplerContext() { + String host = getProviderUrl(); + String list_topic = getDestination(); + String aggregate = "" + getIterationCount(); + Arguments parameters = new Arguments(); + parameters.addArgument("SAMPLER_NAME", this.getName()); + parameters.addArgument("HOST", host); + // ------------------------ClientId-----------------------------------// + parameters.addArgument("CLIENT_ID", getCLIENT_ID()); + parameters.addArgument("TOPIC", list_topic); + + // ------------------------Strategy-----------------------------------// + if (MQTTPublisherGui.ROUND_ROBIN.equals(this.getSTRATEGY())) { + parameters.addArgument("STRATEGY", "ROUND_ROBIN"); + } else { + parameters.addArgument("STRATEGY", "RANDOM"); + } + + parameters.addArgument("AGGREGATE", aggregate); + + String quality = getQuality(); + parameters.addArgument("QOS", quality); + if (this.isRetained()) { + parameters.addArgument("RETAINED", "TRUE"); + } else { + parameters.addArgument("RETAINED", "FALSE"); + } + // -------------------------TimeStamp-----------------------------// + + if (this.isUSE_TIMESTAMP()) { + parameters.addArgument("TIME_STAMP", "TRUE"); + } else + parameters.addArgument("TIME_STAMP", "FALSE"); + + // -------------------------Number Sequence-----------------------// + + if (this.isUSE_NUMBER_SEQUENCE()) { + parameters.addArgument("NUMBER_SEQUENCE", "TRUE"); + } else + parameters.addArgument("NUMBER_SEQUENCE", "FALSE"); + + // ---------------------Message Choice----------------------------// + + if (this.getMessageChoice().equals(MQTTPublisherGui.TEXT_MSG_RSC)) { + + parameters.addArgument("MESSAGE", getTextMessage()); + parameters.addArgument("TYPE_MESSAGE", "TEXT"); + parameters.addArgument("TYPE_VALUE", "TEXT"); + } else if (this.getMessageChoice().equals(MQTTPublisherGui.FIXED_VALUE)) { + + parameters.addArgument("MESSAGE", getFIXED_VALUE()); + parameters.addArgument("TYPE_MESSAGE", "FIXED"); + parameters.addArgument("TYPE_VALUE", getTYPE_FIXED_VALUE()); + } else if (this.getMessageChoice().equals( + MQTTPublisherGui.GENERATED_VALUE)) { + parameters.addArgument("TYPE_MESSAGE", "RANDOM"); + parameters.addArgument("TYPE_VALUE", getTYPE_GENERATED_VALUE()); + parameters.addArgument("SEED", getSEED()); + parameters.addArgument("MIN_RANDOM_VALUE", getMIN_RANDOM_VALUE()); + parameters.addArgument("MAX_RANDOM_VALUE", getMAX_RANDOM_VALUE()); + parameters.addArgument("TYPE_RANDOM_VALUE", getTYPE_RANDOM_VALUE()); + } else if (this.getMessageChoice().equals(MQTTPublisherGui.BIG_VOLUME)) { + parameters.addArgument("TYPE_MESSAGE", "BYTE_ARRAY"); + parameters.addArgument("SIZE_ARRAY", this.getSIZE_ARRAY()); + } + + // -----------------------User/Password-------------------------------// + + if (this.isUseAuth()) { + parameters.addArgument("AUTH", "TRUE"); + parameters.addArgument("USER", getUsername()); + parameters.addArgument("PASSWORD", getPassword()); + } else + parameters.addArgument("AUTH", "FALSE"); + // -----------------------Format--------------------------------------// + parameters.addArgument("FORMAT", getFORMAT()); + if (this.getFORMAT().equals(MQTTPublisherGui.PLAIN_TEXT)) { + parameters.addArgument("CHARSET", getCHARSET()); + + } else + parameters.addArgument("CHARSET", "NULL"); + + // -------------------------List Topic Or Not-------------------------// + + String[] topics = list_topic.split("\\s*,\\s*"); + if (topics.length <= 1) { + parameters.addArgument("LIST_TOPIC", "FALSE"); + } else { + parameters.addArgument("LIST_TOPIC", "TRUE"); + } + // ------------------------Connection per topic--------------------// + + if (this.isOneConnectionPerTopic()) { + parameters.addArgument("PER_TOPIC", "TRUE"); + } else { + parameters.addArgument("PER_TOPIC", "FALSE"); + } + if(this.useRandomSuffix()){ + parameters.addArgument("RANDOM_SUFFIX","TRUE"); + parameters.addArgument("SUFFIX_LENGTH",this.getLength()); + }else { + parameters.addArgument("RANDOM_SUFFIX","FALSE"); + } + + return new JavaSamplerContext(parameters); + } + +} diff --git a/src/main/java/org/apache/jmeter/protocol/mqttws/sampler/SubscriberSampler.java b/src/main/java/org/apache/jmeter/protocol/mqttws/sampler/SubscriberSampler.java new file mode 100644 index 0000000..40d75e2 --- /dev/null +++ b/src/main/java/org/apache/jmeter/protocol/mqttws/sampler/SubscriberSampler.java @@ -0,0 +1,305 @@ +/** + 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. + + Copyright 2014 University Joseph Fourier, LIG Laboratory, ERODS Team + + */ + +package org.apache.jmeter.protocol.mqttws.sampler; + +import java.util.Date; + +import org.apache.jmeter.config.Arguments; +import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext; +//import org.apache.jmeter.protocol.mqtt.client.ListenerforSubscribe; +import org.apache.jmeter.protocol.mqttws.client.MqttSubscriber; +import org.apache.jmeter.protocol.mqttws.control.gui.MQTTPublisherGui; +import org.apache.jmeter.samplers.Interruptible; +import org.apache.jmeter.samplers.SampleResult; +import org.apache.jmeter.testelement.TestStateListener; +import org.apache.jmeter.testelement.ThreadListener; +import org.apache.jorphan.logging.LoggingManager; +import org.apache.log.Logger; + +public class SubscriberSampler extends BaseMQTTSampler implements + Interruptible, ThreadListener, TestStateListener { + + private static final long serialVersionUID = 240L; + private static final Logger log = LoggingManager.getLoggerForClass(); + private static final String DURABLE_SUBSCRIPTION_ID = "mqtt.durableSubscriptionId"; // $NON-NLS-1$ + private static final String DURABLE_SUBSCRIPTION_ID_DEFAULT = ""; + private static final String CLIENT_ID = "mqtt.clientId"; // $NON-NLS-1$ + private static final String CLIENT_ID_DEFAULT = ""; // $NON-NLS-1$ + private static final String TIMEOUT = "mqtt.timeout"; // $NON-NLS-1$ + private static final String TIMEOUT_DEFAULT = "30000"; // $NON-NLS-1$ + private static final String QUALITY = "mqtt.quality"; //$NON-NLS-1$ + private static String OneConnectionPerTopic = "mqtt.one_connection_per_topic"; //$NON-NLS-1$ + public transient MqttSubscriber subscriber = null; + private JavaSamplerContext context = null; + private static String Length = "mqtt.suffix.length";//$NON-NLS-1$ + private static String RandomSuffix = "mqtt.random_suffix_client_id";//$NON-NLS-1$ + private static String STRATEGY = "mqtt.strategy"; //$NON-NLS-1$ + private static String CLEAN_SESSION="mqtt.clean.session";//$NON-NLS-1$ + + public SubscriberSampler() { + super(); + } + + public String getCLEANSESSION() { + return getPropertyAsString(CLEAN_SESSION); + } + + public void setCLEANSESSION(boolean cLEANSESSION) { + + if(cLEANSESSION) { + setProperty(CLEAN_SESSION, "true"); + } + else + setProperty(CLEAN_SESSION, "false"); + } + + public void setOneConnectionPerTopic(boolean oneConnectionPerTopic) { + setProperty(OneConnectionPerTopic, oneConnectionPerTopic); + } + + public boolean isOneConnectionPerTopic() { + String perTopic = getPropertyAsString(OneConnectionPerTopic); + if ("TRUE".equalsIgnoreCase(perTopic)) { + return true; + } else { + return false; + } + + } + + public void setQuality(String quality) { + setProperty(QUALITY, quality); + } + + private String getQuality() { + return getPropertyAsString(QUALITY); + } + + public String getSTRATEGY() { + return getPropertyAsString(STRATEGY); + + } + + public void setSTRATEGY(String sTRATEGY) { + setProperty(STRATEGY, sTRATEGY); + + } + + public void setDurableSubscriptionId(String durableSubscriptionId) { + setProperty(DURABLE_SUBSCRIPTION_ID, durableSubscriptionId, + DURABLE_SUBSCRIPTION_ID_DEFAULT); + } + + public void setClientID(String clientId) { + setProperty(CLIENT_ID, clientId, CLIENT_ID_DEFAULT); + + } + + public void setTimeout(String timeout) { + setProperty(TIMEOUT, timeout, TIMEOUT_DEFAULT); + } + + public String getDurableSubscriptionId() { + return getPropertyAsString(DURABLE_SUBSCRIPTION_ID); + } + + public String getClientId() { + return getPropertyAsString(CLIENT_ID, CLIENT_ID_DEFAULT); + } + + public String getTimeout() { + return getPropertyAsString(TIMEOUT, TIMEOUT_DEFAULT); + } + + public void setRandomSuffix(boolean randomSuffix) { + setProperty(RandomSuffix, randomSuffix); + + } + + public boolean useRandomSuffix() { + String randomSuffix = getPropertyAsString(RandomSuffix); + if ("TRUE".equalsIgnoreCase(randomSuffix)) { + return true; + } else { + return false; + } + } + + public void setLength(String length) { + setProperty(Length, length); + } + + public String getLength() { + return getPropertyAsString(Length); + } + + @Override + public boolean interrupt() { + + System.out.println("Hello interrupt"); + //System.out.println("Received " + ListenerforSubscribe.count.get() +" messages"); + log.debug("Thread ended " + new Date()); + if (this.subscriber != null) { + try { + this.subscriber.close(context); + + } catch (Exception e) { + e.printStackTrace(); + log.warn(e.getLocalizedMessage(), e); + } + + } + return false; + } + + @Override + public void testEnded() { + log.debug("Thread ended " + new Date()); + //System.out.println("Received " + ListenerforSubscribe.count.get() +" messages"); + if (this.subscriber != null) { + try { + this.subscriber.close(context); + + } catch (Exception e) { + e.printStackTrace(); + log.warn(e.getLocalizedMessage(), e); + } + + } + } + + @Override + public void testEnded(String arg0) { + testEnded(); + } + + @Override + public void testStarted() { + } + + @Override + public void testStarted(String arg0) { + testStarted(); + } + + // ------------------------------ For Thread---------------------------------// + + private void logThreadStart() { + if (log.isDebugEnabled()) { + log.debug("Thread started " + new Date()); + log.debug("MQTTSampler: [" + Thread.currentThread().getName() + + "], hashCode=[" + hashCode() + "]"); + } + } + + @Override + public void threadStarted() { + logThreadStart(); + if (subscriber == null) { + try { + subscriber = new MqttSubscriber(); + } catch (Exception e) { + log.warn(e.getLocalizedMessage(), e); + } + } + subscriber.setupTest(context); + } + + @Override + public void threadFinished() { + log.debug("Thread ended " + new Date()); + //System.out.println("Received " + ListenerforSubscribe.count.get() +" messages"); + if (this.subscriber != null) { + try { + this.subscriber.close(context); + + } catch (Exception e) { + e.printStackTrace(); + log.warn(e.getLocalizedMessage(), e); + } + } + } + + @Override + public SampleResult sample() { + //get context just prior to our actual sampling + //so that we won't miss any updates by other samplers + //made prior to that point + context = getSamplerContext(); + return this.subscriber.runTest(context); + } + + //get sampler's JMeter context + public JavaSamplerContext getSamplerContext() { + String host = getProviderUrl(); + String list_topic = getDestination(); + String aggregate = "" + getIterationCount(); + String clientId = getClientId(); + String timeout = this.getTimeout(); + Arguments parameters = new Arguments(); + parameters.addArgument("SAMPLER_NAME", this.getName()); + parameters.addArgument("HOST", host); + parameters.addArgument("CLIENT_ID", clientId); + parameters.addArgument("TOPIC", list_topic); + // ------------------------Strategy-----------------------------------// + if (MQTTPublisherGui.ROUND_ROBIN.equals(this.getSTRATEGY())) { + parameters.addArgument("STRATEGY", "ROUND_ROBIN"); + } else { + parameters.addArgument("STRATEGY", "RANDOM"); + } + parameters.addArgument("AGGREGATE", aggregate); + String quality = getQuality(); + parameters.addArgument("QOS", quality); + parameters.addArgument("DURABLE",this.getCLEANSESSION()); + parameters.addArgument("TIMEOUT", timeout); + + if (this.isUseAuth()) { + parameters.addArgument("AUTH", "TRUE"); + parameters.addArgument("USER", getUsername()); + parameters.addArgument("PASSWORD", getPassword()); + } else + parameters.addArgument("AUTH", "FALSE"); + // -------------------------List Topic Or Not-------------------------// + + String[] topics = list_topic.split("\\s*,\\s*"); + if (topics.length <= 1) { + parameters.addArgument("LIST_TOPIC", "FALSE"); + } else { + parameters.addArgument("LIST_TOPIC", "TRUE"); + } + // ------------------------Connection per topic--------------------// + + if (this.isOneConnectionPerTopic()) { + parameters.addArgument("PER_TOPIC", "TRUE"); + } else { + parameters.addArgument("PER_TOPIC", "FALSE"); + } + if (this.useRandomSuffix()) { + parameters.addArgument("RANDOM_SUFFIX", "TRUE"); + parameters.addArgument("SUFFIX_LENGTH", this.getLength()); + } else { + parameters.addArgument("RANDOM_SUFFIX", "FALSE"); + } + return new JavaSamplerContext(parameters); + } +}