jmeter_perf 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +19 -0
- data/.standard.yml +4 -0
- data/CHANGELOG.md +18 -0
- data/DSL.md +235 -0
- data/README.md +24 -0
- data/Rakefile +12 -0
- data/example/Gemfile +39 -0
- data/example/Gemfile.lock +232 -0
- data/example/README.md +3 -0
- data/example/Rakefile +6 -0
- data/example/app/controllers/application_controller.rb +2 -0
- data/example/app/controllers/test_controller.rb +15 -0
- data/example/bin/bundle +109 -0
- data/example/bin/docker-entrypoint +8 -0
- data/example/bin/rails +4 -0
- data/example/bin/rake +4 -0
- data/example/bin/setup +33 -0
- data/example/config/application.rb +44 -0
- data/example/config/boot.rb +3 -0
- data/example/config/credentials.yml.enc +1 -0
- data/example/config/database.yml +25 -0
- data/example/config/environment.rb +5 -0
- data/example/config/environments/development.rb +64 -0
- data/example/config/environments/production.rb +82 -0
- data/example/config/environments/test.rb +61 -0
- data/example/config/initializers/cors.rb +16 -0
- data/example/config/initializers/filter_parameter_logging.rb +8 -0
- data/example/config/initializers/inflections.rb +16 -0
- data/example/config/locales/en.yml +31 -0
- data/example/config/puma.rb +35 -0
- data/example/config/routes.rb +5 -0
- data/example/config.ru +7 -0
- data/example/fast.log +49 -0
- data/example/jmeter.log +28 -0
- data/example/lib/tasks/test.rake +40 -0
- data/example/log/.keep +0 -0
- data/example/public/robots.txt +1 -0
- data/example/random.log +49 -0
- data/example/slow.log +49 -0
- data/example/vendor/.keep +0 -0
- data/lib/Rakefile +4 -0
- data/lib/jmeter_perf/dsl/access_log_sampler.rb +38 -0
- data/lib/jmeter_perf/dsl/aggregate_graph.rb +61 -0
- data/lib/jmeter_perf/dsl/aggregate_report.rb +61 -0
- data/lib/jmeter_perf/dsl/ajp13_sampler.rb +47 -0
- data/lib/jmeter_perf/dsl/assertion_results.rb +61 -0
- data/lib/jmeter_perf/dsl/bean_shell_assertion.rb +34 -0
- data/lib/jmeter_perf/dsl/bean_shell_listener.rb +34 -0
- data/lib/jmeter_perf/dsl/bean_shell_postprocessor.rb +34 -0
- data/lib/jmeter_perf/dsl/bean_shell_preprocessor.rb +34 -0
- data/lib/jmeter_perf/dsl/bean_shell_sampler.rb +34 -0
- data/lib/jmeter_perf/dsl/bean_shell_timer.rb +34 -0
- data/lib/jmeter_perf/dsl/bsf_assertion.rb +34 -0
- data/lib/jmeter_perf/dsl/bsf_listener.rb +34 -0
- data/lib/jmeter_perf/dsl/bsf_postprocessor.rb +34 -0
- data/lib/jmeter_perf/dsl/bsf_preprocessor.rb +34 -0
- data/lib/jmeter_perf/dsl/bsf_sampler.rb +34 -0
- data/lib/jmeter_perf/dsl/bsf_timer.rb +34 -0
- data/lib/jmeter_perf/dsl/compare_assertion.rb +33 -0
- data/lib/jmeter_perf/dsl/comparison_assertion_visualizer.rb +61 -0
- data/lib/jmeter_perf/dsl/constant_throughput_timer.rb +32 -0
- data/lib/jmeter_perf/dsl/constant_timer.rb +31 -0
- data/lib/jmeter_perf/dsl/counter.rb +37 -0
- data/lib/jmeter_perf/dsl/css_jquery_extractor.rb +37 -0
- data/lib/jmeter_perf/dsl/csv_data_set_config.rb +39 -0
- data/lib/jmeter_perf/dsl/debug_postprocessor.rb +34 -0
- data/lib/jmeter_perf/dsl/debug_sampler.rb +33 -0
- data/lib/jmeter_perf/dsl/distribution_graphalpha.rb +61 -0
- data/lib/jmeter_perf/dsl/duration_assertion.rb +31 -0
- data/lib/jmeter_perf/dsl/for_each_controller.rb +33 -0
- data/lib/jmeter_perf/dsl/ftp_request.rb +40 -0
- data/lib/jmeter_perf/dsl/ftp_request_defaults.rb +38 -0
- data/lib/jmeter_perf/dsl/gaussian_random_timer.rb +32 -0
- data/lib/jmeter_perf/dsl/generate_summary_results.rb +29 -0
- data/lib/jmeter_perf/dsl/graph_results.rb +61 -0
- data/lib/jmeter_perf/dsl/html_assertion.rb +36 -0
- data/lib/jmeter_perf/dsl/html_link_parser.rb +29 -0
- data/lib/jmeter_perf/dsl/html_parameter_mask.rb +38 -0
- data/lib/jmeter_perf/dsl/http_authorization_manager.rb +39 -0
- data/lib/jmeter_perf/dsl/http_cache_manager.rb +32 -0
- data/lib/jmeter_perf/dsl/http_cookie_manager.rb +34 -0
- data/lib/jmeter_perf/dsl/http_header_manager.rb +36 -0
- data/lib/jmeter_perf/dsl/http_request.rb +47 -0
- data/lib/jmeter_perf/dsl/http_request_defaults.rb +53 -0
- data/lib/jmeter_perf/dsl/http_url_rewriting_modifier.rb +36 -0
- data/lib/jmeter_perf/dsl/if_controller.rb +33 -0
- data/lib/jmeter_perf/dsl/include_controller.rb +31 -0
- data/lib/jmeter_perf/dsl/j_unit_request.rb +43 -0
- data/lib/jmeter_perf/dsl/java_request.rb +75 -0
- data/lib/jmeter_perf/dsl/java_request_defaults.rb +75 -0
- data/lib/jmeter_perf/dsl/jdbc_connection_configuration.rb +43 -0
- data/lib/jmeter_perf/dsl/jdbc_postprocessor.rb +39 -0
- data/lib/jmeter_perf/dsl/jdbc_preprocessor.rb +39 -0
- data/lib/jmeter_perf/dsl/jdbc_request.rb +39 -0
- data/lib/jmeter_perf/dsl/jms_pointto_point.rb +47 -0
- data/lib/jmeter_perf/dsl/jms_publisher.rb +49 -0
- data/lib/jmeter_perf/dsl/jms_subscriber.rb +41 -0
- data/lib/jmeter_perf/dsl/json_path_postprocessor.rb +33 -0
- data/lib/jmeter_perf/dsl/jsr223_assertion.rb +35 -0
- data/lib/jmeter_perf/dsl/jsr223_listener.rb +35 -0
- data/lib/jmeter_perf/dsl/jsr223_postprocessor.rb +35 -0
- data/lib/jmeter_perf/dsl/jsr223_preprocessor.rb +35 -0
- data/lib/jmeter_perf/dsl/jsr223_sampler.rb +35 -0
- data/lib/jmeter_perf/dsl/jsr223_timer.rb +35 -0
- data/lib/jmeter_perf/dsl/keystore_configuration.rb +34 -0
- data/lib/jmeter_perf/dsl/ldap_extended_request.rb +48 -0
- data/lib/jmeter_perf/dsl/ldap_extended_request_defaults.rb +48 -0
- data/lib/jmeter_perf/dsl/ldap_request.rb +41 -0
- data/lib/jmeter_perf/dsl/ldap_request_defaults.rb +45 -0
- data/lib/jmeter_perf/dsl/login_config_element.rb +32 -0
- data/lib/jmeter_perf/dsl/loop_controller.rb +32 -0
- data/lib/jmeter_perf/dsl/mail_reader_sampler.rb +43 -0
- data/lib/jmeter_perf/dsl/mailer_visualizer.rb +70 -0
- data/lib/jmeter_perf/dsl/md5_hex_assertion.rb +31 -0
- data/lib/jmeter_perf/dsl/module_controller.rb +31 -0
- data/lib/jmeter_perf/dsl/monitor_results.rb +61 -0
- data/lib/jmeter_perf/dsl/once_only_controller.rb +29 -0
- data/lib/jmeter_perf/dsl/os_process_sampler.rb +40 -0
- data/lib/jmeter_perf/dsl/poisson_random_timer.rb +32 -0
- data/lib/jmeter_perf/dsl/random_controller.rb +31 -0
- data/lib/jmeter_perf/dsl/random_order_controller.rb +29 -0
- data/lib/jmeter_perf/dsl/random_variable.rb +36 -0
- data/lib/jmeter_perf/dsl/recording_controller.rb +29 -0
- data/lib/jmeter_perf/dsl/reg_ex_user_parameters.rb +33 -0
- data/lib/jmeter_perf/dsl/regular_expression_extractor.rb +38 -0
- data/lib/jmeter_perf/dsl/response_assertion.rb +37 -0
- data/lib/jmeter_perf/dsl/response_time_graph.rb +61 -0
- data/lib/jmeter_perf/dsl/result_status_action_handler.rb +31 -0
- data/lib/jmeter_perf/dsl/runtime_controller.rb +31 -0
- data/lib/jmeter_perf/dsl/save_responses_to_a_file.rb +35 -0
- data/lib/jmeter_perf/dsl/simple_config_element.rb +29 -0
- data/lib/jmeter_perf/dsl/simple_controller.rb +29 -0
- data/lib/jmeter_perf/dsl/simple_data_writer.rb +61 -0
- data/lib/jmeter_perf/dsl/smime_assertion.rb +41 -0
- data/lib/jmeter_perf/dsl/smtp_sampler.rb +57 -0
- data/lib/jmeter_perf/dsl/soap_xml_rpc_request.rb +39 -0
- data/lib/jmeter_perf/dsl/spline_visualizer.rb +61 -0
- data/lib/jmeter_perf/dsl/summary_report.rb +61 -0
- data/lib/jmeter_perf/dsl/switch_controller.rb +31 -0
- data/lib/jmeter_perf/dsl/synchronizing_timer.rb +32 -0
- data/lib/jmeter_perf/dsl/tcp_sampler.rb +39 -0
- data/lib/jmeter_perf/dsl/tcp_sampler_config.rb +37 -0
- data/lib/jmeter_perf/dsl/test_action.rb +33 -0
- data/lib/jmeter_perf/dsl/test_fragment.rb +29 -0
- data/lib/jmeter_perf/dsl/test_plan.rb +37 -0
- data/lib/jmeter_perf/dsl/thread_group.rb +43 -0
- data/lib/jmeter_perf/dsl/throughput_controller.rb +38 -0
- data/lib/jmeter_perf/dsl/transaction_controller.rb +32 -0
- data/lib/jmeter_perf/dsl/uniform_random_timer.rb +32 -0
- data/lib/jmeter_perf/dsl/user_defined_variables.rb +39 -0
- data/lib/jmeter_perf/dsl/user_parameters.rb +36 -0
- data/lib/jmeter_perf/dsl/view_results_in_table.rb +61 -0
- data/lib/jmeter_perf/dsl/view_results_tree.rb +61 -0
- data/lib/jmeter_perf/dsl/while_controller.rb +31 -0
- data/lib/jmeter_perf/dsl/x_path_assertion.rb +37 -0
- data/lib/jmeter_perf/dsl/x_path_extractor.rb +37 -0
- data/lib/jmeter_perf/dsl/xml_assertion.rb +29 -0
- data/lib/jmeter_perf/dsl/xml_schema_assertion.rb +31 -0
- data/lib/jmeter_perf/extend/assertions/response_assertion.rb +38 -0
- data/lib/jmeter_perf/extend/config_elements/header_manager.rb +13 -0
- data/lib/jmeter_perf/extend/config_elements/http_cache_manager.rb +12 -0
- data/lib/jmeter_perf/extend/config_elements/http_cookie_manager.rb +39 -0
- data/lib/jmeter_perf/extend/config_elements/http_request_defaults.rb +55 -0
- data/lib/jmeter_perf/extend/config_elements/user_defined_variables.rb +13 -0
- data/lib/jmeter_perf/extend/config_elements/user_parameters.rb +31 -0
- data/lib/jmeter_perf/extend/controllers/foreach_controller.rb +31 -0
- data/lib/jmeter_perf/extend/controllers/loop_controller.rb +11 -0
- data/lib/jmeter_perf/extend/controllers/module_controller.rb +26 -0
- data/lib/jmeter_perf/extend/controllers/throughput_controller.rb +15 -0
- data/lib/jmeter_perf/extend/controllers/transaction_controller.rb +14 -0
- data/lib/jmeter_perf/extend/misc/exists.rb +13 -0
- data/lib/jmeter_perf/extend/misc/rsync.rb +24 -0
- data/lib/jmeter_perf/extend/misc/uuid.rb +12 -0
- data/lib/jmeter_perf/extend/misc/with_helpers.rb +27 -0
- data/lib/jmeter_perf/extend/plugins/jmeter_plugins.rb +124 -0
- data/lib/jmeter_perf/extend/processors/extract.rb +27 -0
- data/lib/jmeter_perf/extend/processors/regular_expression_extractor.rb +27 -0
- data/lib/jmeter_perf/extend/samplers/http_request.rb +66 -0
- data/lib/jmeter_perf/extend/samplers/jms_pointtopoint.rb +23 -0
- data/lib/jmeter_perf/extend/samplers/soapxmlrpc_request.rb +10 -0
- data/lib/jmeter_perf/extend/threads/thread_group.rb +19 -0
- data/lib/jmeter_perf/extend/timers/constant_throughput_timer.rb +11 -0
- data/lib/jmeter_perf/extend/timers/random_timer.rb +14 -0
- data/lib/jmeter_perf/helpers/dsl_generator.rb +157 -0
- data/lib/jmeter_perf/helpers/fallback_content_proxy.rb +96 -0
- data/lib/jmeter_perf/helpers/helper.rb +63 -0
- data/lib/jmeter_perf/helpers/parser.rb +143 -0
- data/lib/jmeter_perf/helpers/running_statistics.rb +62 -0
- data/lib/jmeter_perf/helpers/string.rb +60 -0
- data/lib/jmeter_perf/helpers/user-agents.rb +42 -0
- data/lib/jmeter_perf/plugins/active_threads_over_time.rb +59 -0
- data/lib/jmeter_perf/plugins/composite_graph.rb +77 -0
- data/lib/jmeter_perf/plugins/console_status_logger.rb +19 -0
- data/lib/jmeter_perf/plugins/dummy_sampler.rb +30 -0
- data/lib/jmeter_perf/plugins/jmx_collector.rb +74 -0
- data/lib/jmeter_perf/plugins/json_path_assertion.rb +23 -0
- data/lib/jmeter_perf/plugins/json_path_extractor.rb +22 -0
- data/lib/jmeter_perf/plugins/latencies_over_time.rb +53 -0
- data/lib/jmeter_perf/plugins/loadosophia_uploader.rb +66 -0
- data/lib/jmeter_perf/plugins/perfmon_collector.rb +87 -0
- data/lib/jmeter_perf/plugins/redis_data_set.rb +43 -0
- data/lib/jmeter_perf/plugins/response_codes_per_second.rb +53 -0
- data/lib/jmeter_perf/plugins/response_times_distribution.rb +53 -0
- data/lib/jmeter_perf/plugins/response_times_over_time.rb +53 -0
- data/lib/jmeter_perf/plugins/response_times_percentiles.rb +54 -0
- data/lib/jmeter_perf/plugins/stepping_thread_group.rb +34 -0
- data/lib/jmeter_perf/plugins/transactions_per_second.rb +53 -0
- data/lib/jmeter_perf/plugins/ultimate_thread_group.rb +28 -0
- data/lib/jmeter_perf/plugins/variable_throughput_timer.rb +35 -0
- data/lib/jmeter_perf/report/comparator.rb +258 -0
- data/lib/jmeter_perf/report/summary.rb +268 -0
- data/lib/jmeter_perf/tasks/dsl.rake +19 -0
- data/lib/jmeter_perf/version.rb +5 -0
- data/lib/jmeter_perf/views/report_template.html.erb +114 -0
- data/lib/jmeter_perf.rb +183 -0
- data/lib/specifications/idl.xml +1494 -0
- data/sig/jmeter_perf.rbs +195 -0
- data/sorbet/config +5 -0
- data/sorbet/rbi/annotations/.gitattributes +1 -0
- data/sorbet/rbi/annotations/rainbow.rbi +269 -0
- data/sorbet/rbi/gems/.gitattributes +1 -0
- data/sorbet/rbi/gems/ast@2.4.2.rbi +585 -0
- data/sorbet/rbi/gems/bump@0.10.0.rbi +169 -0
- data/sorbet/rbi/gems/byebug@11.1.3.rbi +3607 -0
- data/sorbet/rbi/gems/coderay@1.1.3.rbi +3427 -0
- data/sorbet/rbi/gems/diff-lcs@1.5.1.rbi +1131 -0
- data/sorbet/rbi/gems/docile@1.4.1.rbi +377 -0
- data/sorbet/rbi/gems/erubi@1.13.0.rbi +150 -0
- data/sorbet/rbi/gems/json@2.7.2.rbi +1562 -0
- data/sorbet/rbi/gems/language_server-protocol@3.17.0.3.rbi +14238 -0
- data/sorbet/rbi/gems/lint_roller@1.1.0.rbi +240 -0
- data/sorbet/rbi/gems/method_source@1.1.0.rbi +304 -0
- data/sorbet/rbi/gems/netrc@0.11.0.rbi +159 -0
- data/sorbet/rbi/gems/nokogiri@1.16.7.rbi +7311 -0
- data/sorbet/rbi/gems/parallel@1.26.3.rbi +291 -0
- data/sorbet/rbi/gems/parser@3.3.5.0.rbi +5519 -0
- data/sorbet/rbi/gems/prism@1.2.0.rbi +39085 -0
- data/sorbet/rbi/gems/pry-byebug@3.10.1.rbi +1151 -0
- data/sorbet/rbi/gems/pry@0.14.2.rbi +10076 -0
- data/sorbet/rbi/gems/racc@1.8.1.rbi +162 -0
- data/sorbet/rbi/gems/rainbow@3.1.1.rbi +403 -0
- data/sorbet/rbi/gems/rake@13.2.1.rbi +3074 -0
- data/sorbet/rbi/gems/rbi@0.2.1.rbi +4535 -0
- data/sorbet/rbi/gems/rbtree3@0.7.1.rbi +9 -0
- data/sorbet/rbi/gems/regexp_parser@2.9.2.rbi +3772 -0
- data/sorbet/rbi/gems/rexml@3.3.8.rbi +4858 -0
- data/sorbet/rbi/gems/rspec-core@3.13.1.rbi +11132 -0
- data/sorbet/rbi/gems/rspec-expectations@3.13.3.rbi +8183 -0
- data/sorbet/rbi/gems/rspec-mocks@3.13.1.rbi +5341 -0
- data/sorbet/rbi/gems/rspec-support@3.13.1.rbi +1630 -0
- data/sorbet/rbi/gems/rspec@3.13.0.rbi +83 -0
- data/sorbet/rbi/gems/rubocop-ast@1.32.3.rbi +7054 -0
- data/sorbet/rbi/gems/rubocop-performance@1.21.1.rbi +9 -0
- data/sorbet/rbi/gems/rubocop@1.65.1.rbi +58182 -0
- data/sorbet/rbi/gems/ruby-progressbar@1.13.0.rbi +1318 -0
- data/sorbet/rbi/gems/simplecov-html@0.13.1.rbi +225 -0
- data/sorbet/rbi/gems/simplecov@0.22.0.rbi +2149 -0
- data/sorbet/rbi/gems/simplecov_json_formatter@0.1.4.rbi +9 -0
- data/sorbet/rbi/gems/spoom@1.5.0.rbi +4932 -0
- data/sorbet/rbi/gems/standard-custom@1.0.2.rbi +9 -0
- data/sorbet/rbi/gems/standard-performance@1.4.0.rbi +9 -0
- data/sorbet/rbi/gems/standard@1.40.0.rbi +926 -0
- data/sorbet/rbi/gems/tapioca@0.16.3.rbi +3596 -0
- data/sorbet/rbi/gems/tdigest@0.2.1.rbi +170 -0
- data/sorbet/rbi/gems/thor@1.3.2.rbi +4378 -0
- data/sorbet/rbi/gems/unicode-display_width@2.6.0.rbi +66 -0
- data/sorbet/rbi/gems/yard-sorbet@0.9.0.rbi +435 -0
- data/sorbet/rbi/gems/yard@0.9.37.rbi +18379 -0
- data/sorbet/rbi/todo.rbi +31 -0
- data/sorbet/tapioca/config.yml +13 -0
- data/sorbet/tapioca/require.rb +15 -0
- data/tasks/dsl.rake +22 -0
- metadata +355 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
require "nokogiri"
|
|
2
|
+
require "pathname"
|
|
3
|
+
|
|
4
|
+
require_relative "string"
|
|
5
|
+
|
|
6
|
+
module JmeterPerf
|
|
7
|
+
module Helpers
|
|
8
|
+
# The DSLGenerator class generates the DSL methods and files
|
|
9
|
+
# for use in JMeter performance testing scripts. It uses a JMeter TestPlan (idl.xml)
|
|
10
|
+
# to generate the methods and files.
|
|
11
|
+
# @see https://github.com/jlurena/jmeter_perf/wiki/3.-Generating-DSL-Methods
|
|
12
|
+
class DSLGenerator
|
|
13
|
+
# Initializes the DSLGenerator.
|
|
14
|
+
# @param dsl_dir [String] Path to the directory where DSL files will be generated.
|
|
15
|
+
# @param idl_xml_path [String] Path to the XML file used for generating methods.
|
|
16
|
+
def initialize(dsl_dir:, idl_xml_path:, document_dsl: true)
|
|
17
|
+
@document_dsl = document_dsl
|
|
18
|
+
@dsl_dir = dsl_dir
|
|
19
|
+
@idl_xml_path = idl_xml_path
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Main method to generate DSL files and methods.
|
|
23
|
+
# It parses the XML, generates methods, documents,
|
|
24
|
+
# updates RBS files, and creates individual DSL files.
|
|
25
|
+
# @return [void]
|
|
26
|
+
def generate
|
|
27
|
+
results = parse_xml
|
|
28
|
+
methods = generate_methods(results)
|
|
29
|
+
|
|
30
|
+
write_methods_to_dsl_md(methods) if @document_dsl
|
|
31
|
+
update_rbs(methods) if @document_dsl
|
|
32
|
+
create_dsl_files(results)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
# Parses the XML file specified by the `idl_xml_path` parameter.
|
|
38
|
+
# @return [Array<Nokogiri::XML::Node>] Array of XML nodes representing valid elements.
|
|
39
|
+
def parse_xml
|
|
40
|
+
idl_xml = File.open(@idl_xml_path)
|
|
41
|
+
doc = Nokogiri::XML(idl_xml.read.gsub(/\n\s+/, ""))
|
|
42
|
+
results = []
|
|
43
|
+
|
|
44
|
+
doc.traverse do |node|
|
|
45
|
+
if valid_node?(node)
|
|
46
|
+
results << node
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
results
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Checks if a given Nokogiri XML node is valid based on specific criteria.
|
|
54
|
+
#
|
|
55
|
+
# A node is considered valid if:
|
|
56
|
+
# - It is not an instance of Nokogiri::XML::Document.
|
|
57
|
+
# - It has an attribute named "testclass".
|
|
58
|
+
# - Its name is not "elementProp".
|
|
59
|
+
#
|
|
60
|
+
# @param node [Nokogiri::XML::Node] The XML node to be validated.
|
|
61
|
+
# @return [Boolean] Returns true if the node is valid, false otherwise.
|
|
62
|
+
def valid_node?(node)
|
|
63
|
+
node.class != Nokogiri::XML::Document &&
|
|
64
|
+
node.attributes["testclass"] &&
|
|
65
|
+
node.name != "elementProp"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Generates methods based on parsed XML results.
|
|
69
|
+
# @param results [Array<Nokogiri::XML::Node>] Parsed XML nodes.
|
|
70
|
+
# @return [Array<Array<String>>] Array of class and method name pairs.
|
|
71
|
+
def generate_methods(results)
|
|
72
|
+
results.map do |element|
|
|
73
|
+
klass = JmeterPerf::Helpers::String.classify(element.attributes["testname"].to_s)
|
|
74
|
+
method = JmeterPerf::Helpers::String.underscore(klass)
|
|
75
|
+
[klass, method]
|
|
76
|
+
end.sort_by(&:first)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Creates individual DSL files based on parsed XML results.
|
|
80
|
+
# @param results [Array<Nokogiri::XML::Node>] Parsed XML nodes.
|
|
81
|
+
# @return [void]
|
|
82
|
+
def create_dsl_files(results)
|
|
83
|
+
FileUtils.rm_rf(@dsl_dir)
|
|
84
|
+
FileUtils.mkdir_p(@dsl_dir)
|
|
85
|
+
|
|
86
|
+
results.each do |element|
|
|
87
|
+
klass = JmeterPerf::Helpers::String.classify(element.attributes["testname"].to_s)
|
|
88
|
+
puts "\tfor Element #{klass}"
|
|
89
|
+
File.write("#{@dsl_dir}/#{JmeterPerf::Helpers::String.underscore(klass)}.rb", <<~EOC)
|
|
90
|
+
module JmeterPerf
|
|
91
|
+
class DSL
|
|
92
|
+
# DSL method synonymous with the JMeter Element #{klass}
|
|
93
|
+
# @param params [Hash] Parameters for the #{klass} element (default: `{}`).
|
|
94
|
+
# @yield block to attach to the #{klass} element
|
|
95
|
+
# @return [JmeterPerf::#{klass}], a subclass of JmeterPerf::DSL that can be chained with other DSL methods.
|
|
96
|
+
# @see https://github.com/jlurena/jmeter_perf/wiki/1.-DSL-Documentation##{klass.downcase}
|
|
97
|
+
def #{JmeterPerf::Helpers::String.underscore(klass)}(params = {}, &)
|
|
98
|
+
node = #{klass}.new(params)
|
|
99
|
+
attach_node(node, &)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
class #{klass}
|
|
103
|
+
attr_accessor :doc
|
|
104
|
+
include JmeterPerf::Helpers::XmlDocumentUpdater
|
|
105
|
+
|
|
106
|
+
def initialize(params = {})
|
|
107
|
+
testname = params.is_a?(Array) ? "#{klass}" : (params[:name] || "#{klass}")
|
|
108
|
+
@doc = Nokogiri::XML(JmeterPerf::Helpers::String.strip_heredoc(
|
|
109
|
+
<<~EOS
|
|
110
|
+
#{element.to_xml.gsub(/testname=".+?"/, 'testname="#{testname}"').gsub(/^/, " ")}
|
|
111
|
+
EOS
|
|
112
|
+
))
|
|
113
|
+
update params
|
|
114
|
+
update_at_xpath params if params.is_a?(Hash) && params[:update_at_xpath]
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
EOC
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Updates the RBS file with method signatures for the DSL methods.
|
|
124
|
+
# @param methods [Array<Array<String>>] Array of class and method name pairs.
|
|
125
|
+
# @return [void]
|
|
126
|
+
def update_rbs(methods)
|
|
127
|
+
file_path = "sig/jmeter_perf.rbs"
|
|
128
|
+
replace_regex = /\s*## AUTOGENERATED - DSL methods RBS(.*?)## AUTOGENERATED - DSL methods RBS/m
|
|
129
|
+
new_content = <<~NEW_CONTENT
|
|
130
|
+
#{methods.map { |klass, method| " def #{method}: (Hash[Symbol, untyped], &block) -> void" }.join("\n")}
|
|
131
|
+
NEW_CONTENT
|
|
132
|
+
|
|
133
|
+
current_content = File.read(file_path)
|
|
134
|
+
|
|
135
|
+
new_file_content = current_content.gsub(replace_regex) do
|
|
136
|
+
"\n ## AUTOGENERATED - DSL methods RBS\n\n#{new_content}\n ## AUTOGENERATED - DSL methods RBS"
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
File.write(file_path, new_file_content)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Writes the list of generated methods to a markdown file.
|
|
143
|
+
# @param methods [Array<Array<String>>] Array of class and method name pairs.
|
|
144
|
+
# @return [void]
|
|
145
|
+
def write_methods_to_dsl_md(methods)
|
|
146
|
+
output = []
|
|
147
|
+
output << "# JmeterPerf::DSL methods"
|
|
148
|
+
|
|
149
|
+
methods.each do |klass, method|
|
|
150
|
+
output << "- #{klass}\n `#{method}`"
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
File.write("DSL.md", output.join("\n"))
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
#
|
|
2
|
+
# This module provides a proxy class that delegates method calls to a primary receiver object,
|
|
3
|
+
# and falls back to a secondary object if the primary does not respond to the method.
|
|
4
|
+
#
|
|
5
|
+
# @example
|
|
6
|
+
# primary = PrimaryClass.new
|
|
7
|
+
# fallback = FallbackClass.new
|
|
8
|
+
# proxy = JmeterPerf::Helpers::FallbackContextProxy.new(primary, fallback)
|
|
9
|
+
# proxy.some_method # Will call `some_method` on primary, or fallback if primary does not respond
|
|
10
|
+
#
|
|
11
|
+
module JmeterPerf::Helpers
|
|
12
|
+
class FallbackContextProxy
|
|
13
|
+
# List of methods that should not be proxied.
|
|
14
|
+
NON_PROXIED_METHODS = [
|
|
15
|
+
:__id__,
|
|
16
|
+
:__send__,
|
|
17
|
+
:!,
|
|
18
|
+
:"!=",
|
|
19
|
+
:==,
|
|
20
|
+
:equal?,
|
|
21
|
+
:instance_eval,
|
|
22
|
+
:instance_variable_get,
|
|
23
|
+
:instance_variable_set,
|
|
24
|
+
:instance_variables,
|
|
25
|
+
:object_id,
|
|
26
|
+
:remove_instance_variable
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
# List of instance variables that should not be proxied.
|
|
30
|
+
NON_PROXIED_INSTANCE_VARIABLES = [
|
|
31
|
+
:@__fallback__,
|
|
32
|
+
:@__receiver__
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
# Initializes a new FallbackContextProxy.
|
|
36
|
+
#
|
|
37
|
+
# @param receiver [Object] the primary object to which method calls are delegated.
|
|
38
|
+
# @param fallback [Object] the secondary object to which method calls are delegated if the primary does not respond.
|
|
39
|
+
def initialize(receiver, fallback)
|
|
40
|
+
@__receiver__ = receiver
|
|
41
|
+
@__fallback__ = fallback
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Returns the ID of the primary receiver.
|
|
45
|
+
#
|
|
46
|
+
# @return [Object] the ID of the primary receiver.
|
|
47
|
+
def id
|
|
48
|
+
@__receiver__.__send__(:id)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Proxies the `sub` method call to the primary receiver or fallback.
|
|
52
|
+
#
|
|
53
|
+
# @param args [Array] the arguments to pass to the `sub` method.
|
|
54
|
+
# @return [Object] the result of the `sub` method call.
|
|
55
|
+
def sub(...)
|
|
56
|
+
__proxy_method__(:sub, ...)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Returns the instance variables of the proxy, excluding non-proxied instance variables.
|
|
60
|
+
#
|
|
61
|
+
# @return [Array<Symbol>] the instance variables of the proxy.
|
|
62
|
+
def instance_variables
|
|
63
|
+
super.map(&:to_sym) - NON_PROXIED_INSTANCE_VARIABLES
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Checks if the proxy responds to a given method.
|
|
67
|
+
#
|
|
68
|
+
# @param name [Symbol] the name of the method.
|
|
69
|
+
# @param include_private [Boolean] whether to include private methods.
|
|
70
|
+
# @return [Boolean] true if the proxy responds to the method, false otherwise.
|
|
71
|
+
def respond_to_missing?(name, include_private)
|
|
72
|
+
__proxy_method__(:respond_to?, name, include_private)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Handles method calls that are not explicitly defined in the proxy.
|
|
76
|
+
#
|
|
77
|
+
# @param method [Symbol] the name of the method.
|
|
78
|
+
# @param args [Array] the arguments to pass to the method.
|
|
79
|
+
# @return [Object] the result of the method call.
|
|
80
|
+
def method_missing(method, ...)
|
|
81
|
+
__proxy_method__(method, ...)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Proxies a method call to the primary receiver or fallback.
|
|
85
|
+
#
|
|
86
|
+
# @param method [Symbol] the name of the method.
|
|
87
|
+
# @param args [Array] the arguments to pass to the method.
|
|
88
|
+
# @return [Object] the result of the method call.
|
|
89
|
+
# @raise [NoMethodError] if neither the primary receiver nor the fallback respond to the method.
|
|
90
|
+
def __proxy_method__(method, ...)
|
|
91
|
+
@__receiver__.__send__(method.to_sym, ...)
|
|
92
|
+
rescue NoMethodError
|
|
93
|
+
@__fallback__.__send__(method.to_sym, ...)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
module JmeterPerf::Helpers
|
|
2
|
+
module XmlDocumentUpdater
|
|
3
|
+
private
|
|
4
|
+
|
|
5
|
+
def update(params)
|
|
6
|
+
params.delete(:name)
|
|
7
|
+
enabled_disabled(params)
|
|
8
|
+
if params.instance_of?(Array)
|
|
9
|
+
update_collection params
|
|
10
|
+
else
|
|
11
|
+
params.each do |name, value|
|
|
12
|
+
node = @doc.children.xpath("//*[contains(@name,\"#{name}\")]")
|
|
13
|
+
if value.instance_of?(Nokogiri::XML::Builder)
|
|
14
|
+
node.first.children = value.doc.at_xpath("//builder").children
|
|
15
|
+
else
|
|
16
|
+
node.first.content = value unless node.empty?
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def enabled_disabled(params)
|
|
23
|
+
return unless params.is_a?(Hash)
|
|
24
|
+
return unless @doc.children.first.attributes["enabled"]
|
|
25
|
+
@doc.children.first.attributes["enabled"].value = params[:enabled].to_s.empty? ? "true" : "false"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def update_at_xpath(params)
|
|
29
|
+
params[:update_at_xpath].each do |fragment|
|
|
30
|
+
if fragment[:xpath]
|
|
31
|
+
@doc.at_xpath(fragment[:xpath]) << fragment[:value]
|
|
32
|
+
else
|
|
33
|
+
fragment.each do |xpath, value|
|
|
34
|
+
@doc.at_xpath(xpath).content = value
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def update_collection(params)
|
|
41
|
+
elements = @doc.at_xpath("//collectionProp/elementProp")
|
|
42
|
+
params.each_with_index do |param, index|
|
|
43
|
+
param.each do |name, value|
|
|
44
|
+
next unless elements&.element_children
|
|
45
|
+
element = elements.element_children.xpath("//*[contains(@name,\"#{name}\")]")
|
|
46
|
+
element.last.content = value
|
|
47
|
+
end
|
|
48
|
+
if index != params.size - 1 && elements
|
|
49
|
+
@doc.at_xpath("//collectionProp") << elements.dup
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def enabled(params)
|
|
55
|
+
# default to true unless explicitly set to false
|
|
56
|
+
if params.has_key?(:enabled) && params[:enabled] == false
|
|
57
|
+
"false"
|
|
58
|
+
else
|
|
59
|
+
"true"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
require "uri"
|
|
2
|
+
|
|
3
|
+
module JmeterPerf::Helpers
|
|
4
|
+
module Parser
|
|
5
|
+
private
|
|
6
|
+
|
|
7
|
+
def parse_http_request(params)
|
|
8
|
+
if params[:raw_path]
|
|
9
|
+
params[:path] = params[:url]
|
|
10
|
+
parse_url(params)
|
|
11
|
+
else
|
|
12
|
+
parse_url(params)
|
|
13
|
+
params[:fill_in] ||= {}
|
|
14
|
+
params[:params]&.split("&")&.each do |param|
|
|
15
|
+
name, value = param.split("=")
|
|
16
|
+
params[:fill_in][name] ||= []
|
|
17
|
+
params[:fill_in][name] << value
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
fill_in(params) if params.has_key?(:fill_in)
|
|
22
|
+
raw_body(params) if params.has_key?(:raw_body)
|
|
23
|
+
files(params) if params.has_key?(:files)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def parse_url(params)
|
|
27
|
+
return if params[:url].empty?
|
|
28
|
+
if params[:url] =~ /https?:\/\/\$/ || params[:url][0] == "$"
|
|
29
|
+
params[:path] = params[:url] # special case for named expressions
|
|
30
|
+
else
|
|
31
|
+
uri = parse_uri(params[:url])
|
|
32
|
+
params[:port] ||= uri.port unless URI.parse(URI::DEFAULT_PARSER.escape(params[:url])).scheme.nil?
|
|
33
|
+
params[:protocol] ||= uri.scheme unless URI.parse(URI::DEFAULT_PARSER.escape(params[:url])).scheme.nil?
|
|
34
|
+
params[:domain] ||= uri.host
|
|
35
|
+
params[:path] ||= uri.path && URI.decode_www_form_component(uri.path)
|
|
36
|
+
params[:params] ||= uri.query && URI.decode_www_form_component(uri.query)
|
|
37
|
+
end
|
|
38
|
+
params.delete(:url)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def parse_uri(uri)
|
|
42
|
+
URI.parse(URI::DEFAULT_PARSER.escape(uri)).scheme.nil? ?
|
|
43
|
+
URI.parse(URI::DEFAULT_PARSER.escape("http://#{uri}")) :
|
|
44
|
+
URI.parse(URI::DEFAULT_PARSER.escape(uri))
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def fill_in(params)
|
|
48
|
+
params[:update_at_xpath] ||= []
|
|
49
|
+
params[:update_at_xpath] = params[:fill_in]
|
|
50
|
+
.each_with_object(params[:update_at_xpath]) do |(name, values), memo|
|
|
51
|
+
Array(values).each do |value|
|
|
52
|
+
memo.push({
|
|
53
|
+
xpath: "//collectionProp",
|
|
54
|
+
value: Nokogiri::XML(JmeterPerf::Helpers::String.strip_heredoc(
|
|
55
|
+
<<-EOF
|
|
56
|
+
<elementProp name="#{name}" elementType="HTTPArgument">
|
|
57
|
+
<boolProp name="HTTPArgument.always_encode">#{params[:always_encode] ? "true" : false}</boolProp>
|
|
58
|
+
<stringProp name="Argument.value">#{value}</stringProp>
|
|
59
|
+
<stringProp name="Argument.metadata">=</stringProp>
|
|
60
|
+
<boolProp name="HTTPArgument.use_equals">true</boolProp>
|
|
61
|
+
<stringProp name="Argument.name">#{name}</stringProp>
|
|
62
|
+
</elementProp>
|
|
63
|
+
EOF
|
|
64
|
+
)).children
|
|
65
|
+
})
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
params.delete(:fill_in)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def raw_body(params)
|
|
72
|
+
params[:update_at_xpath] ||= []
|
|
73
|
+
params[:update_at_xpath].push({
|
|
74
|
+
xpath: "//HTTPSamplerProxy",
|
|
75
|
+
value: Nokogiri::XML(JmeterPerf::Helpers::String.strip_heredoc(
|
|
76
|
+
<<-EOF
|
|
77
|
+
<boolProp name="HTTPSampler.postBodyRaw">true</boolProp>
|
|
78
|
+
EOF
|
|
79
|
+
)).children
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
params[:update_at_xpath].push({
|
|
83
|
+
xpath: "//collectionProp",
|
|
84
|
+
value: Nokogiri::XML(JmeterPerf::Helpers::String.strip_heredoc(
|
|
85
|
+
<<-EOF
|
|
86
|
+
<elementProp name="" elementType="HTTPArgument">
|
|
87
|
+
<boolProp name="HTTPArgument.always_encode">false</boolProp>
|
|
88
|
+
<stringProp name="Argument.value">#{params[:raw_body].encode(xml: :text)}</stringProp>
|
|
89
|
+
<stringProp name="Argument.metadata">=</stringProp>
|
|
90
|
+
</elementProp>
|
|
91
|
+
EOF
|
|
92
|
+
)).children
|
|
93
|
+
})
|
|
94
|
+
params.delete(:raw_body)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def files(params)
|
|
98
|
+
files = params.delete(:files)
|
|
99
|
+
return if files.empty?
|
|
100
|
+
x = Nokogiri::XML::Builder.new do |b|
|
|
101
|
+
b.elementProp(name: "HTTPsampler.Files", elementType: "HTTPFileArgs") {
|
|
102
|
+
b.collectionProp(name: "HTTPFileArgs.files") {
|
|
103
|
+
files.each do |f|
|
|
104
|
+
b.elementProp(name: f[:path], elementType: "HTTPFileArg") {
|
|
105
|
+
b.stringProp f[:path] || "", name: "File.path"
|
|
106
|
+
b.stringProp f[:paramname] || "", name: "File.paramname"
|
|
107
|
+
b.stringProp f[:mimetype] || "", name: "File.mimetype"
|
|
108
|
+
}
|
|
109
|
+
end
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
end
|
|
113
|
+
params[:update_at_xpath] ||= []
|
|
114
|
+
params[:update_at_xpath] << {
|
|
115
|
+
xpath: "//HTTPSamplerProxy",
|
|
116
|
+
value: x.doc.root
|
|
117
|
+
}
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def parse_test_type(params)
|
|
121
|
+
case params.keys.first.to_s
|
|
122
|
+
when "contains"
|
|
123
|
+
2
|
|
124
|
+
when "not-contains"
|
|
125
|
+
6
|
|
126
|
+
when "matches"
|
|
127
|
+
1
|
|
128
|
+
when "not-matches"
|
|
129
|
+
5
|
|
130
|
+
when "equals"
|
|
131
|
+
8
|
|
132
|
+
when "not-equals"
|
|
133
|
+
12
|
|
134
|
+
when "substring"
|
|
135
|
+
16
|
|
136
|
+
when "not-substring"
|
|
137
|
+
20
|
|
138
|
+
else
|
|
139
|
+
2
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
require "tdigest"
|
|
2
|
+
|
|
3
|
+
module JmeterPerf::Helpers
|
|
4
|
+
# Provides running statistics for a series of numbers, including approximate percentiles and
|
|
5
|
+
# standard deviation.
|
|
6
|
+
#
|
|
7
|
+
# @note This class uses a TDigest data structure to keep statistics "close enough". Accuracy is not guaranteed.
|
|
8
|
+
class RunningStatistisc
|
|
9
|
+
# The marker for when to call the compression function on the TDigest structure.
|
|
10
|
+
COMPRESS_MARKER = 1000
|
|
11
|
+
|
|
12
|
+
# @return [Float] the running average of the numbers added
|
|
13
|
+
attr_reader :avg
|
|
14
|
+
|
|
15
|
+
# Initializes a new instance of RunningStatistisc to calculate running statistics.
|
|
16
|
+
#
|
|
17
|
+
# @return [RunningStatistisc]
|
|
18
|
+
def initialize
|
|
19
|
+
@tdigest = ::TDigest::TDigest.new
|
|
20
|
+
@count = 0
|
|
21
|
+
@avg = 0
|
|
22
|
+
@m2 = 0 # Sum of squares of differences from the avg
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Adds a number to the running statistics and updates the average and variance calculations.
|
|
26
|
+
#
|
|
27
|
+
# @param num [Float] the number to add to the running statistics
|
|
28
|
+
# @return [void]
|
|
29
|
+
def add_number(num)
|
|
30
|
+
@tdigest.push(num)
|
|
31
|
+
|
|
32
|
+
@count += 1
|
|
33
|
+
delta = num - @avg
|
|
34
|
+
@avg += delta / @count
|
|
35
|
+
delta2 = num - @avg
|
|
36
|
+
@m2 += delta * delta2
|
|
37
|
+
|
|
38
|
+
# Compress data every 1000 items to maintain memory efficiency
|
|
39
|
+
@tdigest.compress! if @count % COMPRESS_MARKER == 0
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Retrieves approximate percentiles for the data set based on the requested percentile values.
|
|
43
|
+
#
|
|
44
|
+
# @param percentiles [Array<Float>] the requested percentiles (e.g., 0.5 for the 50th percentile)
|
|
45
|
+
# @return [Array<Float>] an array of calculated percentiles corresponding to the requested values
|
|
46
|
+
# @example Requesting the 10th, 50th, and 95th percentiles
|
|
47
|
+
# get_percentiles(0.1, 0.5, 0.95) #=> [some_value_for_10th, some_value_for_50th, some_value_for_95th]
|
|
48
|
+
def get_percentiles(*percentiles)
|
|
49
|
+
@tdigest.compress!
|
|
50
|
+
percentiles.map { |percentile| @tdigest.percentile(percentile) }
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Calculates the standard deviation of the numbers added so far.
|
|
54
|
+
#
|
|
55
|
+
# @return [Float] the standard deviation, or 0 if fewer than two values have been added
|
|
56
|
+
def standard_deviation
|
|
57
|
+
return 0 if @count < 2
|
|
58
|
+
Math.sqrt(@m2 / (@count - 1))
|
|
59
|
+
end
|
|
60
|
+
alias_method :std, :standard_deviation
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
module JmeterPerf::Helpers
|
|
2
|
+
class String
|
|
3
|
+
class << self
|
|
4
|
+
# Converts a string to CamelCase.
|
|
5
|
+
#
|
|
6
|
+
# @param string [String] the string to be converted.
|
|
7
|
+
# @return [String] the CamelCase version of the string.
|
|
8
|
+
def classify(string)
|
|
9
|
+
camelize(string.gsub(/\s/, "_"))
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Converts a string to snake_case.
|
|
13
|
+
#
|
|
14
|
+
# @param string [String] the string to be converted.
|
|
15
|
+
# @return [String] the snake_case version of the string.
|
|
16
|
+
def underscore(string)
|
|
17
|
+
string.gsub("::", "/")
|
|
18
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
|
19
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
|
20
|
+
.tr("-", "_")
|
|
21
|
+
.downcase
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Converts a string to CamelCase or camelCase.
|
|
25
|
+
#
|
|
26
|
+
# @param str [String] the string to be converted.
|
|
27
|
+
# @param uppercase_first_letter [Boolean, Symbol] whether to capitalize the first letter or not.
|
|
28
|
+
# If `:lower`, the first letter will be lowercase.
|
|
29
|
+
# @return [String] the CamelCase or camelCase version of the string.
|
|
30
|
+
def camelize(str, uppercase_first_letter = true)
|
|
31
|
+
string = str.dup
|
|
32
|
+
# String#camelize takes a symbol (:upper or :lower), so here we also support :lower to keep the methods consistent.
|
|
33
|
+
if !uppercase_first_letter || uppercase_first_letter == :lower
|
|
34
|
+
string = string.sub(/^(?:(?=a)b(?=\b|[A-Z_])|\w)/) { |match| match.downcase! || match }
|
|
35
|
+
elsif string.match?(/\A[a-z\d]*\z/)
|
|
36
|
+
return string.capitalize
|
|
37
|
+
else
|
|
38
|
+
string = string.sub(/^[a-z\d]*/) { |match| match.capitalize || match }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
string.gsub!(/(?:_|(\/))([a-z\d]*)/i) do
|
|
42
|
+
word = $2
|
|
43
|
+
substituted = word.capitalize! || word
|
|
44
|
+
($1) ? "_#{substituted}" : substituted
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
string.gsub!(/[^a-zA-Z0-9]/, "")
|
|
48
|
+
string
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Strips leading whitespace from each line that is the same as the amount of whitespace on the first line.
|
|
52
|
+
#
|
|
53
|
+
# @param string [String] the string to be stripped of leading whitespace.
|
|
54
|
+
# @return [String] the string with leading whitespace removed.
|
|
55
|
+
def strip_heredoc(string)
|
|
56
|
+
string.gsub(/^#{string[/\A\s*/]}/, "")
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# This module provides a collection of common user-agent strings for various devices and browsers.
|
|
2
|
+
# It allows retrieval of user-agent strings based on device type.
|
|
3
|
+
module JmeterPerf::Helpers
|
|
4
|
+
module UserAgent
|
|
5
|
+
# A hash containing user-agent strings for common devices and browsers.
|
|
6
|
+
# @return [Hash<Symbol, String>] the user-agent strings for various devices and browsers.
|
|
7
|
+
COMMON_DEVICES = {
|
|
8
|
+
# User-agent string for iPhone
|
|
9
|
+
iphone: "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1",
|
|
10
|
+
# User-agent string for iPod
|
|
11
|
+
ipod: "Mozilla/5.0 (iPod touch; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1",
|
|
12
|
+
# User-agent string for iPad
|
|
13
|
+
ipad: "Mozilla/5.0 (iPad; CPU OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1",
|
|
14
|
+
# User-agent string for Safari on macOS
|
|
15
|
+
safari_osx: "Mozilla/5.0 (Macintosh; Intel Mac OS X 13_0) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Safari/605.1.15",
|
|
16
|
+
# User-agent string for Safari on Windows
|
|
17
|
+
safari_win: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Edg/115.0.1901.188",
|
|
18
|
+
# User-agent string for Edge
|
|
19
|
+
edge: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Edg/115.0.1901.188",
|
|
20
|
+
# User-agent string for Chrome on macOS
|
|
21
|
+
chrome_osx: "Mozilla/5.0 (Macintosh; Intel Mac OS X 13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36",
|
|
22
|
+
# User-agent string for Chrome on Windows
|
|
23
|
+
chrome_win: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36",
|
|
24
|
+
# User-agent string for Firefox on macOS
|
|
25
|
+
ff_osx: "Mozilla/5.0 (Macintosh; Intel Mac OS X 13.0; rv:115.0) Gecko/20100101 Firefox/115.0",
|
|
26
|
+
# User-agent string for Firefox on Windows
|
|
27
|
+
ff_win: "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:115.0) Gecko/20100101 Firefox/115.0",
|
|
28
|
+
# User-agent string for Opera on macOS
|
|
29
|
+
opera_osx: "Mozilla/5.0 (Macintosh; Intel Mac OS X 13.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 OPR/102.0.0.0",
|
|
30
|
+
# User-agent string for Opera on Windows
|
|
31
|
+
opera_win: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 OPR/102.0.0.0"
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
# Retrieves the user-agent string for the specified device.
|
|
35
|
+
#
|
|
36
|
+
# @param device [Symbol] the device type for which to retrieve the user-agent string.
|
|
37
|
+
# @return [String] the user-agent string for the specified device, or the default Chrome on macOS user-agent string if the device is not found.
|
|
38
|
+
def self.string(device)
|
|
39
|
+
COMMON_DEVICES[device] || COMMON_DEVICES[:chrome_osx]
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
module JmeterPerf
|
|
2
|
+
module Plugins
|
|
3
|
+
class ActiveThreadsOverTime
|
|
4
|
+
attr_accessor :doc
|
|
5
|
+
include JmeterPerf::Helpers::XmlDocumentUpdater
|
|
6
|
+
def initialize(params = {})
|
|
7
|
+
testname = params.is_a?(Array) ? "ActiveThreadsOverTime" : (params[:name] || "ActiveThreadsOverTime")
|
|
8
|
+
@doc = Nokogiri::XML(
|
|
9
|
+
JmeterPerf::Helpers::String.strip_heredoc(
|
|
10
|
+
<<-XML
|
|
11
|
+
<kg.apc.jmeter.vizualizers.CorrectedResultCollector guiclass="kg.apc.jmeter.vizualizers.ThreadsStateOverTimeGui" testclass="kg.apc.jmeter.vizualizers.CorrectedResultCollector" testname="#{testname}" enabled="true">
|
|
12
|
+
<boolProp name="ResultCollector.error_logging">false</boolProp>
|
|
13
|
+
<objProp>
|
|
14
|
+
<name>saveConfig</name>
|
|
15
|
+
<value class="SampleSaveConfiguration">
|
|
16
|
+
<time>true</time>
|
|
17
|
+
<latency>true</latency>
|
|
18
|
+
<timestamp>true</timestamp>
|
|
19
|
+
<success>true</success>
|
|
20
|
+
<label>true</label>
|
|
21
|
+
<code>true</code>
|
|
22
|
+
<message>false</message>
|
|
23
|
+
<threadName>true</threadName>
|
|
24
|
+
<dataType>false</dataType>
|
|
25
|
+
<encoding>false</encoding>
|
|
26
|
+
<assertions>false</assertions>
|
|
27
|
+
<subresults>false</subresults>
|
|
28
|
+
<responseData>false</responseData>
|
|
29
|
+
<samplerData>false</samplerData>
|
|
30
|
+
<xml>false</xml>
|
|
31
|
+
<fieldNames>false</fieldNames>
|
|
32
|
+
<responseHeaders>false</responseHeaders>
|
|
33
|
+
<requestHeaders>false</requestHeaders>
|
|
34
|
+
<responseDataOnError>false</responseDataOnError>
|
|
35
|
+
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
|
|
36
|
+
<assertionsResultsToSave>0</assertionsResultsToSave>
|
|
37
|
+
<bytes>true</bytes>
|
|
38
|
+
<threadCounts>true</threadCounts>
|
|
39
|
+
<sampleCount>true</sampleCount>
|
|
40
|
+
</value>
|
|
41
|
+
</objProp>
|
|
42
|
+
<stringProp name="filename"></stringProp>
|
|
43
|
+
<longProp name="interval_grouping">500</longProp>
|
|
44
|
+
<boolProp name="graph_aggregated">false</boolProp>
|
|
45
|
+
<stringProp name="include_sample_labels"></stringProp>
|
|
46
|
+
<stringProp name="exclude_sample_labels"></stringProp>
|
|
47
|
+
<stringProp name="start_offset"></stringProp>
|
|
48
|
+
<stringProp name="end_offset"></stringProp>
|
|
49
|
+
<boolProp name="include_checkbox_state">false</boolProp>
|
|
50
|
+
<boolProp name="exclude_checkbox_state">false</boolProp>
|
|
51
|
+
</kg.apc.jmeter.vizualizers.CorrectedResultCollector>
|
|
52
|
+
XML
|
|
53
|
+
)
|
|
54
|
+
)
|
|
55
|
+
update params
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|