Skip to content

Commit

Permalink
add documentation and improve visibility of methods (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
jlurena authored Oct 26, 2024
1 parent d2e40ea commit d207c9b
Show file tree
Hide file tree
Showing 146 changed files with 1,498 additions and 732 deletions.
354 changes: 177 additions & 177 deletions DSL.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion example/Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: ..
specs:
jmeter_perf (0.1.0)
jmeter_perf (0.0.6)
nokogiri (~> 1.16, >= 1.16.7)
tdigest (~> 0.2.1)

Expand Down
151 changes: 143 additions & 8 deletions lib/jmeter_perf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,157 @@
require_relative file
end

require_relative "jmeter_perf/dsl"

# JmeterPerf module for handling performance testing with JMeter.
# This module provides methods to define and execute JMeter test plans.
module JmeterPerf
def self.test(params = {}, &)
JmeterPerf.dsl_eval(JmeterPerf::ExtendedDSL.new(params), &)
end
# Evaluates the test plan with the given parameters and block.
# @see https://github.com/jlurena/jmeter_perf/wiki/1.-DSL-Documentation DSL Documentation
# @param [Hash] params Parameters for the test plan (default: `{}`).
# @yield The block to define the test plan steps.
# @return [JmeterPerf::ExtendedDSL] The DSL instance with the configured test plan.
def self.test(params = {}, &block)
dsl = JmeterPerf::ExtendedDSL.new(params)

def self.dsl_eval(dsl, &block)
block_context = eval("self", block.binding, __FILE__, __LINE__)
proxy_context = JmeterPerf::FallbackContextProxy.new(dsl, block_context)
begin
block_context.instance_variables.each { |ivar| proxy_context.instance_variable_set(ivar, block_context.instance_variable_get(ivar)) }
block_context.instance_variables.each do |ivar|
proxy_context.instance_variable_set(ivar, block_context.instance_variable_get(ivar))
end
proxy_context.instance_eval(&block)
ensure
block_context.instance_variables.each { |ivar| block_context.instance_variable_set(ivar, proxy_context.instance_variable_get(ivar)) }
block_context.instance_variables.each do |ivar|
block_context.instance_variable_set(ivar, proxy_context.instance_variable_get(ivar))
end
end
dsl
end

# DSL class for defining JMeter test plans.
# Provides methods to generate, save, and run JMeter tests.
class ExtendedDSL < DSL
include Parser
attr_accessor :root

# Initializes an ExtendedDSL object with the provided parameters.
# @param [Hash] params Parameters for the test plan (default: `{}`).
def initialize(params = {})
@root = Nokogiri::XML(<<-EOF.strip_heredoc)
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="3.1" jmeter="3.1" ruby-jmeter="3.0">
<hashTree>
</hashTree>
</jmeterTestPlan>
EOF
node = JmeterPerf::TestPlan.new(params)
@current_node = @root.at_xpath("//jmeterTestPlan/hashTree")
@current_node = attach_to_last(node)
end

# Saves the test plan as a JMX file.
#
# @param [String] out_jmx The path for the output JMX file (default: `"ruby-jmeter.jmx"`).
def jmx(out_jmx: "ruby-jmeter.jmx")
File.write(out_jmx, doc.to_xml(indent: 2))
logger.info "JMX saved to: #{out_jmx}"
end

# Runs the test plan with the specified configuration.
#
# @param [String] name The name of the test run (default: `"ruby-jmeter"`).
# @param [String] jmeter_path Path to the JMeter executable (default: `"jmeter"`).
# @param [String] out_jmx The filename for the output JMX file (default: `"ruby-jmeter.jmx"`).
# @param [String] out_jtl The filename for the output JTL file (default: `"jmeter.jtl"`).
# @param [String] out_jmeter_log The filename for the JMeter log file (default: `"jmeter.log"`).
# @param [String] out_cmd_log The filename for the command log file (default: `"jmeter-cmd.log"`).
# @return [JmeterPerf::Report::Summary] The summary report of the test run.
# @raise [RuntimeError] If the test execution fails.
def run(
name: "ruby-jmeter",
jmeter_path: "jmeter",
out_jmx: "ruby-jmeter.jmx",
out_jtl: "jmeter.jtl",
out_jmeter_log: "jmeter.log",
out_cmd_log: "jmeter-cmd.log"
)
jmx(out_jmx:)
logger.warn "Executing #{out_jmx} test plan locally ..."

cmd = <<~CMD.strip
#{jmeter_path} -n -t #{out_jmx} -j #{out_jmeter_log} -l #{out_jtl}
CMD

summary = JmeterPerf::Report::Summary.new(out_jtl, name)
jtl_process_thread = summary.stream_jtl_async

File.open(out_cmd_log, "w") do |f|
pid = Process.spawn(cmd, out: f, err: [:child, :out])
Process.waitpid(pid)
end

summary.finish! # Notify jtl collection that JTL cmd finished
jtl_process_thread.join # Join main thread and wait for it to finish

unless $?.exitstatus.zero?
logger.error("Failed to run #{cmd}. See #{out_cmd_log} and #{out_jmeter_log} for details.")
raise "Exit status: #{$?.exitstatus}"
end

summary.summarize_data!
logger.info "[Test Plan Execution Completed Successfully] JTL saved to: #{out_jtl}\n"
summary
rescue
summary.finish!
raise
end

private

# Creates a new hash tree node for the JMeter test plan.
#
# @return [Nokogiri::XML::Node] A new hash tree node.
def hash_tree
Nokogiri::XML::Node.new("hashTree", @root)
end

# Attaches a node as the last child of the current node.
#
# @param [Object] node The node to attach.
# @return [Object] The hash tree for the attached node.
def attach_to_last(node)
ht = hash_tree
last_node = @current_node
last_node << node.doc.children << ht
ht
end

# Attaches a node and evaluates the block within its context.
#
# @param [Object] node The node to attach.
# @yield The block to be executed in the node's context.
def attach_node(node, &block)
ht = attach_to_last(node)
previous = @current_node
@current_node = ht
instance_exec(&block) if block
@current_node = previous
end

# Returns the Nokogiri XML document.
#
# @return [Nokogiri::XML::Document] The XML document for the JMeter test plan.
def doc
Nokogiri::XML(@root.to_s, &:noblanks)
end

# Logger instance to log messages to the standard output.
#
# @return [Logger] The logger instance, initialized to DEBUG level.
def logger
return @logger if @logger
@logger = Logger.new($stdout)
@logger.level = Logger::DEBUG
@logger
end
end
end
112 changes: 0 additions & 112 deletions lib/jmeter_perf/dsl.rb

This file was deleted.

5 changes: 5 additions & 0 deletions lib/jmeter_perf/dsl/access_log_sampler.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
module JmeterPerf
class DSL
# DSL method synonymous with the JMeter Element AccessLogSampler
# @see https://github.com/jlurena/jmeter_perf/wiki/1.-DSL-Documentation#accesslogsampler
# @param [Hash] params Parameters for the AccessLogSampler element (default: `{}`).
# @yield block to attach to the AccessLogSampler element
# @return [JmeterPerf::AccessLogSampler], a subclass of JmeterPerf::DSL that can be chained with other DSL methods.
def access_log_sampler(params = {}, &)
node = JmeterPerf::AccessLogSampler.new(params)
attach_node(node, &)
Expand Down
5 changes: 5 additions & 0 deletions lib/jmeter_perf/dsl/aggregate_graph.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
module JmeterPerf
class DSL
# DSL method synonymous with the JMeter Element AggregateGraph
# @see https://github.com/jlurena/jmeter_perf/wiki/1.-DSL-Documentation#aggregategraph
# @param [Hash] params Parameters for the AggregateGraph element (default: `{}`).
# @yield block to attach to the AggregateGraph element
# @return [JmeterPerf::AggregateGraph], a subclass of JmeterPerf::DSL that can be chained with other DSL methods.
def aggregate_graph(params = {}, &)
node = JmeterPerf::AggregateGraph.new(params)
attach_node(node, &)
Expand Down
5 changes: 5 additions & 0 deletions lib/jmeter_perf/dsl/aggregate_report.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
module JmeterPerf
class DSL
# DSL method synonymous with the JMeter Element AggregateReport
# @see https://github.com/jlurena/jmeter_perf/wiki/1.-DSL-Documentation#aggregatereport
# @param [Hash] params Parameters for the AggregateReport element (default: `{}`).
# @yield block to attach to the AggregateReport element
# @return [JmeterPerf::AggregateReport], a subclass of JmeterPerf::DSL that can be chained with other DSL methods.
def aggregate_report(params = {}, &)
node = JmeterPerf::AggregateReport.new(params)
attach_node(node, &)
Expand Down
5 changes: 5 additions & 0 deletions lib/jmeter_perf/dsl/ajp13_sampler.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
module JmeterPerf
class DSL
# DSL method synonymous with the JMeter Element AJP13Sampler
# @see https://github.com/jlurena/jmeter_perf/wiki/1.-DSL-Documentation#ajp13sampler
# @param [Hash] params Parameters for the AJP13Sampler element (default: `{}`).
# @yield block to attach to the AJP13Sampler element
# @return [JmeterPerf::AJP13Sampler], a subclass of JmeterPerf::DSL that can be chained with other DSL methods.
def ajp13_sampler(params = {}, &)
node = JmeterPerf::AJP13Sampler.new(params)
attach_node(node, &)
Expand Down
5 changes: 5 additions & 0 deletions lib/jmeter_perf/dsl/assertion_results.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
module JmeterPerf
class DSL
# DSL method synonymous with the JMeter Element AssertionResults
# @see https://github.com/jlurena/jmeter_perf/wiki/1.-DSL-Documentation#assertionresults
# @param [Hash] params Parameters for the AssertionResults element (default: `{}`).
# @yield block to attach to the AssertionResults element
# @return [JmeterPerf::AssertionResults], a subclass of JmeterPerf::DSL that can be chained with other DSL methods.
def assertion_results(params = {}, &)
node = JmeterPerf::AssertionResults.new(params)
attach_node(node, &)
Expand Down
5 changes: 5 additions & 0 deletions lib/jmeter_perf/dsl/bean_shell_assertion.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
module JmeterPerf
class DSL
# DSL method synonymous with the JMeter Element BeanShellAssertion
# @see https://github.com/jlurena/jmeter_perf/wiki/1.-DSL-Documentation#beanshellassertion
# @param [Hash] params Parameters for the BeanShellAssertion element (default: `{}`).
# @yield block to attach to the BeanShellAssertion element
# @return [JmeterPerf::BeanShellAssertion], a subclass of JmeterPerf::DSL that can be chained with other DSL methods.
def bean_shell_assertion(params = {}, &)
node = JmeterPerf::BeanShellAssertion.new(params)
attach_node(node, &)
Expand Down
5 changes: 5 additions & 0 deletions lib/jmeter_perf/dsl/bean_shell_listener.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
module JmeterPerf
class DSL
# DSL method synonymous with the JMeter Element BeanShellListener
# @see https://github.com/jlurena/jmeter_perf/wiki/1.-DSL-Documentation#beanshelllistener
# @param [Hash] params Parameters for the BeanShellListener element (default: `{}`).
# @yield block to attach to the BeanShellListener element
# @return [JmeterPerf::BeanShellListener], a subclass of JmeterPerf::DSL that can be chained with other DSL methods.
def bean_shell_listener(params = {}, &)
node = JmeterPerf::BeanShellListener.new(params)
attach_node(node, &)
Expand Down
5 changes: 5 additions & 0 deletions lib/jmeter_perf/dsl/bean_shell_postprocessor.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
module JmeterPerf
class DSL
# DSL method synonymous with the JMeter Element BeanShellPostprocessor
# @see https://github.com/jlurena/jmeter_perf/wiki/1.-DSL-Documentation#beanshellpostprocessor
# @param [Hash] params Parameters for the BeanShellPostprocessor element (default: `{}`).
# @yield block to attach to the BeanShellPostprocessor element
# @return [JmeterPerf::BeanShellPostprocessor], a subclass of JmeterPerf::DSL that can be chained with other DSL methods.
def bean_shell_postprocessor(params = {}, &)
node = JmeterPerf::BeanShellPostprocessor.new(params)
attach_node(node, &)
Expand Down
5 changes: 5 additions & 0 deletions lib/jmeter_perf/dsl/bean_shell_preprocessor.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
module JmeterPerf
class DSL
# DSL method synonymous with the JMeter Element BeanShellPreprocessor
# @see https://github.com/jlurena/jmeter_perf/wiki/1.-DSL-Documentation#beanshellpreprocessor
# @param [Hash] params Parameters for the BeanShellPreprocessor element (default: `{}`).
# @yield block to attach to the BeanShellPreprocessor element
# @return [JmeterPerf::BeanShellPreprocessor], a subclass of JmeterPerf::DSL that can be chained with other DSL methods.
def bean_shell_preprocessor(params = {}, &)
node = JmeterPerf::BeanShellPreprocessor.new(params)
attach_node(node, &)
Expand Down
5 changes: 5 additions & 0 deletions lib/jmeter_perf/dsl/bean_shell_sampler.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
module JmeterPerf
class DSL
# DSL method synonymous with the JMeter Element BeanShellSampler
# @see https://github.com/jlurena/jmeter_perf/wiki/1.-DSL-Documentation#beanshellsampler
# @param [Hash] params Parameters for the BeanShellSampler element (default: `{}`).
# @yield block to attach to the BeanShellSampler element
# @return [JmeterPerf::BeanShellSampler], a subclass of JmeterPerf::DSL that can be chained with other DSL methods.
def bean_shell_sampler(params = {}, &)
node = JmeterPerf::BeanShellSampler.new(params)
attach_node(node, &)
Expand Down
Loading

0 comments on commit d207c9b

Please sign in to comment.